您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Storing and loading Lorebook Entries for Discord/Shapes
// ==UserScript== // @name Discord/Shapes - Lorebook // @namespace http://tampermonkey.net/ // @version 1.8 // @description Storing and loading Lorebook Entries for Discord/Shapes // @author Vishanka // @match https://discord.com/channels/* // @grant unsafeWindow // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // Create and add the arrow button to open the storage panel const arrowButton = document.createElement('div'); arrowButton.innerHTML = '〈'; // Unicode for a more spread left-pointing angle bracket arrowButton.style.position = 'fixed'; arrowButton.style.bottom = '50%'; arrowButton.style.right = '0'; // Start visible at the screen edge arrowButton.style.padding = '10px'; arrowButton.style.fontSize = '24px'; arrowButton.style.zIndex = '1000'; arrowButton.style.cursor = 'pointer'; //arrowButton.style.backgroundColor = '#212121'; arrowButton.style.color = '#B4B4B4'; // Light grey color arrowButton.style.borderRadius = '5px 0 0 5px'; arrowButton.style.transition = 'transform 0.3s ease, right 0.3s ease, background-color 0.1s'; arrowButton.onmouseover = () => { arrowButton.style.backgroundColor = 'transparent'; }; arrowButton.onmouseout = () => { arrowButton.style.backgroundColor = 'transparent'; }; document.body.appendChild(arrowButton); // Create the fancy sliding panel unsafeWindow.DCstoragePanel = document.createElement('div'); DCstoragePanel.style.position = 'fixed'; DCstoragePanel.style.top = '0'; DCstoragePanel.style.right = '-250px'; // Initially hidden DCstoragePanel.style.height = '100%'; DCstoragePanel.style.width = '250px'; DCstoragePanel.style.backgroundColor = '#171717'; //storagePanel.style.boxShadow = '-4px 0px 8px rgba(0, 0, 0, 0.5)'; DCstoragePanel.style.transition = 'right 0.3s ease'; DCstoragePanel.style.zIndex = '999'; document.body.appendChild(DCstoragePanel); // Create the header above the button const storagePanelHeader = document.createElement('div'); storagePanelHeader.innerText = 'Shapes Tools'; storagePanelHeader.style.margin = '20px'; storagePanelHeader.style.padding = '10px'; storagePanelHeader.style.fontSize = '19px'; storagePanelHeader.style.fontWeight = '550'; storagePanelHeader.style.color = '#ECECEC'; storagePanelHeader.style.textAlign = 'center'; DCstoragePanel.appendChild(storagePanelHeader); // Create a divider line const dividerLine = document.createElement('div'); dividerLine.style.height = '1px'; dividerLine.style.backgroundColor = '#212121'; // Dark grey color for subtle separation dividerLine.style.margin = '10px 20px'; // Space around the line (top/bottom, left/right) DCstoragePanel.appendChild(dividerLine); // Create the button inside the panel // Create the button to open the panel const button = document.createElement('button'); button.id = 'profileManagerButton'; button.innerText = 'Manage Lorebook'; button.style.marginTop = '20px'; button.style.marginLeft = '13px'; button.style.marginRight = '5px'; button.style.padding = '7px 15px'; button.style.fontSize = '16px'; button.style.cursor = 'pointer'; button.style.backgroundColor = 'transparent'; button.style.color = '#b0b0b0'; // Light grey text color button.style.borderRadius = '8px'; button.style.textAlign = 'center'; button.style.width = '90%'; button.style.transition = 'background-color 0.1s, color 0.1s'; button.onmouseover = () => { button.style.backgroundColor = '#212121'; button.style.color = '#ffffff'; }; button.onmouseout = () => { button.style.backgroundColor = 'transparent'; button.style.color = '#b0b0b0'; }; DCstoragePanel.appendChild(button); //DCstoragePanel.appendChild(uiButton); //DCstoragePanel.appendChild(settingsWindow); //DCstoragePanel.appendChild(importButton); //DCstoragePanel.appendChild(exportButton); // Toggle panel visibility arrowButton.addEventListener('click', () => { if (DCstoragePanel.style.right === '-250px') { DCstoragePanel.style.right = '0'; arrowButton.style.right = '250px'; // Clamp arrow button to the panel border arrowButton.style.transform = 'rotate(180deg)'; // Rotate the arrow } else { DCstoragePanel.style.right = '-250px'; arrowButton.style.right = '0'; // Keep arrow button visible at the screen edge arrowButton.style.transform = 'rotate(0deg)'; } }); // Create the main panel container const panel = document.createElement('div'); panel.id = 'profileManagerPanel'; panel.style.position = 'fixed'; panel.style.top = '50%'; panel.style.left = '50%'; panel.style.transform = 'translate(-50%, -50%)'; // Check if the device is mobile if (window.innerWidth <= 768) { // Example threshold for mobile panel.style.width = '90%'; // Wider for mobile panel.style.height = '90%'; // Taller for mobile } else { panel.style.width = '800px'; // Default for non-mobile panel.style.height = '700px'; // Default for non-mobile } panel.style.backgroundColor = '#2F2F2F'; panel.style.borderRadius = '20px'; panel.style.padding = '10px'; panel.style.display = 'none'; panel.style.zIndex = '1000'; document.body.appendChild(panel); // Add close button for the panel const closeButton = document.createElement('button'); closeButton.innerText = '✕'; closeButton.style.position = 'absolute'; closeButton.style.borderRadius = '50%'; closeButton.style.color = '#ffffff'; closeButton.style.top = '20px'; closeButton.style.right = '20px'; closeButton.style.backgroundColor = 'transparent'; closeButton.style.cursor = 'pointer'; // Hover effect closeButton.addEventListener('mouseenter', () => { // closeButton.style.transform = 'scale(1.1)'; closeButton.style.backgroundColor = '#676767'; }); closeButton.addEventListener('mouseleave', () => { // closeButton.style.transform = 'scale(1)'; closeButton.style.backgroundColor = 'transparent'; }); panel.appendChild(closeButton); closeButton.addEventListener('click', () => { panel.style.display = 'none'; }); // Toggle panel visibility when button is clicked button.addEventListener('click', () => { panel.style.display = panel.style.display === 'none' ? 'block' : 'none'; loadProfileEntries(); }); const profileslabel = document.createElement('div'); profileslabel.textContent = 'Profiles'; profileslabel.style.color = '#dddddd'; profileslabel.style.fontSize = '14px'; profileslabel.style.marginBottom = '5px'; profileslabel.style.marginLeft = '3px'; profileslabel.style.marginTop = '5px'; profileslabel.style.fontSize = '20px'; profileslabel.style.fontWeight = '550'; panel.appendChild(profileslabel); // Create the profile management panel const profilePanel = document.createElement('div'); profilePanel.id = 'profilePanel'; profilePanel.style.float = 'left'; profilePanel.style.width = '20%'; profilePanel.style.borderRight = '0.5px solid #444444'; profilePanel.style.height = '93%'; panel.appendChild(profilePanel); // Create the profile list container const profileList = document.createElement('div'); profileList.id = 'profileList'; profileList.style.height = '95%'; profileList.style.color = 'white'; profileList.style.overflowY = 'auto'; profilePanel.appendChild(profileList); // Create the add profile button const addProfileButton = document.createElement('button'); addProfileButton.innerText = 'Add Profile'; addProfileButton.style.padding = '8px'; addProfileButton.style.border = '0.2px solid #4E4E4E'; addProfileButton.style.backgroundColor = 'transparent'; addProfileButton.style.color = '#fff'; addProfileButton.style.borderRadius = '20px'; addProfileButton.style.width = '90%'; addProfileButton.style.cursor = 'pointer'; addProfileButton.onmouseover = () => { addProfileButton.style.backgroundColor = '#424242'; }; addProfileButton.onmouseout = () => { addProfileButton.style.backgroundColor = 'transparent'; }; profilePanel.appendChild(addProfileButton); // Add functionality to add profile button addProfileButton.addEventListener('click', () => { const profileName = prompt('Enter profile name:'); if (profileName) { const profileKey = `profile-${profileName}`; if (!localStorage.getItem(profileKey)) { localStorage.setItem(profileKey, JSON.stringify({})); // Save profile under key "profile-[profilename]" with empty value loadProfiles(); } else { alert('Profile already exists.'); } } }); // Create the profile selection functionality function loadProfiles() { profileList.innerHTML = ''; Object.keys(localStorage).forEach(profileKey => { if (profileKey.startsWith('profile-')) { const profileName = profileKey.replace('profile-', ''); const profileItem = document.createElement('div'); profileItem.innerText = profileName; profileItem.style.padding = '5px'; profileItem.style.marginBottom = '5px'; profileItem.style.cursor = 'pointer'; profileItem.style.backgroundColor = profileName === getCurrentProfile() ? '#424242' : '#2F2F2F'; profileItem.style.borderRadius = '5px'; profileItem.style.width = '90%'; profileItem.style.position = 'relative'; profileItem.addEventListener('click', () => { setCurrentProfile(profileName); loadProfiles(); loadProfileEntries(); }); const removeButton = document.createElement('button'); removeButton.innerText = '✕'; removeButton.style.position = 'absolute'; removeButton.style.top = '3px'; removeButton.style.right = '10px'; removeButton.style.cursor = 'pointer'; removeButton.style.backgroundColor = 'transparent'; removeButton.style.color = 'white'; removeButton.addEventListener('click', (e) => { e.stopPropagation(); localStorage.removeItem(profileKey); if (profileName === getCurrentProfile()) { setCurrentProfile(null); } loadProfiles(); loadProfileEntries(); }); profileItem.appendChild(removeButton); profileList.appendChild(profileItem); } }); } const title = document.createElement('h3'); title.innerText = 'Manage Lorebook Entries'; title.style.fontWeight = 'normal'; title.style.color = '#ffffff'; title.style.textAlign = 'left'; title.style.fontSize = '24px'; title.style.marginTop = '20px'; title.style.position = 'relative'; title.style.marginLeft = '23%'; title.style.marginBottom = '15px'; title.style.fontWeight = '550'; panel.appendChild(title); // Create profile entries list const profileEntriesList = document.createElement('div'); profileEntriesList.id = 'profileEntriesList'; profileEntriesList.style.marginTop = '20px'; profileEntriesList.style.height = '48%'; // Check if the device is mobile if (window.innerWidth <= 768) { // Example threshold for mobile profileEntriesList.style.height = '30%'; } else { profileEntriesList.style.height = '48%'; } profileEntriesList.style.overflowY = 'auto'; panel.appendChild(profileEntriesList); const entrieslabel = document.createElement('div'); entrieslabel.textContent = 'Enter keys and description:'; entrieslabel.style.color = '#dddddd'; entrieslabel.style.fontSize = '14px'; entrieslabel.style.marginBottom = '5px'; entrieslabel.style.marginTop = '5px'; entrieslabel.style.marginLeft = '23%'; panel.appendChild(entrieslabel); // Create key-value input fields const inputContainer = document.createElement('div'); inputContainer.id = 'inputContainer'; inputContainer.style.marginTop = '10px'; inputContainer.style.display = 'flex'; inputContainer.style.flexDirection = 'column'; inputContainer.style.alignItems = 'center'; // Center children horizontally inputContainer.style.margin = '0 auto'; panel.appendChild(inputContainer); const keyInput = document.createElement('input'); // keyInput.id = 'keyInput'; keyInput.type = 'text'; keyInput.placeholder = 'Entry Keywords (comma-separated)'; keyInput.style.width = '90%'; keyInput.style.marginBottom = '5px'; keyInput.style.padding = '10px'; keyInput.style.border = '1px solid #444444'; keyInput.style.borderRadius = '8px'; keyInput.style.backgroundColor = '#1e1e1e'; keyInput.style.color = '#dddddd'; inputContainer.appendChild(keyInput); const valueInput = document.createElement('textarea'); // valueInput.id = 'valueInput'; valueInput.placeholder = ' '; valueInput.style.width = '90%'; valueInput.style.marginBottom = '5px'; valueInput.style.padding = '10px'; valueInput.style.border = '1px solid #444444'; valueInput.style.borderRadius = '8px'; valueInput.style.backgroundColor = '#1e1e1e'; valueInput.style.color = '#dddddd'; valueInput.style.height = '100px'; valueInput.style.resize = 'vertical'; valueInput.maxLength = 1000; valueInput.style.overflow = 'auto'; const charCounter = document.createElement('div'); charCounter.style.color = '#dddddd'; charCounter.style.fontSize = '12px'; charCounter.style.marginTop = '0px'; charCounter.style.marginBottom = '15px'; charCounter.style.textAlign = 'right'; charCounter.style.marginRight = '-87%'; charCounter.style.color = 'grey'; charCounter.textContent = `0/${valueInput.maxLength}`; // Update the counter as the user types valueInput.addEventListener('input', () => { charCounter.textContent = `${valueInput.value.length}/${valueInput.maxLength}`; }); inputContainer.appendChild(valueInput); inputContainer.appendChild(charCounter); const saveButton = document.createElement('button'); saveButton.innerText = 'Add Entry'; saveButton.style.padding = '10px 20px'; saveButton.style.border = '0.2px solid #4E4E4E'; saveButton.style.backgroundColor = '#2F2F2F'; saveButton.style.color = '#fff'; saveButton.style.borderRadius = '50px'; saveButton.style.cursor = 'pointer'; saveButton.style.width = '95%'; inputContainer.appendChild(saveButton); let isEditing = false; let editingKey = ''; saveButton.addEventListener('click', () => { const key = keyInput.value.trim(); // Trim any extra spaces const value = valueInput.value; const currentProfile = getCurrentProfile(); if (key && currentProfile) { const profileKey = `${currentProfile}-lorebook:${key.toLowerCase()}`; // Normalize to lowercase const formattedValue = `<[Lorebook: ${key}] ${value}>`; // Check for duplicate keys (case-insensitive) const isDuplicateKey = Object.keys(localStorage).some(storageKey => { return storageKey.toLowerCase() === profileKey.toLowerCase(); }); // Allow overwrite if editing, otherwise enforce uniqueness if (!isEditing && isDuplicateKey) { alert('The key is already used in an existing entry (case-insensitive). Please use a different key.'); return; } localStorage.setItem(profileKey, formattedValue); // alert('Saved!'); keyInput.value = ''; // Clear the key input valueInput.value = ''; // Clear the value input isEditing = false; editingKey = ''; loadProfileEntries(); } else { alert('Please select a profile and enter a key.'); } }); function loadProfileEntries() { profileEntriesList.innerHTML = ''; profileEntriesList.style.display = 'flex'; profileEntriesList.style.flexDirection = 'column'; profileEntriesList.style.alignItems = 'center'; // Center children horizontally profileEntriesList.style.margin = '0 auto'; // Center the entire container const currentProfile = getCurrentProfile(); if (currentProfile) { Object.keys(localStorage).forEach(storageKey => { if (storageKey.startsWith(`${currentProfile}-lorebook:`)) { const entryKey = storageKey.replace(`${currentProfile}-lorebook:`, ''); const entryValue = localStorage.getItem(storageKey); const displayedValue = entryValue.replace(/^<\[Lorebook:.*?\]\s*/, '').replace(/>$/, ''); const entryItem = document.createElement('div'); entryItem.style.padding = '10px'; entryItem.style.marginBottom = '12px'; entryItem.style.borderRadius = '8px'; // entryItem.style.borderBottom = '0.5px solid #424242'; entryItem.style.backgroundColor = '#424242'; entryItem.style.position = 'relative'; entryItem.style.color = 'white'; entryItem.style.flexDirection = 'column'; entryItem.style.width = '90%'; const keyElement = document.createElement('div'); keyElement.innerText = entryKey; keyElement.style.fontWeight = 'bold'; keyElement.style.marginBottom = '10px'; entryItem.appendChild(keyElement); const valueElement = document.createElement('div'); valueElement.innerText = displayedValue; entryItem.appendChild(valueElement); entryItem.addEventListener('click', () => { keyInput.value = entryKey; valueInput.value = entryValue.replace(`<[Lorebook: ${entryKey}] `, '').replace('>', ''); isEditing = true; editingKey = entryKey; }); const removeButton = document.createElement('button'); removeButton.innerText = '✕'; removeButton.style.position = 'absolute'; removeButton.style.top = '10px'; removeButton.style.right = '10px'; removeButton.style.cursor = 'pointer'; removeButton.style.backgroundColor = 'transparent'; removeButton.style.color = 'white'; removeButton.addEventListener('click', () => { localStorage.removeItem(storageKey); loadProfileEntries(); }); entryItem.appendChild(removeButton); profileEntriesList.appendChild(entryItem); } }); } } // Utility functions to manage profiles and local storage function getCurrentProfile() { return localStorage.getItem('currentProfile'); } function setCurrentProfile(profileName) { localStorage.setItem('currentProfile', profileName); } // Initial load loadProfiles(); })();