Discord/Shapes - Main Logic

Handling the logic of Rules and Lorebook

目前为 2024-11-24 提交的版本。查看 最新版本

// ==UserScript==
// @name         Discord/Shapes - Main Logic
// @namespace    http://tampermonkey.net/
// @version      1.5
// @description  Handling the logic of Rules and Lorebook
// @author       Vishanka
// @match        https://discord.com/channels/*
// @grant        unsafeWindow
// @run-at document-idle
// ==/UserScript==

(function() {
    'use strict';

    // Function to check localStorage and reload if not ready
    function checkLocalStorageAndReload() {
        try {
            if (localStorage.length > 0) {
                console.log("LocalStorage has items. Proceeding with script...");
                initializeScript();
            } else {
                console.warn("LocalStorage is empty. Reloading page...");
                setTimeout(() => {
                    location.reload();
                }, 5000); // Wait 5 seconds before reloading
            }
        } catch (error) {
            console.error("Error accessing localStorage:", error);
            setTimeout(() => {
                location.reload();
            }, 5000); // Wait 5 seconds before reloading
        }
    }

    // Initial check for localStorage existence
    checkLocalStorageAndReload();

    function initializeScript() {
        // Retrieve settings from localStorage or set default values
        let enterKeyDisabled = JSON.parse(localStorage.getItem('enterKeyDisabled')) || false;
        let customRuleEnabled = JSON.parse(localStorage.getItem('customRuleEnabled')) || true;
        let scanForKeywordsEnabled = JSON.parse(localStorage.getItem('scanForKeywordsEnabled')) || true;

        // Create and add the UI button
 /*       window.uiButton = document.createElement('button');
        uiButton.innerHTML = 'Toggle Settings';
 //       uiButton.style.position = 'fixed';
        uiButton.style.bottom = '20px';
        uiButton.style.right = '20px';
        uiButton.style.zIndex = '1000';
        uiButton.style.padding = '10px';
        uiButton.style.backgroundColor = '#5865F2';
        uiButton.style.color = 'white';
        uiButton.style.border = 'none';
        uiButton.style.borderRadius = '5px';
        uiButton.style.cursor = 'pointer';

  //      document.body.appendChild(uiButton);
*/
        // Create the settings window
        unsafeWindow.settingsWindow = document.createElement('div');
   //     settingsWindow.style.position = 'fixed';
        settingsWindow.style.bottom = '60px';
        settingsWindow.style.right = '20px';
        settingsWindow.style.width = '250px';
        settingsWindow.style.padding = '15px';
 //       settingsWindow.style.backgroundColor = '#2f3136';
        settingsWindow.style.color = 'white';
//        settingsWindow.style.border = '1px solid #5865F2';
        settingsWindow.style.borderRadius = '5px';
  //      settingsWindow.style.display = 'none';
        settingsWindow.style.zIndex = '1001';
DCstoragePanel.appendChild(settingsWindow);
        // Custom Rule Checkbox
        const enableCustomRuleCheckbox = document.createElement('input');
        enableCustomRuleCheckbox.type = 'checkbox';
        enableCustomRuleCheckbox.checked = customRuleEnabled;
        enableCustomRuleCheckbox.id = 'enableCustomRuleCheckbox';

        const enableCustomRuleLabel = document.createElement('label');
        enableCustomRuleLabel.htmlFor = 'enableCustomRuleCheckbox';
        enableCustomRuleLabel.innerText = ' Enable Custom Rules';

        // Scan for Keywords Checkbox
        const enableScanForKeywordsCheckbox = document.createElement('input');
        enableScanForKeywordsCheckbox.type = 'checkbox';
        enableScanForKeywordsCheckbox.checked = scanForKeywordsEnabled;
        enableScanForKeywordsCheckbox.id = 'enableScanForKeywordsCheckbox';

        const enableScanForKeywordsLabel = document.createElement('label');
        enableScanForKeywordsLabel.htmlFor = 'enableScanForKeywordsCheckbox';
        enableScanForKeywordsLabel.innerText = ' Enable Lorebook';

        // Append elements to settings window
        settingsWindow.appendChild(enableCustomRuleCheckbox);
        settingsWindow.appendChild(enableCustomRuleLabel);
        settingsWindow.appendChild(document.createElement('br'));
        settingsWindow.appendChild(enableScanForKeywordsCheckbox);
        settingsWindow.appendChild(enableScanForKeywordsLabel);
  //      document.body.appendChild(settingsWindow);

        // Event listener to open/close settings window
/*        uiButton.addEventListener('click', function() {
            settingsWindow.style.display = settingsWindow.style.display === 'none' ? 'block' : 'none';
        });
*/
        // Update customRuleEnabled when checkbox is toggled, and save it in localStorage
        enableCustomRuleCheckbox.addEventListener('change', function() {
            customRuleEnabled = enableCustomRuleCheckbox.checked;
            localStorage.setItem('customRuleEnabled', JSON.stringify(customRuleEnabled));
        });

        // Update scanForKeywordsEnabled when checkbox is toggled, and save it in localStorage
        enableScanForKeywordsCheckbox.addEventListener('change', function() {
            scanForKeywordsEnabled = enableScanForKeywordsCheckbox.checked;
            localStorage.setItem('scanForKeywordsEnabled', JSON.stringify(scanForKeywordsEnabled));
        });

        // Add event listener to handle Enter key behavior
        window.addEventListener('keydown', function(event) {
            if (event.key === 'Enter' && !event.shiftKey && !enterKeyDisabled) {
                event.preventDefault();
                event.stopPropagation();
                event.stopImmediatePropagation();
                console.log('Enter key disabled');
                enterKeyDisabled = true;

                // Execute main handler for Enter key
                handleEnterKey();

                enterKeyDisabled = false;
            }
        }, true); // Use capture mode to intercept the event before Discord's handlers

        // Main function that handles Enter key behavior
        function handleEnterKey() {
            let inputElement = getInputElement();
            if (inputElement) {
                inputElement.focus();
                if (customRuleEnabled) {
                applyCustomRule(inputElement);
            }
                setCursorToEnd(inputElement);
                if (scanForKeywordsEnabled) {
                    scanForKeywords(inputElement);
                }
                sendMessage(inputElement);
                anotherCustomFunction();
            }
        }



// Function to get the correct input element based on the mode
function getInputElement() {
    return document.querySelector('[data-slate-editor="true"]') || document.querySelector('textarea[class*="textArea_"]');
}

// Function to apply custom rules for the input field
function applyCustomRule(inputElement) {
    const customRule = unsafeWindow.customRuleLogic ? unsafeWindow.customRuleLogic.getCurrentText() : '';

    if (inputElement.nodeName === 'TEXTAREA') {
        // For mobile version where input is <textarea>
        const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
        nativeInputValueSetter.call(inputElement, inputElement.value + customRule);

        const inputEvent = new Event('input', {
            bubbles: true,
            cancelable: true,
        });
        inputElement.dispatchEvent(inputEvent);
    } else {
        // For desktop version where input is a Slate editor
        const inputEvent = new InputEvent('beforeinput', {
            bubbles: true,
            cancelable: true,
            inputType: 'insertText',
            data: customRule,
        });
        inputElement.dispatchEvent(inputEvent);
    }
}

// Function to set the cursor position to the end after inserting the text
function setCursorToEnd(inputElement) {
    if (inputElement.nodeName === 'TEXTAREA') {
        inputElement.selectionStart = inputElement.selectionEnd = inputElement.value.length;
    } else {
        const range = document.createRange();
        range.selectNodeContents(inputElement);
        range.collapse(false);
        const selection = window.getSelection();
        selection.removeAllRanges();
        selection.addRange(range);
    }
}

// Function to send the message (either click send button or simulate Enter key)
function sendMessage(inputElement) {
    let sendButton = document.querySelector('button[aria-label="Nachricht senden"]');
    if (sendButton) {
        sendButton.click();
        console.log('Send button clicked to send message');
    } else {
        // For desktop version, simulate pressing Enter to send the message
        let enterEvent = new KeyboardEvent('keydown', {
            key: 'Enter',
            code: 'Enter',
            keyCode: 13,
            which: 13,
            bubbles: true,
            cancelable: true
        });
        inputElement.dispatchEvent(enterEvent);
        console.log('Enter key simulated to send message');
    }
}

// Example of adding another function
function anotherCustomFunction() {
    console.log('Another custom function executed');
}


// Function to scan for keywords and access local storage
function scanForKeywords(inputElement) {
    const currentProfile = getCurrentProfile();
    if (currentProfile) {
        // Retrieve all messages before iterating through storage keys
        const messageItems = document.querySelectorAll('div[class*="messageContent_"]');
        const relevantMessages = Array.from(messageItems).slice(-15); // Messages -5 to -1
        const lastMessage = Array.from(messageItems).slice(-1); // Last message only

        // Log the messages for debugging purposes even if no keyword is matched
        console.log("Relevant Messages (last 5):", relevantMessages.map(msg => msg.textContent));
        console.log("Last Message:", lastMessage.map(msg => msg.textContent));

        // Iterate through all localStorage keys that match the profile-lorebook prefix
        Object.keys(localStorage).forEach(storageKey => {
            if (storageKey.startsWith(`${currentProfile}-lorebook:`)) {
                const entryKeys = storageKey.replace(`${currentProfile}-lorebook:`, '').split(',');
                const entryValue = localStorage.getItem(storageKey);

                // Log the entry keys for debugging purposes
                console.log(`Entry Keys: `, entryKeys);

                entryKeys.forEach(entryKey => {
                    // Check input element text for complete word match of keyword
                    const inputText = inputElement.value || inputElement.textContent;

                    // Combine check for keyword in input or in the last message
                    const isKeywordInInput = inputText && new RegExp(`\\b${entryKey}\\b`).test(inputText);
                    const isKeywordInLastMessage = lastMessage.some(message => {
                        const lastMessageText = message.textContent;
                        return new RegExp(`\\b${entryKey}\\b`).test(lastMessageText);
                    });

                    if (isKeywordInInput || isKeywordInLastMessage) {
                        const keywordAlreadyUsed = relevantMessages.some(message => {
                            const messageText = message.textContent;
                            const bracketContent = messageText.match(/\[(.*?)\]/);

                            return bracketContent ? new RegExp(`\\b${entryKey}\\b`).test(bracketContent[1]) : false;
                        });

                        if (!keywordAlreadyUsed) {
                            // Append the entryValue to the input element
                            if (inputElement.nodeName === 'TEXTAREA') {
                                const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
                                nativeInputValueSetter.call(inputElement, inputElement.value + '\n' + entryValue);

                                const inputEvent = new Event('input', {
                                    bubbles: true,
                                    cancelable: true,
                                });
                                inputElement.dispatchEvent(inputEvent);
                            } else {
                                const inputEvent = new InputEvent('beforeinput', {
                                    bubbles: true,
                                    cancelable: true,
                                    inputType: 'insertText',
                                    data: '\n' + entryValue,
                                });
                                inputElement.dispatchEvent(inputEvent);
                            }
                            console.log(`Keyword '${entryKey}' detected. Appended lorebook entry to the input.`);
                        } else {
                            console.log(`Keyword '${entryKey}' already found in recent bracketed messages. Skipping append.`);
                        }
                    }
                });
            }
        });
    }
}

// Function to get the current profile from local storage
function getCurrentProfile() {
    return localStorage.getItem('currentProfile');
}



  }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址