// ==UserScript== // @name 发送到 Memos // @name:en Send to Memos // @namespace http://tampermonkey.net/ // @version 2.0 // @description 将选中的链接或文本发送到 Memos,支持配置、添加源页面信息和快速发送按钮 // @description:en Send selected links or text to Memos, supports configuration, adding source page information, and quick send buttons // @author Hu3rror // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 获取保存的配置或使用默认值 const MEMOS_API_URL = GM_getValue('MEMOS_API_URL', ''); const API_TOKEN = GM_getValue('MEMOS_API_TOKEN', ''); let isConfigured = MEMOS_API_URL && API_TOKEN; // 添加样式 GM_addStyle(` #memos-float-button { position: fixed; width: 50px; height: 50px; background-color: #4caf50; color: white; border-radius: 50%; text-align: center; line-height: 50px; font-size: 18px; font-weight: bold; cursor: pointer; box-shadow: 2px 2px 5px rgba(0,0,0,0.3); z-index: 9999; user-select: none; display: flex; align-items: center; justify-content: center; right: 20px; bottom: 20px; } #memos-float-button:hover { background-color: #45a049; } .memos-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); display: flex; justify-content: center; align-items: center; z-index: 10000; } .memos-modal-content { background-color: white; padding: 20px; border-radius: 8px; width: 400px; max-width: 90%; } .memos-modal h2 { margin-top: 0; color: #333; } .memos-form-group { margin-bottom: 15px; } .memos-form-group label { display: block; margin-bottom: 5px; font-weight: bold; } .memos-form-group input { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; } .memos-button { padding: 8px 16px; background-color: #4caf50; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 10px; } .memos-button.cancel { background-color: #f44336; } .memos-button:hover { opacity: 0.9; } .memos-buttons { display: flex; justify-content: flex-end; margin-top: 20px; } `); // 创建自动关闭的通知 function showNotification(message, isError = false) { const notification = document.createElement('div'); notification.style.position = 'fixed'; notification.style.top = '20px'; notification.style.right = '20px'; notification.style.padding = '10px 20px'; notification.style.backgroundColor = isError ? '#f44336' : '#4caf50'; notification.style.color = 'white'; notification.style.borderRadius = '5px'; notification.style.zIndex = '9999'; notification.style.opacity = '0.9'; notification.style.transition = 'opacity 0.2s ease'; notification.textContent = message; document.body.appendChild(notification); // 1.5秒后淡出并移除 setTimeout(() => { notification.style.opacity = '0'; setTimeout(() => { notification.remove(); }, 500); // 等待淡出动画完成 }, 1500); } // 获取选中文本 function getSelectedText() { return window.getSelection().toString().trim(); } // 获取当前页面信息,以 Markdown 格式 function getPageInfo() { const pageTitle = document.title || '无标题页面'; const pageUrl = window.location.href; return `\n\n---\n**来源**:[${pageTitle}](${pageUrl})`; } // 发送内容到 Memos 的函数 function sendToMemos(content) { if (!isConfigured) { showNotification('请先配置 Memos API URL 和 Token', true); showConfigModal(); return; } // 添加页面来源信息 content += getPageInfo(); GM_xmlhttpRequest({ method: 'POST', url: MEMOS_API_URL, headers: { 'Authorization': `Bearer ${API_TOKEN}`, 'Content-Type': 'application/json' }, data: JSON.stringify({ content: content, visibility: 'PRIVATE' // 可选:'PUBLIC', 'PROTECTED', 'PRIVATE' }), onload: function(response) { if (response.status === 200 || response.status === 201) { showNotification('成功发送到 Memos!'); } else { showNotification(`发送到 Memos 失败。状态码: ${response.status}\n可能端点错误,建议尝试 /api/v1/memo 或 /api/memos。`, true); } }, onerror: function(error) { showNotification('发送到 Memos 时出错: ' + error, true); } }); } // 存储当前右键点击的链接 let currentLink = null; // 监听右键点击事件,捕获链接 document.addEventListener('contextmenu', function(event) { currentLink = event.target.closest('a'); }, false); // 注册菜单命令 GM_registerMenuCommand('发送选中内容到 Memos', function() { handleSendAction(); }); GM_registerMenuCommand('配置 Memos API', function() { showConfigModal(); }); // 处理发送动作 function handleSendAction() { const selectedText = getSelectedText(); if (selectedText) { // 如果有选中文本,发送选中文本 sendToMemos(selectedText); } else if (currentLink && currentLink.href) { // 如果没有选中文本但有链接,发送链接 const linkText = currentLink.textContent.trim() || '无文本'; const linkUrl = currentLink.href; const content = `${linkText}\n${linkUrl}`; sendToMemos(content); } else { showNotification('请先选择文本或右键点击链接', true); } } // 清理 currentLink,防止重复使用 document.addEventListener('click', function() { currentLink = null; }, false); // 创建配置模态框 function showConfigModal() { // 创建模态框容器 const modal = document.createElement('div'); modal.className = 'memos-modal'; // 创建模态框内容 const modalContent = document.createElement('div'); modalContent.className = 'memos-modal-content'; modalContent.innerHTML = `