您需要先安装一个扩展,例如 篡改猴、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或关注我们的公众号极客氢云获取最新地址