您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
One-click clipboard quote → GitHub Gist, with keyword highlighting, versioning & Lemur compatibility
当前为
- // ==UserScript==
- // @name Clip-to-Gist
- // @name:zh-CN Clip-to-Gist 金句剪贴脚本(v2.3)
- // @namespace https://github.com/yourusername
- // @version 2.3
- // @description One-click clipboard quote → GitHub Gist, with keyword highlighting, versioning & Lemur compatibility
- // @description:zh-CN 一键剪贴板金句并上传至 GitHub Gist,支持关键词标注、高亮、版本号,并兼容 Lemur Browser
- // @author Your Name
- // @include *
- // @match *://*/*
- // @grant GM_setValue
- // @grant GM_getValue
- // @grant GM_xmlhttpRequest
- // @grant GM_addStyle
- // @grant GM_registerMenuCommand
- // @run-at document-end
- // @license MIT
- // ==/UserScript==
- ;(function() {
- 'use strict';
- // —— API 退回实现 ——
- // 存储
- const setValue = typeof GM_setValue === 'function'
- ? GM_setValue
- : (k, v) => localStorage.setItem(k, v);
- const getValue = typeof GM_getValue === 'function'
- ? (k, def) => {
- const v = GM_getValue(k);
- return v == null ? def : v;
- }
- : (k, def) => {
- const v = localStorage.getItem(k);
- return v == null ? def : v;
- };
- // HTTP 请求
- const httpRequest = typeof GM_xmlhttpRequest === 'function'
- ? GM_xmlhttpRequest
- : opts => {
- const h = opts.headers || {};
- if (opts.method === 'GET') {
- fetch(opts.url, { headers: h }).then(resp =>
- resp.text().then(text => opts.onload({ status: resp.status, responseText: text }))
- );
- } else {
- fetch(opts.url, {
- method: opts.method,
- headers: h,
- body: opts.data
- }).then(resp =>
- resp.text().then(text => opts.onload({ status: resp.status, responseText: text }))
- );
- }
- };
- // 样式注入
- function addStyle(css) {
- if (typeof GM_addStyle === 'function') {
- GM_addStyle(css);
- } else {
- const s = document.createElement('style');
- s.textContent = css;
- document.head.appendChild(s);
- }
- }
- // 菜单命令(Lemur 不支持时不用)
- if (typeof GM_registerMenuCommand === 'function') {
- GM_registerMenuCommand('配置 Gist 参数', openConfigModal);
- }
- // 版本号存储键
- const VERSION_KEY = 'clip2gistVersion';
- if (getValue(VERSION_KEY, null) == null) {
- setValue(VERSION_KEY, 1);
- }
- // 全局样式
- addStyle(`
- #clip2gist-trigger {
- position: fixed !important;
- bottom: 20px !important;
- right: 20px !important;
- width: 40px; height: 40px;
- line-height: 40px; text-align: center;
- background: #4CAF50; color: #fff;
- border-radius: 50%; cursor: pointer;
- z-index: 2147483647 !important;
- font-size: 24px;
- box-shadow: 0 2px 6px rgba(0,0,0,0.3);
- }
- .clip2gist-mask {
- position: fixed; inset: 0; background: rgba(0,0,0,0.5);
- display: flex; align-items: center; justify-content: center;
- z-index: 2147483646;
- }
- .clip2gist-dialog {
- background: #fff; padding: 20px; border-radius: 8px;
- max-width: 90%; max-height: 90%; overflow: auto;
- box-shadow: 0 2px 10px rgba(0,0,0,0.3);
- }
- .clip2gist-dialog input {
- width: 100%; padding: 6px; margin: 4px 0 12px;
- box-sizing: border-box; font-size: 14px;
- }
- .clip2gist-dialog button {
- margin-left: 8px; padding: 6px 12px; font-size: 14px;
- cursor: pointer;
- }
- .clip2gist-word {
- display: inline-block; margin: 2px; padding: 4px 6px;
- border: 1px solid #ccc; border-radius: 4px; cursor: pointer;
- user-select: none;
- }
- .clip2gist-word.selected {
- background: #ffeb3b; border-color: #f1c40f;
- }
- #clip2gist-preview {
- margin-top: 12px; padding: 8px; border: 1px solid #ddd;
- min-height: 40px; font-family: monospace;
- }
- `);
- // 主流程
- async function mainFlow() {
- let text = '';
- try {
- text = await navigator.clipboard.readText();
- } catch (e) {
- return alert('请在 HTTPS 环境并授权剪贴板访问');
- }
- if (!text.trim()) {
- return alert('剪贴板内容为空');
- }
- showEditDialog(text.trim());
- }
- // 在移动端/桌面延迟插入浮动按钮
- function insertTrigger() {
- if (!document.body) {
- return setTimeout(insertTrigger, 100);
- }
- const btn = document.createElement('div');
- btn.id = 'clip2gist-trigger';
- btn.textContent = '📝';
- // 单击→主流程,双击→配置
- btn.addEventListener('click', mainFlow, false);
- btn.addEventListener('dblclick', openConfigModal, false);
- document.body.appendChild(btn);
- }
- insertTrigger();
- // 编辑对话框
- function showEditDialog(rawText) {
- const mask = document.createElement('div');
- mask.className = 'clip2gist-mask';
- const dlg = document.createElement('div');
- dlg.className = 'clip2gist-dialog';
- // 词块化
- const container = document.createElement('div');
- rawText.split(/\s+/).forEach(w => {
- const sp = document.createElement('span');
- sp.className = 'clip2gist-word';
- sp.textContent = w;
- sp.addEventListener('click', () => {
- sp.classList.toggle('selected'); updatePreview();
- });
- container.appendChild(sp);
- });
- dlg.appendChild(container);
- // 预览区
- const preview = document.createElement('div');
- preview.id = 'clip2gist-preview';
- dlg.appendChild(preview);
- // 按钮
- const row = document.createElement('div');
- ['取消','配置','确认'].forEach(label => {
- const b = document.createElement('button');
- b.textContent = label;
- if (label==='取消') b.onclick = () => document.body.removeChild(mask);
- else if (label==='配置') b.onclick = openConfigModal;
- else b.onclick = onConfirm;
- row.appendChild(b);
- });
- dlg.appendChild(row);
- mask.appendChild(dlg);
- document.body.appendChild(mask);
- updatePreview();
- function updatePreview() {
- const spans = Array.from(container.children);
- const segs = [];
- for (let i=0; i<spans.length;) {
- if (spans[i].classList.contains('selected')) {
- const group=[spans[i].textContent], j=i+1;
- while (j<spans.length && spans[j].classList.contains('selected')) {
- group.push(spans[j].textContent); j++;
- }
- segs.push(`{${group.join(' ')}}`);
- i=j;
- } else {
- segs.push(spans[i].textContent); i++;
- }
- }
- preview.textContent = segs.join(' ');
- }
- async function onConfirm() {
- const gistId = getValue('gistId','');
- const token = getValue('githubToken','');
- if (!gistId || !token) {
- return alert('请先配置 Gist ID 与 GitHub Token');
- }
- const ver = getValue(VERSION_KEY,1);
- const header = `版本 ${ver}`;
- const content = preview.textContent;
- // 拉取
- httpRequest({
- method: 'GET',
- url: `https://api.github.com/gists/${gistId}`,
- headers: { Authorization: `token ${token}` },
- onload(resp1) {
- if (resp1.status !== 200) {
- return alert('拉取 Gist 失败:'+resp1.status);
- }
- const data = JSON.parse(resp1.responseText);
- const fname = Object.keys(data.files)[0];
- const old = data.files[fname].content;
- const updated = `\n\n----\n${header}\n${content}` + old;
- // 更新
- httpRequest({
- method: 'PATCH',
- url: `https://api.github.com/gists/${gistId}`,
- headers: {
- Authorization: `token ${token}`,
- 'Content-Type': 'application/json'
- },
- data: JSON.stringify({ files:{[fname]:{content:updated}} }),
- onload(resp2) {
- if (resp2.status === 200) {
- alert(`上传成功 🎉 已发布版本 ${ver}`);
- setValue(VERSION_KEY, ver+1);
- document.body.removeChild(mask);
- } else {
- alert('上传失败:'+resp2.status);
- }
- }
- });
- }
- });
- }
- }
- // 配置对话框
- function openConfigModal() {
- const mask = document.createElement('div');
- mask.className = 'clip2gist-mask';
- const dlg = document.createElement('div');
- dlg.className = 'clip2gist-dialog';
- const l1 = document.createElement('label');
- l1.textContent = 'Gist ID:';
- const i1 = document.createElement('input');
- i1.value = getValue('gistId','');
- const l2 = document.createElement('label');
- l2.textContent = 'GitHub Token:';
- const i2 = document.createElement('input');
- i2.value = getValue('githubToken','');
- dlg.append(l1,i1,l2,i2);
- const save = document.createElement('button');
- save.textContent = '保存';
- save.onclick = () => {
- setValue('gistId', i1.value.trim());
- setValue('githubToken', i2.value.trim());
- alert('配置已保存');
- document.body.removeChild(mask);
- };
- const cancel = document.createElement('button');
- cancel.textContent = '取消';
- cancel.onclick = () => document.body.removeChild(mask);
- dlg.append(save,cancel);
- mask.appendChild(dlg);
- document.body.appendChild(mask);
- }
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址