您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
本地笔记追加同步到GitHub为纯文本,无同步弹窗,结果写控制台,保留其他弹窗提示,移动端兼容!
// ==UserScript== // @name 短语笔记CSV导出 // @namespace http://tampermonkey.net/ // @version 1.9 // @description 本地笔记追加同步到GitHub为纯文本,无同步弹窗,结果写控制台,保留其他弹窗提示,移动端兼容! // @author ChatGPT // @match *://*/* // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @connect api.github.com // ==/UserScript== (function () { 'use strict'; const NOTE_KEY = 'mobile_note_list'; const GITHUB_USERNAME = 'moodHappy'; const REPO_NAME = 'HelloWorld'; const FILE_PATH = 'Notes/phrase_note.json'; // 内容纯文本,后缀json无影响 const TOKEN = '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'; // Function to show a temporary message at the highest z-index function showTemporaryMessage(msg, duration = 3000) { const messageDiv = document.createElement('div'); messageDiv.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: rgba(0, 0, 0, 0.8); /* Slightly darker background for better visibility */ color: white; padding: 18px 30px; /* Slightly larger padding */ border-radius: 10px; /* Slightly more rounded corners */ z-index: 2147483641; /* Set to a very high z-index */ font-size: 18px; /* Larger font size */ text-align: center; opacity: 0; transition: opacity 0.4s ease-in-out; /* Slightly longer transition */ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); /* Add a subtle shadow */ `; messageDiv.textContent = msg; document.body.appendChild(messageDiv); // Fade in setTimeout(() => { messageDiv.style.opacity = '1'; }, 10); // Fade out and remove setTimeout(() => { messageDiv.style.opacity = '0'; messageDiv.addEventListener('transitionend', () => messageDiv.remove()); }, duration); console.log('[笔记]', msg); } // Original showMessage for critical alerts (e.g., selection issues) that require user action function showMessage(msg) { alert(msg); console.log('[笔记]', msg); } function logSync(msg) { console.log('[同步日志]', msg); } function getNotes() { try { return JSON.parse(GM_getValue(NOTE_KEY, '[]')); } catch (e) { return []; } } function setNotes(notes) { GM_setValue(NOTE_KEY, JSON.stringify(notes)); } async function storeNote() { // Made async to await syncToGitHub const selection = window.getSelection().toString().trim(); if (!selection) return showMessage('❗请先选中文本。'); // Still uses alert for user action const formatted = selection.replace(/["“”]:?|:/, '|').replace(/["“”]/g, ''); if (!formatted.includes('|')) return showMessage('❗格式不符,请选中形如 xxx:"yyy" 的文本'); // Still uses alert for user action const notes = getNotes(); notes.push(formatted); setNotes(notes); // Changed to showTemporaryMessage for "note saved successfully" showTemporaryMessage(`✅ 已保存笔记:\n${formatted}`, 3000); if (notes.length >= 5) { exportNotes(notes); // This will now also trigger syncToGitHub setNotes([]); showTemporaryMessage('📤 自动导出并清空本地笔记(5条)', 3000); // Changed to showTemporaryMessage } } function showNoteCount() { const notes = getNotes(); showTemporaryMessage(`📊 当前已保存 ${notes.length} 条笔记`, 3000); // Changed to showTemporaryMessage } async function manualExport() { // Made async to await syncToGitHub const notes = getNotes(); if (notes.length === 0) return showTemporaryMessage('⚠️ 当前没有需要导出的笔记', 3000); // Changed to showTemporaryMessage exportNotes(notes); // This will now also trigger syncToGitHub setNotes([]); showTemporaryMessage(`📤 手动导出并清空 ${notes.length} 条笔记`, 3000); // Changed to showTemporaryMessage } async function exportNotes(notes) { // Made async to await syncToGitHub const csv = '\uFEFF' + notes.join('\n'); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'notes_' + new Date().toISOString().replace(/[:T]/g, '-').slice(0, 19) + '.csv'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(a.href); // Trigger GitHub sync after successful CSV export await syncToGitHub(); } async function syncToGitHub() { const newNotes = getNotes(); if (newNotes.length === 0) { logSync('⚠️ 没有笔记需要同步'); showTemporaryMessage('⚠️ 没有笔记需要同步', 3000); // Also show temp message for no notes return; } logSync('☁️ 开始同步到 GitHub(追加模式)...'); showTemporaryMessage('☁️ 正在同步笔记到 GitHub...', 5000); // Show a syncing message const url = `https://api.github.com/repos/${GITHUB_USERNAME}/${REPO_NAME}/contents/${FILE_PATH}`; const headers = { 'Authorization': `Bearer ${TOKEN}`, 'Accept': 'application/vnd.github+json' }; try { let oldText = ''; let sha = ''; const res = await fetch(url, { headers }); if (res.status === 200) { const data = await res.json(); sha = data.sha; oldText = decodeURIComponent(escape(atob(data.content.replace(/\n/g, '')))); } const oldLines = oldText.split('\n').filter(line => line.trim()); const allNotesSet = new Set([...newNotes, ...oldLines]); const combinedText = '\uFEFF' + Array.from(allNotesSet).join('\n'); const encodedContent = btoa(unescape(encodeURIComponent(combinedText))); const uploadBody = { message: '📤 追加同步笔记', content: encodedContent, committer: { name: GITHUB_USERNAME, email: `${GITHUB_USERNAME}@users.noreply.github.com` } }; if (sha) uploadBody.sha = sha; const putRes = await fetch(url, { method: 'PUT', headers, body: JSON.stringify(uploadBody) }); if (putRes.ok) { logSync('✅ 成功追加同步到 GitHub 并清空本地笔记'); showTemporaryMessage('✅ 笔记已成功同步到 GitHub!', 3000); // Success message setNotes([]); } else { const errText = await putRes.text(); console.error('❌ 上传失败:', errText); logSync(`❌ 同步失败:${putRes.status}`); showTemporaryMessage('❌ 笔记同步到 GitHub 失败!', 3000); // Failure message } } catch (err) { console.error('❌ 异常:', err); logSync('❌ 网络错误或Token无效'); showTemporaryMessage('❌ 笔记同步到 GitHub 失败!网络错误或Token无效。', 3000); // Error message } } // 菜单命令 GM_registerMenuCommand('📌 存储笔记(选中文本)', storeNote); GM_registerMenuCommand('📊 查看笔记数量', showNoteCount); GM_registerMenuCommand('📤 手动导出CSV', manualExport); GM_registerMenuCommand('☁️ 同步到GitHub(追加模式)', syncToGitHub); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址