您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
透过右键、喜欢或按钮复制推文链接,并支援fixupx模式,可在油猴介面中直接开关指定功能,中英语言显示切换。
当前为
// ==UserScript== // @name X Copy Tweet Link Helper // @name:zh-TW X 複製推文連結助手 // @name:zh-CN X 复制推文连结助手 // @namespace http://tampermonkey.net/ // @version 2.1 // @description Copy tweet links via right-click, like button, or dedicated button. Supports Fixupx mode, allows toggling specific features directly in the Tampermonkey interface, and offers Chinese/English language switching. // @description:zh-TW 透過右鍵、喜歡或按鈕複製推文鏈接,並支援fixupx模式,可在油猴介面中直接開關指定功能,中英語言顯示切換。 // @description:zh-CN 透过右键、喜欢或按钮复制推文链接,并支援fixupx模式,可在油猴介面中直接开关指定功能,中英语言显示切换。 // @author ChatGPT // @match https://x.com/* // @match https://twitter.com/* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @license MIT // ==/UserScript== (function () { 'use strict'; const defaultSettings = { rightClickCopy: true, likeCopy: true, showCopyButton: true, useFixupx: false, language: 'EN' }; const settings = { get(key) { return GM_getValue(key, defaultSettings[key]); }, set(key, value) { GM_setValue(key, value); } }; const lang = { EN: { copySuccess: "Link copied!", copyButton: "🔗", rightClickCopy: 'Right-click Copy', likeCopy: 'Like Copy', showCopyButton: 'Show Copy Button', useFixupx: 'Use Fixupx', language: 'Language' }, ZH: { copySuccess: "已複製鏈結!", copyButton: "🔗", rightClickCopy: '右鍵複製', likeCopy: '喜歡時複製', showCopyButton: '顯示複製按鈕', useFixupx: '使用 Fixupx', language: '語言' } }; const getText = (key) => lang[settings.get('language')][key]; function cleanTweetUrl(rawUrl) { try { const url = new URL(rawUrl); url.search = ''; url.pathname = url.pathname.replace(/\/photo\/\d+$/, ''); if (settings.get('useFixupx')) { url.hostname = 'fixupx.com'; } return url.toString(); } catch { return rawUrl; } } function copyTweetLink(tweet) { const anchor = tweet.querySelector('a[href*="/status/"]'); if (!anchor) return; const cleanUrl = cleanTweetUrl(anchor.href); navigator.clipboard.writeText(cleanUrl).then(() => { showToast(getText('copySuccess')); }); } let toastTimer = null; function showToast(msg) { let toast = document.getElementById('x-copy-tweet-toast'); if (!toast) { toast = document.createElement('div'); toast.id = 'x-copy-tweet-toast'; Object.assign(toast.style, { position: 'fixed', bottom: '20px', left: '50%', transform: 'translateX(-50%)', background: '#1da1f2', color: '#fff', padding: '8px 16px', borderRadius: '20px', zIndex: 9999, fontSize: '14px', pointerEvents: 'none' }); document.body.appendChild(toast); } toast.innerText = msg; toast.style.display = 'block'; if (toastTimer) clearTimeout(toastTimer); toastTimer = setTimeout(() => { toast.style.display = 'none'; }, 1500); } function insertCopyButton(tweet) { if (tweet.querySelector('.my-copy-btn')) return; const actionGroup = tweet.querySelector('[role="group"]'); if (!actionGroup) return; const btn = document.createElement('div'); btn.className = 'my-copy-btn'; btn.innerText = getText('copyButton'); Object.assign(btn.style, { fontSize: '16px', cursor: 'pointer', userSelect: 'none', marginLeft: '8px', display: 'flex', alignItems: 'center', justifyContent: 'center' }); btn.onclick = (e) => { e.stopPropagation(); copyTweetLink(tweet); }; const buttonContainer = actionGroup.lastElementChild; if (buttonContainer && buttonContainer.parentElement) { const wrapper = document.createElement('div'); wrapper.style.display = 'flex'; wrapper.style.alignItems = 'center'; wrapper.style.marginLeft = '8px'; wrapper.appendChild(btn); buttonContainer.parentElement.appendChild(wrapper); } else { actionGroup.appendChild(btn); // fallback } } // 防止重複綁定like事件 function bindLikeCopy(tweet) { if (tweet.hasAttribute('data-likecopy')) return; tweet.setAttribute('data-likecopy', 'true'); const likeBtn = tweet.querySelector('[data-testid="like"]'); if (likeBtn && !likeBtn.hasAttribute('data-likecopy-listener')) { likeBtn.setAttribute('data-likecopy-listener', 'true'); likeBtn.addEventListener('click', () => { copyTweetLink(tweet); }); } } // 防止重複綁定右鍵事件 function bindRightClickCopy(tweet) { if (tweet.hasAttribute('data-rightclick')) return; tweet.setAttribute('data-rightclick', 'true'); tweet.addEventListener('contextmenu', (e) => { if (tweet.querySelector('img, video')) { copyTweetLink(tweet); } }); } // 只處理新增的article節點 function processTweetNode(node) { if (!(node instanceof HTMLElement)) return; if (node.tagName === 'ARTICLE') { if (settings.get('showCopyButton')) insertCopyButton(node); if (settings.get('rightClickCopy')) bindRightClickCopy(node); if (settings.get('likeCopy')) bindLikeCopy(node); } else { node.querySelectorAll && node.querySelectorAll('article').forEach(article => { if (settings.get('showCopyButton')) insertCopyButton(article); if (settings.get('rightClickCopy')) bindRightClickCopy(article); if (settings.get('likeCopy')) bindLikeCopy(article); }); } } // 初始處理現有推文 document.querySelectorAll('article').forEach(processTweetNode); // 只處理新增節點 const tweetObserver = new MutationObserver((mutations) => { for (const mutation of mutations) { mutation.addedNodes.forEach(processTweetNode); } }); tweetObserver.observe(document.body, { childList: true, subtree: true }); // MenuCommand 註冊與註銷 let menuIds = []; function updateMenuCommands() { // 註銷舊的 menuIds.forEach(id => { try { GM_unregisterMenuCommand(id); } catch {} }); menuIds = []; menuIds.push(GM_registerMenuCommand(`${getText('rightClickCopy')} ( ${settings.get('rightClickCopy') ? '✅' : '❌'} )`, toggleRightClickCopy)); menuIds.push(GM_registerMenuCommand(`${getText('likeCopy')} ( ${settings.get('likeCopy') ? '✅' : '❌'} )`, toggleLikeCopy)); menuIds.push(GM_registerMenuCommand(`${getText('showCopyButton')} ( ${settings.get('showCopyButton') ? '✅' : '❌'} )`, toggleShowCopyButton)); menuIds.push(GM_registerMenuCommand(`${getText('useFixupx')} ( ${settings.get('useFixupx') ? '✅' : '❌'} )`, toggleUseFixupx)); // 支援多語言自動切換 const langs = Object.keys(lang); const currentLangIdx = langs.indexOf(settings.get('language')); const nextLang = langs[(currentLangIdx + 1) % langs.length]; menuIds.push(GM_registerMenuCommand(`${getText('language')} ( ${settings.get('language')} )`, () => toggleLanguage(nextLang))); } updateMenuCommands(); function toggleRightClickCopy() { settings.set('rightClickCopy', !settings.get('rightClickCopy')); reloadPage(); } function toggleLikeCopy() { settings.set('likeCopy', !settings.get('likeCopy')); reloadPage(); } function toggleShowCopyButton() { settings.set('showCopyButton', !settings.get('showCopyButton')); reloadPage(); } function toggleUseFixupx() { settings.set('useFixupx', !settings.get('useFixupx')); reloadPage(); } function toggleLanguage(nextLang) { settings.set('language', nextLang); reloadPage(); } function reloadPage() { location.reload(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址