// ==UserScript==
// @name 全局快捷关键词复制·增强存储导出版
// @namespace http://tampermonkey.net/
// @version 3.10
// @description 本地存储、位置记忆、添加/删除/导出关键词
// @match *://*/*
// @grant none
// @run-at document-idle
// @downloadURL https://update.greasyfork.icu/scripts/575523/%E5%85%A8%E5%B1%80%E5%BF%AB%E6%8D%B7%E5%85%B3%E9%94%AE%E8%AF%8D%E5%A4%8D%E5%88%B6%C2%B7%E5%A2%9E%E5%BC%BA%E5%AD%98%E5%82%A8%E5%AF%BC%E5%87%BA%E7%89%88.user.js
// @updateURL https://update.greasyfork.icu/scripts/575523/%E5%85%A8%E5%B1%80%E5%BF%AB%E6%8D%B7%E5%85%B3%E9%94%AE%E8%AF%8D%E5%A4%8D%E5%88%B6%C2%B7%E5%A2%9E%E5%BC%BA%E5%AD%98%E5%82%A8%E5%AF%BC%E5%87%BA%E7%89%88.meta.js
// ==/UserScript==
(function() {
'use strict';
// 存储 KEY
const KEY_STORAGE = "quick_copy_keywords";
const POS_STORAGE = "quick_copy_panel_pos";
// 默认关键词
const DEFAULT_KEYWORDS = [
"俄乌战争", "伊朗", "巴以冲突", "叙利亚", "中东局势",
"俄罗斯", "乌克兰", "军事新闻", "地缘政治", "美军动态",
"北约", "朝鲜", "国际局势", "中国外交", "台海",
"日本动态", "韩国新闻", "欧盟", "非洲局势", "拉美动态"
];
// 读取关键词
function getKeys() {
try {
const data = localStorage.getItem(KEY_STORAGE);
return data ? JSON.parse(data) : DEFAULT_KEYWORDS;
} catch {
return DEFAULT_KEYWORDS;
}
}
// 保存关键词
function saveKeys(arr) {
localStorage.setItem(KEY_STORAGE, JSON.stringify(arr));
}
// 读取位置
function getPos() {
try {
return JSON.parse(localStorage.getItem(POS_STORAGE)) || { left: 20, top: 500 };
} catch {
return { left: 20, top: 500 };
}
}
// 保存位置
function savePos(x, y) {
localStorage.setItem(POS_STORAGE, JSON.stringify({ left: x, top: y }));
}
if (document.getElementById('quick-copy-panel')) return;
const root = document.createElement('div');
root.id = 'quick-copy-panel';
const pos = getPos();
root.style.cssText = `
all: initial;
position: fixed;
z-index: 9999999;
left: ${pos.left}px;
top: ${pos.top}px;
width: 220px;
font-family: system-ui, sans-serif;
user-select: none;
`;
document.body.appendChild(root);
const bar = document.createElement('div');
bar.style.cssText = `
background: #1677ff;
color: white;
padding: 10px 12px;
border-radius: 10px 10px 0 0;
font-size: 14px;
font-weight: 500;
display: flex;
justify-content: space-between;
align-items: center;
cursor: move;
`;
bar.innerHTML = `快捷复制−`;
root.appendChild(bar);
const panel = document.createElement('div');
panel.id = 'panel-body';
panel.style.cssText = `
background: #ffffff;
border-radius: 0 0 10px 10px;
padding: 10px;
box-shadow: 0 4px 16px rgba(0,0,0,0.15);
max-height: 320px;
overflow-y: auto;
::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-thumb { background: #ccc; border-radius: 5px; }
::-webkit-scrollbar-track { background: #f5f5f5; }
`;
root.appendChild(panel);
const input = document.createElement('input');
input.type = 'text';
input.placeholder = "输入自定义关键词";
input.style.cssText = `
width: 100%;
box-sizing: border-box;
padding: 8px 10px;
border: 1px solid #e0e0e0;
border-radius: 6px;
font-size: 14px;
margin-bottom: 8px;
outline: none;
`;
panel.appendChild(input);
const btnGroup = document.createElement('div');
btnGroup.style.display = "flex";
btnGroup.style.gap = "6px";
btnGroup.style.marginBottom = "10px";
const copyBtn = document.createElement('button');
copyBtn.textContent = '复制';
copyBtn.style.cssText = `
flex:1; padding: 8px; background:#1677ff; color:white; border:none; border-radius:6px; cursor:pointer;
`;
const addBtn = document.createElement('button');
addBtn.textContent = '添加';
addBtn.style.cssText = `
flex:1; padding: 8px; background:#22c55e; color:white; border:none; border-radius:6px; cursor:pointer;
`;
btnGroup.append(copyBtn, addBtn);
panel.appendChild(btnGroup);
const list = document.createElement('div');
list.style.cssText = `
display: flex; flex-wrap: wrap; gap: 6px; margin-bottom:10px;
`;
panel.appendChild(list);
const exportBtn = document.createElement('button');
exportBtn.textContent = "导出全部关键词";
exportBtn.style.cssText = `
width:100%; padding:8px; background:#ff4081; color:#fff;
border:none; border-radius:6px; cursor:pointer; font-size:13px;
`;
panel.appendChild(exportBtn);
// 渲染列表
function renderList() {
list.innerHTML = "";
const keys = getKeys();
keys.forEach((kw, idx) => {
const item = document.createElement('div');
item.style.cssText = "position:relative;";
const btn = document.createElement('button');
btn.textContent = kw;
btn.style.cssText = `
padding: 6px 20px 6px 10px;
border:none; border-radius:6px;
background:#f2f2f2; font-size:13px;
cursor:pointer; white-space:nowrap;
`;
btn.onclick = () => {
input.value = kw;
copyText(kw);
};
const del = document.createElement('span');
del.textContent = "×";
del.style.cssText = `
position:absolute; right:4px; top:2px;
font-size:12px; color:#999; cursor:pointer;
`;
del.onclick = (e) => {
e.stopPropagation();
keys.splice(idx, 1);
saveKeys(keys);
renderList();
};
item.appendChild(btn);
item.appendChild(del);
list.appendChild(item);
});
}
// 添加
addBtn.onclick = () => {
const val = input.value.trim();
if (!val) return tip("请输入关键词");
const list = getKeys();
list.push(val);
saveKeys(list);
input.value = "";
renderList();
tip("已添加:" + val);
};
// 导出
exportBtn.onclick = () => {
const arr = getKeys();
const code = "const KEYWORDS = " + JSON.stringify(arr, null, 4) + ";";
navigator.clipboard.writeText(code).then(() => {
tip("已复制全部关键词");
});
};
// 折叠
const foldBtn = document.getElementById('fold-btn');
foldBtn.style.cursor = 'pointer';
foldBtn.onclick = () => {
const hidden = panel.style.display === 'none';
panel.style.display = hidden ? 'block' : 'none';
foldBtn.textContent = hidden ? '−' : '+';
bar.style.borderRadius = hidden ? '10px' : '10px 10px 0 0';
};
// 复制
function copyText(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.cssText = 'position:fixed;left:-9999px;top:-9999px;';
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
const tip = document.createElement('div');
tip.textContent = `已复制:${text}`;
tip.style.cssText = `
position: fixed; left:50%; bottom:80px; transform:translateX(-50%);
background:rgba(0,0,0,0.7); color:white; padding:6px 12px; border-radius:6px;
font-size:13px; z-index:99999999; white-space:nowrap;
`;
document.body.appendChild(tip);
setTimeout(() => tip.remove(), 1200);
}
copyBtn.onclick = () => {
const val = input.value.trim();
if (val) copyText(val);
};
// 拖拽 + 位置保存
let isDrag = false, startX, startY, origLeft, origTop;
bar.addEventListener('mousedown', e => {
if (e.target === foldBtn) return;
isDrag = false;
startX = e.clientX;
startY = e.clientY;
origLeft = root.offsetLeft;
origTop = root.offsetTop;
const move = ev => {
const dx = ev.clientX - startX;
const dy = ev.clientY - startY;
if (Math.abs(dx) > 4 || Math.abs(dy) > 4) isDrag = true;
root.style.left = origLeft + dx + 'px';
root.style.top = origTop + dy + 'px';
};
const up = () => {
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', up);
if (isDrag) savePos(root.offsetLeft, root.offsetTop);
};
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', up);
});
function tip(text) {
const t = document.createElement('div');
t.textContent = text;
t.style.cssText = `
position:fixed; bottom:60px; left:50%; transform:translateX(-50%);
background:rgba(0,0,0,0.7); color:#fff; padding:5px 10px; border-radius:4px;
font-size:12px; z-index:999999;
`;
document.body.appendChild(t);
setTimeout(() => t.remove(), 1400);
}
renderList();
// 默认永久折叠
panel.style.display = "none";
foldBtn.textContent = "+";
bar.style.borderRadius = "10px";
})();