// ==UserScript== // @name B-Note-Uni (哔记通用版) // @namespace http://tampermonkey.net/ // @version 0.4 // @description 哔记(B-Note)的"Universal version"(通用版本),可在多个页面实现文本快速插入、图片插入、本地导入导出、快捷键、markdown写作、分屏模式。 // @author XYZ // @match *://*/* // @exclude *://*.bilibili.com/* // @exclude *://github.com/* // @grant none // @require https://code.jquery.com/jquery-3.6.0.min.js // @require https://code.jquery.com/ui/1.12.1/jquery-ui.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.5.0/jszip.min.js // @require https://unpkg.com/axios@1.1.2/dist/axios.min.js // @license MIT License // @icon data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIxLjUiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBhcmlhLWhpZGRlbj0idHJ1ZSI+CiAgPHBhdGggc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNC4yNiAxMC4xNDdhNjAuNDM2IDYwLjQzNiAwIDAwLS40OTEgNi4zNDdBNDguNjI3IDQ4LjYyNyAwIDAxMTIgMjAuOTA0YTQ4LjYyNyA0OC42MjcgMCAwMTguMjMyLTQuNDEgNjAuNDYgNjAuNDYgMCAwMC0uNDkxLTYuMzQ3bS0xNS40ODIgMGE1MC41NyA1MC41NyAwIDAwLTIuNjU4LS44MTNBNTkuOTA1IDU5LjkwNSAwIDAxMTIgMy40OTNhNTkuOTAyIDU5LjkwMiAwIDAxMTAuMzk5IDUuODRjLS44OTYuMjQ4LTEuNzgzLjUyLTIuNjU4LjgxNG0tMTUuNDgyIDBBNTAuNjk3IDUwLjY5NyAwIDAxMTIgMTMuNDg5YTUwLjcwMiA1MC43MDIgMCAwMTcuNzQtMy4zNDJNNi43NSAxNWEuNzUuNzUgMCAxMDAtMS41Ljc1Ljc1IDAgMDAwIDEuNXptMCAwdi0zLjY3NUE1NS4zNzggNTUuMzc4IDAgMDExMiA4LjQ0M20tNy4wMDcgMTEuNTVBNS45ODEgNS45ODEgMCAwMDYuNzUgMTUuNzV2LTEuNSI+PC9wYXRoPgo8L3N2Zz4= // @downloadURL https://update.greasyfork.icu/scripts/477045/B-Note-Uni%20%28%E5%93%94%E8%AE%B0%E9%80%9A%E7%94%A8%E7%89%88%29.user.js // @updateURL https://update.greasyfork.icu/scripts/477045/B-Note-Uni%20%28%E5%93%94%E8%AE%B0%E9%80%9A%E7%94%A8%E7%89%88%29.meta.js // ==/UserScript== (function () { 'use strict'; // 填写你的github的token以及repo(仓库名) let token = ''; let repo = ''; // Add the TOAST UI Editor CSS $('head').append(''); // Add the TOAST UI Editor JS const scriptEditor = document.createElement('script'); scriptEditor.src = 'https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js'; document.body.appendChild(scriptEditor); // Add the JQuery UI $('head').append(''); // Create a switch using SVG. function createSVGIcon(svgContent) { const svgIcon = $(svgContent); svgIcon.css({ width: '24px', height: '24px', verticalAlign: 'middle', marginRight: '5px' }); return svgIcon; } const openEditorIcon = ''; const closeEditorIcon = ''; // Create the button const openEditorButton = $(''); openEditorButton.append(createSVGIcon(openEditorIcon)); $('body').append(openEditorButton); const toggleButton = $(''); const toggleButtonText = $('打开B-Note'); toggleButton.append(createSVGIcon(openEditorIcon)).append(toggleButtonText); $('body').append(toggleButton); const buttonStyles = ` .B-Note-button { position: fixed; bottom: 10px; right: -80px; width: 120px; height: 32px; z-index: 10000; background-color: rgba(255, 255, 255, 0.2); color: black; border: none; border-radius: 4px; padding: 2px 0px; font-size: 13px; cursor: pointer; transition: right 0.3s, background-color 0.3s; } .B-Note-button:hover { background-color: rgba(255, 255, 255, 0.9); right: 0px; } `; const styleElement = $(''); styleElement.text(buttonStyles); $('head').append(styleElement); let saveButton; let helpButton; let editor; let editorDiv; let isEditorOpen = false; let isSplitScreen = false; let originalContainerStyle; // Get the current date, title, and current webpage link. function getPageInfo() { let currentDate = new Date(); let formattedDate = `${currentDate.getFullYear()}年${currentDate.getMonth() + 1}月${currentDate.getDate()}日`; let pageTitle = document.title; let pageLink = window.location.href; return { formattedDate, pageTitle, pageLink }; } let pageInfo = getPageInfo(); // Use IndexedDB to automatically back up notes. const dbName = 'BNoteDB'; const storeName = 'notes'; let db; const openRequest = indexedDB.open(dbName, 1); openRequest.onupgradeneeded = function (e) { const db = e.target.result; if (!db.objectStoreNames.contains(storeName)) { db.createObjectStore(storeName, { keyPath: 'pageTitle' }); } }; openRequest.onsuccess = function (e) { db = e.target.result; }; function saveNoteToDB() { if (isEditorOpen) { let { formattedDate, pageTitle, pageLink } = getPageInfo(); const content = editor.getMarkdown(); const timestamp = Date.now(); const note = { pageTitle, content, timestamp }; const transaction = db.transaction(storeName, 'readwrite'); const store = transaction.objectStore(storeName); store.put(note); } } setInterval(saveNoteToDB, 120000); // Upload to Github async function handleImageInsertion() { const content = editor.getMarkdown(); const regex = /!\[.*?\]\(data:image\/.*?;base64,.*?\)/g; const matches = content.match(regex); if (matches) { for (const match of matches) { const base64 = match.substring(match.indexOf('base64,') + 7, match.lastIndexOf(')')); const blob = base64ToBlob(base64); const imageUrl = await uploadImageToGitHub(blob); const newContent = content.replace(match, `![Image](${imageUrl})`); editor.setMarkdown(newContent); } } } function base64ToBlob(base64) { const binary = atob(base64); const array = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { array[i] = binary.charCodeAt(i); } return new Blob([array], { type: 'image/png' }); } async function uploadImageToGitHub(blob) { const branch = 'main'; const currentDate = new Date(); currentDate.setMinutes(currentDate.getMinutes() + currentDate.getTimezoneOffset() + 8 * 60); const year = currentDate.getFullYear(); const month = currentDate.getMonth() + 1; const day = currentDate.getDate(); const hours = currentDate.getHours(); const minutes = currentDate.getMinutes(); const seconds = currentDate.getSeconds(); const time = `${hours}-${minutes}-${seconds}`; const pageInfo = getPageInfo(); const invalidChars = /[<>:"/\\|?*]/g; const cleanedPageTitle = pageInfo.pageTitle.replace(invalidChars, ''); const path = `images/B-Note/${year}/${month}/${day}/${cleanedPageTitle}/${time}.png`; const url = `https://api.github.com/repos/${repo}/contents/${path}`; const base64 = await blobToBase64(blob); const payload = { message: 'Upload image', content: base64, branch: branch, }; const response = await axios.put(url, payload, { headers: { 'Authorization': `token ${token}`, 'Content-Type': 'application/json', }, }); return response.data.content.download_url; } function blobToBase64(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result.split(',')[1]); reader.onerror = reject; reader.readAsDataURL(blob); }); } const container = $('
'); // Function to create the editor function createEditor() { container.css({ position: 'fixed', top: '8%', right: '0%', width: '32%', height: '86%', zIndex: 99999, backgroundColor: '#fff', border: '1px solid #ccc', borderRadius: '5px', padding: '0px', overflow: 'hidden', }); $('body').append(container); // Make the container resizable container.resizable({ handles: 'n, e, s, w, ne, se, sw, nw', minWidth: 300, minHeight: 200, resize: function (event, ui) { const newHeight = ui.size.height - 80; editorDiv.height(newHeight + 'px'); } }); const handle = $('
B-Note
'); handle.css({ position: 'sticky', top: 0, height: '30px', backgroundColor: '#ccc', cursor: 'move', boxSizing: 'border-box', margin: '0', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '16px', fontStyle: 'bold', }); container.append(handle); const buttonDiv = $('
'); buttonDiv.css({ position: 'sticky', top: '35px', display: 'flex', justifyContent: 'flex-start', paddingLeft: '10px', marginBottom: '10px', gap: '10px', }); container.append(buttonDiv); // Get button SVG const saveIcon = ''; const importIcon = ''; const helpIcon = ''; const autoBackupIcon = ''; const insertIcon = ''; const splitScreenIcon = ''; // Get save button saveButton = createSVGButton(saveIcon, '保存', function () { saveEditorContent(); }); buttonDiv.append(saveButton); // Import button const importButton = createSVGButton(importIcon, '导入', function () { importEditorContent(); }); buttonDiv.append(importButton); // Create insert Button const insertButton = createSVGButton(insertIcon, '插入', function () { const selection = document.getSelection(); const selectedText = selection.toString(); const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null; const imgElement = range ? range.cloneContents().querySelector('img') : null; if (imgElement) { const imgSrc = imgElement.src; editor.replaceSelection(`![Image](${imgSrc})`); } else if (selectedText) { editor.insertText(selectedText); } }); insertButton.setAttribute("id", "insertButton"); buttonDiv.append(insertButton); // Create automatic backups. const autoBackupButton = createSVGButton(autoBackupIcon, '自动备份', function () { showAutoBackupDialog(); }); buttonDiv.append(autoBackupButton); // Create split-screen mode. const splitScreenButton = createSVGButton(splitScreenIcon, '分屏模式', toggleSplitScreen); buttonDiv.append(splitScreenButton); // Create the help button function createHelpPopup() { const helpPopup = $(`