您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
FINAL-AutoCopy: 透過模擬原生複製功能獲取 URL,並自動將轉換後的連結寫入剪貼簿。
// ==UserScript== // @name X.com 分享連結轉換 (FX/VX Twitter) // @namespace http://tampermonkey.net/ // @version 2.6 // @description FINAL-AutoCopy: 透過模擬原生複製功能獲取 URL,並自動將轉換後的連結寫入剪貼簿。 // @author Customized for User // @match https://x.com/* // @match https://twitter.com/* // @icon https://pbs.twimg.com/media/GGmfzX_bUAAUUFw?format=png // @grant none // @run-at document-idle // @license MIT // ==/UserScript== (function() { 'use strict'; const POTENTIAL_ITEM_SELECTOR = 'div[role="menuitem"]'; const MENU_CONTAINER_SELECTOR = 'div[role="menu"]'; const TARGET_TEXT = '複製連結'; const PROCESSED_ATTR = 'data-fxvx-processed'; /** * 創建新的選單項 DOM 元素 (保持不變) */ function createMenuItem(text, service, originalItem) { const newItem = originalItem.cloneNode(true); newItem.classList.add('fx-vx-share-item'); newItem.setAttribute('data-service', service); const textSpan = newItem.querySelector('span'); if (textSpan) { textSpan.textContent = text; } newItem.removeAttribute('tabindex'); return newItem; } /** * 處理點擊事件:獲取轉換後的連結,並自動寫入剪貼簿。 */ function handleCopy(event) { event.stopPropagation(); event.preventDefault(); const item = event.currentTarget; const service = item.getAttribute('data-service'); // 1. 取得原生「複製連結」按鈕 let originalCopyItem = null; const menuContainer = item.closest(MENU_CONTAINER_SELECTOR); if (menuContainer) { const menuItems = menuContainer.querySelectorAll(POTENTIAL_ITEM_SELECTOR); menuItems.forEach(mi => { if (mi.textContent && mi.textContent.includes(TARGET_TEXT)) { originalCopyItem = mi; } }); } if (!originalCopyItem) { console.error('無法找到原生「複製連結」按鈕。'); return; } // 2. 模擬點擊原生按鈕 originalCopyItem.click(); // 3. 延遲讀取剪貼簿 (給 X.com 程式碼反應時間) setTimeout(() => { navigator.clipboard.readText() .then(originalUrl => { if (!originalUrl || !originalUrl.includes('/status/')) { console.error('剪貼簿中未讀取到有效的貼文連結。'); return; } // 4. 轉換 URL const regex = /:\/\/(?:x|twitter)\.com/i; const newUrl = originalUrl.replace(regex, `://${service}.com`); if (newUrl === originalUrl) { console.error("網址轉換失敗:原始 URL 格式不符合預期。"); return; } // 5. 將轉換後的 URL 寫回剪貼簿 (自動複製) navigator.clipboard.writeText(newUrl) .then(() => { console.log(`已自動複製 ${service.toUpperCase()} 連結: ${newUrl} ✅`); // 可選:給用戶一個快速視覺回饋(例如在控制台或網頁上) }) .catch(err => { console.error('寫入剪貼簿時發生錯誤 (請檢查權限):', err); // 如果寫入失敗,彈出提示讓用戶手動複製 prompt(`【複製失敗】請手動複製以下連結:\n\n按 Ctrl+C / Cmd+C 即可複製。`, newUrl); }); }) .catch(err => { console.error('讀取剪貼簿時發生錯誤 (請檢查權限):', err); }); }, 100); } /** * 尋找並插入新的分享選項 (保持不變) */ function insertShareOptions() { const menuContainers = document.querySelectorAll(MENU_CONTAINER_SELECTOR); menuContainers.forEach(menuContainer => { if (menuContainer.hasAttribute(PROCESSED_ATTR)) { return; } const menuItems = menuContainer.querySelectorAll(POTENTIAL_ITEM_SELECTOR); let originalItem = null; menuItems.forEach(item => { if (item.textContent && item.textContent.includes(TARGET_TEXT)) { originalItem = item; } }); if (originalItem) { menuContainer.setAttribute(PROCESSED_ATTR, 'true'); // 建立並插入 FX 連結選項 const fxItem = createMenuItem('複製 FxTwitter 連結 (自動)', 'fxtwitter', originalItem); fxItem.addEventListener('click', handleCopy); menuContainer.insertBefore(fxItem, originalItem.nextSibling); // 建立並插入 VX 連結選項 const vxItem = createMenuItem('複製 VxTwitter 連結 (自動)', 'vxtwitter', originalItem); vxItem.addEventListener('click', handleCopy); menuContainer.insertBefore(vxItem, fxItem.nextSibling); } }); } // --- MutationObserver 監聽 DOM 變化 --- const targetNode = document.body; const config = { childList: true, subtree: true }; const observer = new MutationObserver(function(mutationsList, observer) { insertShareOptions(); }); observer.observe(targetNode, config); insertShareOptions(); })();