您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
共享选定文本到Gist并粘贴到剪贴板
当前为
// ==UserScript== // @name Gist Shared Clipboard // @name:ja Gist 共有クリップボード // @name:zh-CN Gist 共享剪贴板 // @name:zh-TW Gist 共享剪貼簿 // @license MIT // @namespace http://tampermonkey.net/ // @version 2025-05-27 // @description Share selected text to Gist and paste it to clipboard // @description:ja Gistに選択したテキストを共有し、クリップボードに貼り付ける // @description:zh-CN 共享选定文本到Gist并粘贴到剪贴板 // @description:zh-TW 共享選定文本到Gist並粘貼到剪貼簿 // @author Julia Lee // @match *://*/* // @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_setClipboard // ==/UserScript== (async function () { 'use strict'; const GITHUB_TOKEN = await GM.getValue('GITHUB_TOKEN', ''); // GitHubのPersonal Access Tokenを指定 const GIST_ID = await GM.getValue('GIST_ID', ''); // GistのIDを指定 const FILENAME = 'GM-Shared-Clipboard.txt'; // Gist内のファイル名 const RIGHT_CLICK_MAX_AGE = 20 * 1000; // 右クリックしてからTargetの保持時間(ミリ秒) await GM.deleteValue('GIST_DOWNLOADING'); await GM.deleteValue('GIST_UPLOADING'); let crtRightTgtContent = null; let crtRightTgtUpdated = 0; if (GITHUB_TOKEN && GIST_ID) { const menu1 = GM_registerMenuCommand("Gist Share", gistUpload, { accessKey: 'c', autoClose: true, title: 'Share selected text to Gist', }); const menu2 = GM_registerMenuCommand("Gist Paste", gistDowload, { accessKey: 'v', autoClose: true, title: 'Paste Gist content to clipboard', }); } const menu3 = GM_registerMenuCommand("Gist Setup", setup, { accessKey: 'x', autoClose: true, title: 'Setup Gist ID and Token', }); document.body.addEventListener("mousedown", event => { if (event.button == 0) { // left click for mouse // crtRightTgtContent = null; } else if (event.button == 1) { // wheel click for mouse // crtRightTgtContent = null; } else if (event.button == 2) { // right click for mouse const elm = event.target; const nodName = elm.nodeName.toLowerCase(); switch (nodName) { case 'img': crtRightTgtContent = elm.src; break; case 'a': crtRightTgtContent = elm.href; break; default: crtRightTgtContent = null; break; } if (crtRightTgtContent) { crtRightTgtUpdated = new Date(); } } }); const gistUrl = `https://api.github.com/gists/${GIST_ID}`; const headers = { 'Authorization': `Bearer ${GITHUB_TOKEN}`, 'Content-Type': 'application/json', }; async function gistUpload(_event) { // If the target is too old, reset it if (crtRightTgtContent && (new Date()) - crtRightTgtUpdated > RIGHT_CLICK_MAX_AGE) { crtRightTgtContent = null; // crtRightTgtUpdated = 0; } const selectedText = document.getSelection().toString(); if (!crtRightTgtContent && !selectedText) { return } const locked = await GM.getValue('GIST_UPLOADING'); if (locked) { console.log("Gist is already uploading."); return; } const data = { files: { [FILENAME]: { content: selectedText || crtRightTgtContent } } }; try { await GM.setValue('GIST_UPLOADING', true); const res = await fetch(gistUrl, { method: 'POST', headers, body: JSON.stringify(data) }); if (!res.ok) { const error = await res.json(); throw new Error(`Failed to update Gist: ${error.message}`); } const result = await res.json(); // await GM.setClipboard(result.html_url, "text") await GM.setClipboard(result.files[FILENAME].content, "text"); console.log("Gist URL: ", result.html_url); await showMessage('✅ Target Shared!', 'OK', 2500); } catch (error) { console.error("Error: ", error); await showMessage(`❌ ${error.message}`, 'NG', 2500); } finally { await GM.deleteValue('GIST_UPLOADING'); } } async function gistDowload(_event) { if (inIframe()) { console.log("Gist Paste is not available in iframe."); return; } const locked = await GM.getValue('GIST_DOWNLOADING'); if (locked) { console.log("Gist is already Downloading."); return; } try { await GM.setValue('GIST_DOWNLOADING', true); const res = await fetch(gistUrl, { headers }); if (!res.ok) { const error = await res.json(); throw new Error(`Failed to fetch Gist: ${error.message}`); } const result = await res.json(); const content = result.files[FILENAME].content; if (!content) { throw new Error('No content found in the Gist.'); } await GM.setClipboard(content, "text"); console.log("Gist Content: ", content); await showMessage('✅ Clipboard Updated!', 'OK', 2500); } catch (error) { console.error("Error: ", error); await showMessage(`❌ ${error.message}`, 'NG', 2500); } finally { await GM.deleteValue('GIST_DOWNLOADING'); } } async function setup() { if (inIframe()) { console.log("Gist Setup is not available in iframe."); return; } const registerDialog = await createRegisterDialog(); registerDialog.showModal(); const saveButton = document.getElementById('save-button'); const gistIdInput = document.getElementById('gist-id-input'); const gistTokenInput = document.getElementById('gist-token-input'); saveButton.addEventListener('click', async () => { const gistId = gistIdInput.value; const token = gistTokenInput.value; if (!gistId || !token) { await showMessage('❌ Gist ID and Token are required!', 'NG', 2500); return; } await GM.setValue('GIST_ID', gistId); await GM.setValue('GITHUB_TOKEN', token); registerDialog.close(); registerDialog.remove(); setTimeout(() => { location.reload() }, 2500); // Restart Script await showMessage('✅ Gist ID and Token saved!', 'OK', 2500); }); const clearInfoButton = document.getElementById('clear-button'); clearInfoButton.addEventListener('click', async () => { if (!confirm('Are you sure you want to clear Gist ID and Token?')) { return; } await GM.deleteValue('GITHUB_TOKEN'); await GM.deleteValue('GIST_ID'); registerDialog.close(); registerDialog.remove(); setTimeout(() => { location.reload() }, 2500); // Restart Script await showMessage('✅ Gist ID and Token cleared!', 'OK', 2500); }); } })(); async function showMessage(text, type = 'OK', duration = 4000) { const htmlId = `GistShare_Message-${type}`; const existingMessage = document.getElementById(htmlId); if (existingMessage) { return; } // 既に表示されている場合は何もしない if (duration < 1000) { duration = 1000; } // 最低1秒は表示する return new Promise((resolve) => { const message = document.createElement('div'); message.id = `GistShare_Message-${type}`; message.textContent = text; // 共通スタイル Object.assign(message.style, { position: 'fixed', top: '20px', right: '20px', padding: '12px 18px', borderRadius: '10px', color: '#fff', fontSize: '14px', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)', zIndex: 9999, transform: 'translateY(20px)', opacity: '0', transition: 'opacity 0.4s ease, transform 0.4s ease' }); // タイプ別デザイン if (type === 'OK') { message.style.backgroundColor = '#4caf50'; // 緑 message.style.borderLeft = '6px solid #2e7d32'; } else if (type === 'NG') { message.style.backgroundColor = '#f44336'; // 赤 message.style.borderLeft = '6px solid #b71c1c'; } document.body.appendChild(message); // フェードイン(下から) setTimeout(() => { message.style.opacity = '.95'; message.style.transform = 'translateY(0)'; }, 10); // requestAnimationFrame(() => { // message.style.opacity = '1'; // message.style.transform = 'translateY(0)'; // }); // 指定時間後にフェードアウト setTimeout(() => { message.style.opacity = '0'; message.style.transform = 'translateY(-20px)'; setTimeout(() => { message.remove(); resolve(); // メッセージが削除された後にresolveを呼び出す }, 400); // transition と一致 }, duration - 400); }); } async function createRegisterDialog() { const existDialog = document.getElementById('tm-gist-dialog'); if (existDialog) existDialog.remove(); const registerDialog = document.createElement('dialog'); registerDialog.id = 'tm-gist-dialog'; registerDialog.style.padding = '1em'; registerDialog.style.zIndex = 9999; registerDialog.style.maxWidth = '400px'; registerDialog.style.margin = 'auto'; registerDialog.style.border = '2px solid #ccc'; registerDialog.style.borderRadius = '8px'; registerDialog.style.backgroundColor = '#fff'; registerDialog.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.1)'; registerDialog.style.position = 'fixed'; registerDialog.style.padding = '1.5em'; registerDialog.style.boxSizing = 'border-box'; const gistIdLabel = document.createElement('label'); gistIdLabel.textContent = 'Gist ID:'; gistIdLabel.style.display = 'block'; gistIdLabel.style.marginBottom = '0.5em'; gistIdLabel.for = 'gist-id-input'; registerDialog.appendChild(gistIdLabel); const gistIdInput = document.createElement('input'); gistIdInput.id = 'gist-id-input'; gistIdInput.type = 'text'; gistIdInput.style.width = '100%'; gistIdInput.style.boxSizing = 'border-box'; gistIdInput.style.padding = '0.5em'; gistIdInput.style.border = '1px solid #ccc'; gistIdInput.style.borderRadius = '4px'; gistIdInput.style.marginBottom = '1em'; gistIdInput.value = await GM.getValue('GIST_ID', ''); gistIdInput.placeholder = 'Your Gist ID'; registerDialog.appendChild(gistIdInput); const gistIdHelpText = document.createElement('small'); gistIdHelpText.style.display = 'block'; gistIdHelpText.style.marginBottom = '1.1em'; gistIdHelpText.style.color = '#666'; const gistIdHelpLabel = document.createElement('span'); gistIdHelpLabel.textContent = 'Create or Select a Gist: '; gistIdHelpText.appendChild(gistIdHelpLabel); const gistIdHelpLink = document.createElement('a'); gistIdHelpLink.href = 'https://gist.github.com/mine'; gistIdHelpLink.target = '_blank'; gistIdHelpLink.textContent = 'https://gist.github.com/'; gistIdHelpText.appendChild(gistIdHelpLink); registerDialog.appendChild(gistIdHelpText); const gistTokenLabel = document.createElement('label'); gistTokenLabel.textContent = 'Gist Token:'; gistTokenLabel.style.display = 'block'; gistTokenLabel.style.marginBottom = '0.5em'; gistTokenLabel.for = 'gist-token-input'; registerDialog.appendChild(gistTokenLabel); const gistTokenInput = document.createElement('input'); gistTokenInput.id = 'gist-token-input'; gistTokenInput.type = 'password'; gistTokenInput.style.width = '100%'; gistTokenInput.style.boxSizing = 'border-box'; gistTokenInput.style.padding = '0.5em'; gistTokenInput.style.border = '1px solid #ccc'; gistTokenInput.style.borderRadius = '4px'; gistTokenInput.style.marginBottom = '1em'; gistTokenInput.value = await GM.getValue('GITHUB_TOKEN', ''); gistTokenInput.placeholder = 'ghp_XXXXXXXXXXXXXXXX'; registerDialog.appendChild(gistTokenInput); const gistTokenHelpText = document.createElement('small'); gistTokenHelpText.style.display = 'block'; gistTokenHelpText.style.marginBottom = '1em'; gistTokenHelpText.style.color = '#666'; const gistTokenHelpLabel = document.createElement('span'); gistTokenHelpLabel.textContent = 'Create a Token: '; gistTokenHelpText.appendChild(gistTokenHelpLabel); const gistTokenHelpLink = document.createElement('a'); gistTokenHelpLink.href = 'https://github.com/settings/tokens'; gistTokenHelpLink.target = '_blank'; gistTokenHelpLink.textContent = 'https://github.com/settings/tokens'; gistTokenHelpText.appendChild(gistTokenHelpLink); registerDialog.appendChild(gistTokenHelpText); const saveButton = document.createElement('button'); saveButton.textContent = 'Save Info'; saveButton.style.backgroundColor = '#4caf50'; saveButton.style.color = '#fff'; saveButton.style.border = 'none'; saveButton.style.padding = '0.5em 1em'; saveButton.style.borderRadius = '4px'; saveButton.style.cursor = 'pointer'; saveButton.style.marginTop = '1em'; saveButton.style.float = 'right'; saveButton.id = 'save-button'; registerDialog.appendChild(saveButton); const clearInfoButton = document.createElement('button'); clearInfoButton.textContent = 'Clear Info'; clearInfoButton.style.backgroundColor = '#f44336'; clearInfoButton.style.color = '#fff'; clearInfoButton.style.border = 'none'; clearInfoButton.style.padding = '0.5em 1em'; clearInfoButton.style.borderRadius = '4px'; clearInfoButton.style.cursor = 'pointer'; clearInfoButton.style.marginTop = '1em'; clearInfoButton.style.marginRight = '0.5em'; clearInfoButton.style.float = 'right'; clearInfoButton.id = 'clear-button'; registerDialog.appendChild(clearInfoButton); const closeButton = document.createElement('button'); closeButton.textContent = 'X'; closeButton.style.position = 'absolute'; closeButton.style.top = '7px'; closeButton.style.right = '7px'; closeButton.style.backgroundColor = '#ccc'; closeButton.style.border = 'none'; closeButton.style.borderRadius = '15%'; closeButton.style.color = '#fff'; closeButton.style.cursor = 'pointer'; closeButton.style.padding = '0.2em 0.5em'; closeButton.style.fontSize = '14px'; closeButton.addEventListener('click', () => { registerDialog.close(); registerDialog.remove(); }); registerDialog.appendChild(closeButton); const css = document.createElement('style'); css.id = 'tm-gist-css'; css.textContent = ` #tm-gist-dialog button:hover { opacity: 0.8; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); }`; registerDialog.appendChild(css); document.body.appendChild(registerDialog); return registerDialog; } function inIframe() { try { return window.self !== window.top; } catch (e) { return true; } }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址