Discord/Shapes Tools

Various Functions for Shapes.inc for Discord

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

// ==UserScript==
// @name         Discord/Shapes Tools
// @namespace    https://vishanka.com
// @version      1.1
// @description  Various Functions for Shapes.inc for Discord
// @author       Vishanka
// @match        https://discord.com/channels/*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @license      Proprietary
// @run-at document-idle
// ==/UserScript==


(function() {
    'use strict';

// ================================================================== LOREBOOK ==================================================================
function LorebookScript(){

// Create and add the arrow button to open the storage panel
const arrowButton = document.createElement('div');
arrowButton.innerHTML = '〈';
arrowButton.style.position = 'fixed';
arrowButton.style.bottom = '50%';
arrowButton.style.right = '0';
arrowButton.style.padding = '10px';
arrowButton.style.fontSize = '24px';
arrowButton.style.zIndex = '1000';
arrowButton.style.cursor = 'pointer';
arrowButton.style.color = '#B4B4B4';
arrowButton.style.borderRadius = '5px 0 0 5px';
arrowButton.style.transition = 'transform 0.3s ease, right 0.3s ease, background-color 0.1s';

// Toggle panel visibility
arrowButton.addEventListener('click', () => {
  if (DCstoragePanel.style.right === '-250px') {
    DCstoragePanel.style.right = '0';
    arrowButton.style.right = '250px';
    arrowButton.style.transform = 'rotate(180deg)';
  } else {
    DCstoragePanel.style.right = '-250px';
    arrowButton.style.right = '0';
    arrowButton.style.transform = 'rotate(0deg)';
  }
});

// Create the fancy sliding panel
window.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';
DCstoragePanel.style.transition = 'right 0.3s ease';
DCstoragePanel.style.zIndex = '999';

// 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';

// Create a divider line
const dividerLine = document.createElement('div');
dividerLine.style.height = '1px';
dividerLine.style.backgroundColor = '#212121';
dividerLine.style.margin = '10px 20px';

// Manage Lorebook Button
window.openLorebookButton = document.createElement('div');
window.openLorebookButton.innerHTML = `
    <button id="toggle-lorebook-panel"
        style="
            position: relative;
            top: 10px;
            right: 0px;
            left: 10px;
            padding: 7px 15px;


            background: transparent;
            color: #b0b0b0;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            text-align: center;
            cursor: pointer;
            width: 90%;
            transition: background-color 0.1s, color 0.1s;
            z-index: 1001;">
        Manage Lorebook
    </button>
`;

const lorebookButtonElement = openLorebookButton.querySelector('button');
lorebookButtonElement.onmouseover = () => {
    lorebookButtonElement.style.backgroundColor = '#212121';
    lorebookButtonElement.style.color = '#ffffff';
};
lorebookButtonElement.onmouseout = () => {
    lorebookButtonElement.style.backgroundColor = 'transparent';
    lorebookButtonElement.style.color = '#b0b0b0';
};

// Create the main panel container
const lorebookPanel = document.createElement('div');
lorebookPanel.id = 'lorebookManagerPanel';
lorebookPanel.style.position = 'fixed';
lorebookPanel.style.top = '50%';
lorebookPanel.style.left = '50%';
lorebookPanel.style.transform = 'translate(-50%, -50%)';
// Size different for Mobile and Desktop
if (window.innerWidth <= 768) {
    lorebookPanel.style.width = '90%';
    lorebookPanel.style.height = '90%';
} else {
    lorebookPanel.style.width = '800px';
    lorebookPanel.style.height = '700px';
}
lorebookPanel.style.backgroundColor = '#2F2F2F';
lorebookPanel.style.borderRadius = '20px';
lorebookPanel.style.padding = '10px';
lorebookPanel.style.display = 'none';
lorebookPanel.style.zIndex = '1000';

// 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';

closeButton.addEventListener('mouseenter', () => {
    closeButton.style.backgroundColor = '#676767';
});
closeButton.addEventListener('mouseleave', () => {
    closeButton.style.backgroundColor = 'transparent';
});

// Hide the Lorebook Panel
closeButton.addEventListener('click', () => {
    lorebookPanel.style.display = 'none';
});

// Open the Lorebook Panel
openLorebookButton.addEventListener('click', () => {
    lorebookPanel.style.display = lorebookPanel.style.display === 'none' ? 'block' : 'none';
    loadProfileEntries();
});

// Profiles Title
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';

// Profile Management Panel
const lorebookProfilePanel = document.createElement('div');
lorebookProfilePanel.id = 'lorebookProfilePanel';
lorebookProfilePanel.style.float = 'left';
lorebookProfilePanel.style.width = '20%';
lorebookProfilePanel.style.borderRight = '0.5px solid #444444';
lorebookProfilePanel.style.height = '93%';

// 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';

// Add Profiles 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';

// Mouseover Effect for Add Profiles Button
addProfileButton.onmouseover = () => {
    addProfileButton.style.backgroundColor = '#424242';
};
addProfileButton.onmouseout = () => {
    addProfileButton.style.backgroundColor = 'transparent';
};

addProfileButton.addEventListener('click', () => {
    const profileName = prompt('Enter profile name:');
    if (profileName) {
        const profileKey = `lorebook.profile:${profileName}`;

        // Create a list of keys from localStorage that match the prefix 'lorebook.profile:'
        const existingKeys = Object.keys(localStorage)
            .filter(key => key.startsWith('lorebook.profile:'))
            .map(key => key.toLowerCase()); // Convert all keys to lowercase for case-insensitive check

        if (!existingKeys.includes(profileKey.toLowerCase())) {
            localStorage.setItem(profileKey, JSON.stringify({}));
            loadProfiles();
        } else {
            alert('Profile already exists.');
        }
    }
});


// Profile Selection Functionality
function loadProfiles() {
    profileList.innerHTML = '';
        Object.keys(localStorage).forEach(profileKey => {
            if (profileKey.startsWith('lorebook.profile:')) {
                const profileName = profileKey.replace('lorebook.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);
            }
        });
}

// Lorebook Entries Title
const lorebookEntriesTitle = document.createElement('h3');
lorebookEntriesTitle.innerText = 'Manage Lorebook Entries';
lorebookEntriesTitle.style.fontWeight = 'normal';
lorebookEntriesTitle.style.color = '#ffffff';
lorebookEntriesTitle.style.textAlign = 'left';
lorebookEntriesTitle.style.fontSize = '24px';
lorebookEntriesTitle.style.marginTop = '20px';
lorebookEntriesTitle.style.position = 'relative';
lorebookEntriesTitle.style.marginLeft = '23%';
lorebookEntriesTitle.style.marginBottom = '15px';
lorebookEntriesTitle.style.fontWeight = '550';

// 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) {
    profileEntriesList.style.height = '30%';
} else {
    profileEntriesList.style.height = '48%';
}
profileEntriesList.style.overflowY = 'auto';

// Header for Inputs
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%';

// 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';
inputContainer.style.margin = '0 auto';


const lorebookKeyInput = document.createElement('input');
lorebookKeyInput.type = 'text';
lorebookKeyInput.placeholder = 'Entry Keywords (comma-separated)';
lorebookKeyInput.style.width = '90%';
lorebookKeyInput.style.marginBottom = '5px';
lorebookKeyInput.style.padding = '10px';
lorebookKeyInput.style.border = '1px solid #444444';
lorebookKeyInput.style.borderRadius = '8px';
lorebookKeyInput.style.backgroundColor = '#1e1e1e';
lorebookKeyInput.style.color = '#dddddd';


const lorebookValueInput = document.createElement('textarea');
lorebookValueInput.placeholder = ' ';
lorebookValueInput.style.width = '90%';
lorebookValueInput.style.marginBottom = '5px';
lorebookValueInput.style.padding = '10px';
lorebookValueInput.style.border = '1px solid #444444';
lorebookValueInput.style.borderRadius = '8px';
lorebookValueInput.style.backgroundColor = '#1e1e1e';
lorebookValueInput.style.color = '#dddddd';
lorebookValueInput.style.height = '100px';
lorebookValueInput.style.resize = 'vertical';
lorebookValueInput.maxLength = 1000;
lorebookValueInput.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/${lorebookValueInput.maxLength}`;

// Update the counter as the user types
lorebookValueInput.addEventListener('input', () => {
  charCounter.textContent = `${lorebookValueInput.value.length}/${lorebookValueInput.maxLength}`;
});

// Save Entry button, also important for editing
const lorebookSaveButton = document.createElement('button');
lorebookSaveButton.innerText = 'Add Entry';
lorebookSaveButton.style.padding = '10px 20px';
lorebookSaveButton.style.border = '0.2px solid #4E4E4E';
lorebookSaveButton.style.backgroundColor = '#2F2F2F';
lorebookSaveButton.style.color = '#fff';
lorebookSaveButton.style.borderRadius = '50px';
lorebookSaveButton.style.cursor = 'pointer';
lorebookSaveButton.style.width = '95%';

// Append all Elements
document.body.appendChild(arrowButton);
document.body.appendChild(DCstoragePanel);
DCstoragePanel.appendChild(storagePanelHeader);
DCstoragePanel.appendChild(dividerLine);
document.body.appendChild(lorebookPanel);
lorebookPanel.appendChild(closeButton);
lorebookPanel.appendChild(profileslabel);
lorebookPanel.appendChild(lorebookProfilePanel);
lorebookProfilePanel.appendChild(profileList);
lorebookProfilePanel.appendChild(addProfileButton);
lorebookPanel.appendChild(lorebookEntriesTitle);
lorebookPanel.appendChild(profileEntriesList);
lorebookPanel.appendChild(entrieslabel);
lorebookPanel.appendChild(inputContainer);
inputContainer.appendChild(lorebookKeyInput);
inputContainer.appendChild(lorebookValueInput);
inputContainer.appendChild(charCounter);
inputContainer.appendChild(lorebookSaveButton);

let isEditing = false;
let editingKey = '';

lorebookSaveButton.addEventListener('click', () => {
    const key = lorebookKeyInput.value.trim().toLowerCase(); // Ensure key is always saved as lowercase
    const value = lorebookValueInput.value;
    const currentProfile = getCurrentProfile();

    if (key && currentProfile) {
        const profileKey = `${currentProfile}.lorebook:${key}`;
        const formattedValue = `<[Lorebook: ${key}] ${value}>`;

        // Check for duplicate keys (case-insensitive) and prevent keys that partially match an existing key
        const isDuplicateKey = Object.keys(localStorage).some(storageKey => {
            const normalizedStorageKey = storageKey.toLowerCase();
            const normalizedCurrentProfile = currentProfile.toLowerCase();
            const currentKey = normalizedStorageKey.replace(`${normalizedCurrentProfile}.lorebook:`.toLowerCase(), '');
            return (
                (currentKey === key || currentKey.split(',').includes(key)) &&
                (!isEditing || editingKey.toLowerCase() !== currentKey)
            );
        });

        // Enforce uniqueness for edits as well
        if (isDuplicateKey) {
            alert('The key is already used in an existing entry (case-insensitive). Please use a different key.');
            return;
        }

        // Remove the old key if editing and key has changed
        if (isEditing && editingKey.toLowerCase() !== key) {
            const oldProfileKey = `${currentProfile}.lorebook:${editingKey.toLowerCase()}`;
            localStorage.removeItem(oldProfileKey);
        }

        localStorage.setItem(profileKey, formattedValue);
        lorebookKeyInput.value = '';
        lorebookValueInput.value = '';
        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';
    profileEntriesList.style.margin = '0 auto';

    const currentProfile = getCurrentProfile();
    if (currentProfile) {
        Object.keys(localStorage).forEach(storageKey => {
            // Normalize both the profile and the storage key for case-insensitive comparison
            if (storageKey.toLowerCase().startsWith(`${currentProfile.toLowerCase()}.lorebook:`)) {
                const entryKey = storageKey.replace(new RegExp(`^${currentProfile}\.lorebook:`, 'i'), '');
                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.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', () => {
                    lorebookKeyInput.value = entryKey;
                    lorebookValueInput.value = entryValue.replace(/^<\[Lorebook:.*?\]\s*/, '').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', (event) => {
                    event.stopPropagation();
                    localStorage.removeItem(storageKey);
                    loadProfileEntries();
                });

                entryItem.appendChild(removeButton);
                profileEntriesList.appendChild(entryItem);
            }
        });
    }
}

// Utility functions to manage profiles and local storage
function getCurrentProfile() {
    // Return the current profile name in its original case, but convert to lower case for comparisons
    const selectedProfile = localStorage.getItem('selectedProfile.lorebook');
    return selectedProfile ? selectedProfile : null;
}

function setCurrentProfile(profileName) {
    localStorage.setItem('selectedProfile.lorebook', profileName);
}

loadProfiles();

}

// ================================================================ IMPORT/EXPORT ===============================================================
function ImportExportScript() {
// Create buttons to trigger export and import
window.exportButton = document.createElement('div');
exportButton.innerHTML = `
  <div style="display: flex; align-items: center; justify-content: center;">
    <button style="margin-top: 20px; margin-left: 4px; margin-right: 5px; padding: 7px 51px; font-size: 16px; cursor: pointer; background-color: transparent; color: #b0b0b0; border-radius: 8px; text-align: center; transition: background-color 0.1s, color 0.1s;">Export localStorage</button>
  </div>
`;

window.exportButton.onmouseover = () => {
  exportButton.querySelector('button').style.backgroundColor = '#212121';
  exportButton.querySelector('button').style.color = '#ffffff';
};
exportButton.onmouseout = () => {
  exportButton.querySelector('button').style.backgroundColor = 'transparent';
  exportButton.querySelector('button').style.color = '#b0b0b0';
};
//DCstoragePanel.appendChild(exportButton);

window.importButton = document.createElement('div');
importButton.innerHTML = `
  <div style="display: flex; align-items: center; justify-content: center;">
    <button style="margin-top: 20px; margin-left: 4px; margin-right: 5px; padding: 7px 50px; font-size: 16px; cursor: pointer; background-color: transparent; color: #b0b0b0; border-radius: 8px; text-align: center; transition: background-color 0.1s, color 0.1s;">Import localStorage</button>
  </div>
`;

importButton.onmouseover = () => {
  importButton.querySelector('button').style.backgroundColor = '#212121';
  importButton.querySelector('button').style.color = '#ffffff';
};
importButton.onmouseout = () => {
  importButton.querySelector('button').style.backgroundColor = 'transparent';
  importButton.querySelector('button').style.color = '#b0b0b0';
};
//DCstoragePanel.appendChild(importButton);

    // Export specific localStorage entries
    exportButton.addEventListener('click', () => {
        const filteredData = {};
        for (const key in localStorage) {
            if (localStorage.hasOwnProperty(key)) {
                if (key.startsWith('events') || key.includes('lorebook')) {
                    filteredData[key] = localStorage.getItem(key);
                }
            }
        }
        const data = JSON.stringify(filteredData);
        const blob = new Blob([data], {type: 'application/json'});
        const url = URL.createObjectURL(blob);

        const a = document.createElement('a');
        a.href = url;
        a.download = 'localStorage_filtered.json';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    });

    // Import localStorage
    importButton.addEventListener('click', () => {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = 'application/json';
        input.addEventListener('change', (event) => {
            const file = event.target.files[0];
            if (!file) {
                return;
            }

            const reader = new FileReader();
            reader.onload = (e) => {
                try {
                    const importedData = JSON.parse(e.target.result);
                    for (const key in importedData) {
                        localStorage.setItem(key, importedData[key]);
                    }
                    alert('localStorage has been successfully imported.');
                } catch (err) {
                    alert('Failed to import localStorage: ' + err.message);
                }
            };
            reader.readAsText(file);
        });
        input.click();
    });
    }

// =================================================================== EVENTS ===================================================================
function EventsScript() {

window.eventsButton = document.createElement('div');
window.eventsButton.innerHTML = `
    <button id="toggle-events-panel"
        style="
            position: relative;
            top: 10px;
            right: 0px;
            left: 10px;
            padding: 7px 15px;


            background: transparent;
            color: #b0b0b0;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            text-align: center;
            cursor: pointer;
            width: 90%;
            transition: background-color 0.1s, color 0.1s;
            z-index: 1001;">
        Manage Events
    </button>
`;

let manageEventsButton = window.eventsButton.querySelector('#toggle-events-panel');
manageEventsButton.onclick = openProfilePanel;

const eventsbuttonElement = eventsButton.querySelector('button');
eventsbuttonElement.onmouseover = () => {
    eventsbuttonElement.style.backgroundColor = '#212121';
    eventsbuttonElement.style.color = '#ffffff';
};
eventsbuttonElement.onmouseout = () => {
    eventsbuttonElement.style.backgroundColor = 'transparent';
    eventsbuttonElement.style.color = '#b0b0b0';
};

function openProfilePanel() {

    if (document.querySelector('#eventsProfilePanel')) {
        return;
    }

// Create profile management panel
const eventsProfilePanel = document.createElement('div');
eventsProfilePanel.id = 'eventsProfilePanel';
eventsProfilePanel.style.position = 'fixed';
eventsProfilePanel.style.top = '50%';
eventsProfilePanel.style.left = '50%';
eventsProfilePanel.style.transform = 'translate(-50%, -50%)';
// Size different for Mobile and Desktop
if (window.innerWidth <= 768) {
    eventsProfilePanel.style.width = '90%';
    eventsProfilePanel.style.height = '90%';
} else {
    eventsProfilePanel.style.width = '800px';
    eventsProfilePanel.style.height = '700px';
}
//eventsProfilePanel.style.width = '800px';
//eventsProfilePanel.style.height = '700px';
eventsProfilePanel.style.backgroundColor = '#2F2F2F';
eventsProfilePanel.style.color = 'white';
eventsProfilePanel.style.borderRadius = '20px';
eventsProfilePanel.style.padding = '20px';
eventsProfilePanel.style.zIndex = '1000';
eventsProfilePanel.style.display = 'flex';
eventsProfilePanel.style.flexDirection = 'row';

// Create close button for profilePanel
const closeButton = document.createElement('button');
closeButton.style.position = 'absolute';
closeButton.style.top = '15px';
closeButton.style.right = '15px';
closeButton.style.width = '30px';
closeButton.style.height = '30px';
closeButton.style.backgroundColor = 'transparent';
closeButton.style.color = '#ffffff';
closeButton.style.border = 'none';
closeButton.style.borderRadius = '50%';
closeButton.style.cursor = 'pointer';
closeButton.style.display = 'flex';
closeButton.style.alignItems = 'center';
closeButton.style.zIndex = '1001';
closeButton.style.justifyContent = 'center';
closeButton.style.transition = 'background-color 0.2s ease';
closeButton.style.boxSizing = 'border-box';

// Create span for the '✕' character
const closeIcon = document.createElement('span');
closeIcon.innerText = '✕';
closeIcon.style.fontSize = '16px';
closeIcon.style.position = 'relative';
closeIcon.style.top = '-1px';

// Hover effect
closeButton.addEventListener('mouseenter', () => {
    closeButton.style.backgroundColor = '#676767';
});

closeButton.addEventListener('mouseleave', () => {
    closeButton.style.backgroundColor = 'transparent';
});

// Close button action
closeButton.onclick = function() {
    document.body.removeChild(eventsProfilePanel);
};

// Create profile list container
const profileListContainer = document.createElement('div');
profileListContainer.style.flex = '0.50';
profileListContainer.style.marginRight = '20px';
profileListContainer.style.paddingRight = '20px';
profileListContainer.style.display = 'flex';
profileListContainer.style.flexDirection = 'column';
profileListContainer.style.borderRight = '1px solid #444444';
profileListContainer.style.overflowY = 'auto';
profileListContainer.style.maxHeight = '660px';

// Create header for profile list
const profileListHeader = document.createElement('h4');
profileListHeader.innerText = 'Profiles';
profileListHeader.style.marginBottom = '10px';

// Create profile list
const profileList = document.createElement('ul');
profileList.style.overflowY = 'auto';
profileList.style.height = '600px';


// Create button to add profile
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.cursor = 'pointer';

addProfileButton.onmouseover = () => {
    addProfileButton.style.backgroundColor = '#424242';
};
addProfileButton.onmouseout = () => {
    addProfileButton.style.backgroundColor = 'transparent';
};
addProfileButton.onclick = function() {
    openAddProfileDialog();
};

// Create key-value input container
const keyValueContainer = document.createElement('div');
keyValueContainer.style.flex = '2.3';
keyValueContainer.style.display = 'flex';
keyValueContainer.style.flexDirection = 'column';
keyValueContainer.style.gap = '10px';

// Create entries list
const entriesList = document.createElement('div');
entriesList.style.overflowY = 'auto';
entriesList.style.height = '340px';
entriesList.style.width = '100%';
entriesList.style.paddingRight = '20px';
entriesList.style.borderCollapse = 'collapse';
entriesList.style.display = 'block';
entriesList.style.overflowY = 'auto';

// Create a header above the headerRow
const manageEventsHeader = document.createElement('h2');
manageEventsHeader.innerText = 'Manage Event List';
manageEventsHeader.style.marginBottom = '-10px';

closeButton.appendChild(closeIcon);
eventsProfilePanel.appendChild(closeButton);
profileListContainer.appendChild(profileListHeader);
profileListContainer.appendChild(profileList);
profileListContainer.appendChild(addProfileButton);
keyValueContainer.appendChild(manageEventsHeader);

// Create table header
const headerRow = document.createElement('tr');
const headers = ['Key', 'Value', '%', 'Time', ''];
headers.forEach(headerText => {
    const header = document.createElement('th');
    header.innerText = headerText;
    header.style.padding = '5px';
    header.style.textAlign = 'left';
        if (headerText === 'Value') {
            header.style.width = '60%';
        } else if (headerText === 'Key') {
            header.style.width = '15%';
        } else if (headerText === '%' || headerText === 'Time') {
            header.style.width = '10%';
        } else if (headerText === '') {
            header.style.width = '5%';
        }
    headerRow.appendChild(header);
});

const headerContainer = document.createElement('div');
headerContainer.style.position = 'sticky';
headerContainer.style.top = '0';
headerContainer.style.backgroundColor = '#2F2F2F';
headerContainer.style.zIndex = '1';
headerContainer.appendChild(headerRow);
entriesList.appendChild(headerContainer);
entriesList.style.position = 'sticky';
entriesList.style.top = '0';
entriesList.style.backgroundColor = '#2F2F2F';
// Create a separate header for the entries list
const entriesHeaderContainer = document.createElement('div');
entriesHeaderContainer.style.position = 'sticky';
entriesHeaderContainer.style.top = '0';
entriesHeaderContainer.style.backgroundColor = '#2F2F2F';
entriesHeaderContainer.style.zIndex = '1';
const entriesHeader = document.createElement('div');
entriesHeader.style.display = 'flex';
entriesHeader.style.padding = '5px 0';
entriesHeader.style.borderBottom = '1px solid #444444';
headers.forEach(headerText => {
  const header = document.createElement('div');
  header.innerText = headerText;
  header.style.padding = '5px';
  header.style.textAlign = 'left'; // Align headers to the left
    if (headerText === 'Value') {
        header.style.width = '57%';
    } else if (headerText === 'Key') {
        header.style.width = '15%';
    } else if (headerText === '%' || headerText === 'Time') {
        header.style.width = '7%';
    } else if (headerText === '') {
        header.style.width = '5%';
    }
  entriesHeader.appendChild(header);
});
entriesHeaderContainer.appendChild(entriesHeader);
keyValueContainer.appendChild(entriesHeaderContainer);
keyValueContainer.appendChild(entriesList);

// Create container for probability and time range inputs
const probTimeContainer = document.createElement('div');
probTimeContainer.style.display = 'flex';
probTimeContainer.style.gap = '10px';
probTimeContainer.style.marginBottom = '-4px';

// Create probability label and input
const probabilityContainer = document.createElement('div');
probabilityContainer.style.display = 'flex';
probabilityContainer.style.flexDirection = 'column';
probabilityContainer.style.width = '30%'; // Adjust width to fit the row better

const probabilityLabel = document.createElement('div');
probabilityLabel.innerText = 'Event Probability';
probabilityLabel.style.color = 'white';
probabilityLabel.style.marginBottom = '0px';
probabilityContainer.appendChild(probabilityLabel);

const probabilityInputContainer = document.createElement('div');
probabilityInputContainer.style.display = 'flex';
probabilityInputContainer.style.alignItems = 'center';

const probabilityInput = document.createElement('input');
probabilityInput.type = 'number';
probabilityInput.placeholder = '0-100';
probabilityInput.style.backgroundColor = '#1E1E1E';
probabilityInput.style.color = 'white';
probabilityInput.style.border = '1px solid #444444';
probabilityInput.style.borderRadius = '5px';
probabilityInput.style.padding = '5px';
probabilityInput.style.width = '85%';
probabilityInput.style.marginRight = '5px';
probabilityInputContainer.appendChild(probabilityInput);

const probabilityPercentLabel = document.createElement('span');
probabilityPercentLabel.innerText = '%';
probabilityPercentLabel.style.color = 'white';
probabilityInputContainer.appendChild(probabilityPercentLabel);

probabilityContainer.appendChild(probabilityInputContainer);
probTimeContainer.appendChild(probabilityContainer);

// Create time range label and input
const timeRangeContainer = document.createElement('div');
timeRangeContainer.style.display = 'flex';
timeRangeContainer.style.flexDirection = 'column';
timeRangeContainer.style.width = '30%'; // Adjust width to fit the row better

const timeRangeLabel = document.createElement('div');
timeRangeLabel.innerText = 'Time Range';
timeRangeLabel.style.color = 'white';
timeRangeLabel.style.marginBottom = '0px';
timeRangeContainer.appendChild(timeRangeLabel);

const timeRangeInputContainer = document.createElement('div');
timeRangeInputContainer.style.display = 'flex';
timeRangeInputContainer.style.alignItems = 'center';

const timeRangeInput = document.createElement('input');
timeRangeInput.type = 'text';
timeRangeInput.placeholder = '0-24';
timeRangeInput.value = '0-24'; // Set default value

timeRangeInput.style.backgroundColor = '#1E1E1E';
timeRangeInput.style.color = 'white';
timeRangeInput.style.border = '1px solid #444444';
timeRangeInput.style.borderRadius = '5px';
timeRangeInput.style.padding = '5px';
timeRangeInput.style.width = '85%';
timeRangeInput.style.marginRight = '5px';

timeRangeInput.addEventListener('blur', () => {
    const timeValue = timeRangeInput.value.trim();
    const timeRegex = /^([0-9]|1[0-9]|2[0-3])-(?:[0-9]|1[0-9]|2[0-3])$/;
    if (!timeRegex.test(timeValue)) {
        alert('Please enter a valid time range between 0-23, e.g., "8-16" or "0-24". Defaulting to "0-24".');
        timeRangeInput.value = '0-24';
    }
});

timeRangeInputContainer.appendChild(timeRangeInput);

const timeRangeUnitLabel = document.createElement('span');
timeRangeUnitLabel.innerText = 'h';
timeRangeUnitLabel.style.color = 'white';
timeRangeInputContainer.appendChild(timeRangeUnitLabel);

timeRangeContainer.appendChild(timeRangeInputContainer);
probTimeContainer.appendChild(timeRangeContainer);

// Create overall probability label and input
const overallProbabilityContainer = document.createElement('div');
overallProbabilityContainer.style.display = 'flex';
overallProbabilityContainer.style.flexDirection = 'column';
overallProbabilityContainer.style.width = '30%'; // Adjust width to fit the row better

const overallProbabilityLabel = document.createElement('div');
overallProbabilityLabel.innerText = 'Overall Probability';
overallProbabilityLabel.style.color = 'white';
overallProbabilityLabel.style.marginBottom = '0px';
overallProbabilityContainer.appendChild(overallProbabilityLabel);

const overallProbabilityInputContainer = document.createElement('div');
overallProbabilityInputContainer.style.display = 'flex';
overallProbabilityInputContainer.style.alignItems = 'center';

const overallProbabilityInput = document.createElement('input');
overallProbabilityInput.type = 'number';
overallProbabilityInput.placeholder = '0-100';
overallProbabilityInput.style.backgroundColor = '#202530';
overallProbabilityInput.style.color = 'white';
overallProbabilityInput.style.border = '1px solid #444444';
overallProbabilityInput.style.borderRadius = '5px';
overallProbabilityInput.style.padding = '5px';
overallProbabilityInput.style.marginRight = '5px';
overallProbabilityInput.style.width = '85%';

// Load the existing overall probability value if set
const savedProbability = localStorage.getItem('events.probability');
if (savedProbability) {
    overallProbabilityInput.value = savedProbability;
}

// Add event listener to save the value to localStorage when changed
overallProbabilityInput.addEventListener('input', () => {
    const probabilityValue = overallProbabilityInput.value.trim();
    if (probabilityValue !== '' && probabilityValue >= 0 && probabilityValue <= 100) {
        localStorage.setItem('events.probability', probabilityValue);
    } else {
        alert('Please enter a valid probability between 0 and 100.');
    }
});

overallProbabilityInputContainer.appendChild(overallProbabilityInput);

const overallProbabilityPercentLabel = document.createElement('span');
overallProbabilityPercentLabel.innerText = '%';
overallProbabilityPercentLabel.style.color = 'white';
overallProbabilityInputContainer.appendChild(overallProbabilityPercentLabel);

overallProbabilityContainer.appendChild(overallProbabilityInputContainer);
probTimeContainer.appendChild(overallProbabilityContainer);

// Append probability and time range container to the main keyValue container
keyValueContainer.appendChild(probTimeContainer);

// Create input for key
const keyInput = document.createElement('input');
keyInput.type = 'text';
keyInput.placeholder = 'Enter key';
keyInput.style.backgroundColor = '#1E1E1E';
keyInput.style.color = 'white';
keyInput.style.border = '1px solid #444444';
keyInput.style.borderRadius = '5px';
keyInput.style.padding = '5px';
keyInput.style.marginBottom = '-4px';
keyValueContainer.appendChild(keyInput);

// Create input for value
const valueInput = document.createElement('textarea');
valueInput.placeholder = 'Enter value';
valueInput.style.backgroundColor = '#1E1E1E';
valueInput.style.color = 'white';
valueInput.style.border = '1px solid #444444';
valueInput.style.borderRadius = '5px';
valueInput.style.padding = '5px';
valueInput.style.height = '80px';
valueInput.style.overflowWrap = 'break-word';
valueInput.style.overflow = 'auto';
valueInput.style.marginBottom = '-4px';
keyValueContainer.appendChild(valueInput);


// Create button to add key-value pair
const addEntryButton = document.createElement('button');
addEntryButton.innerText = 'Add Entry';
    addEntryButton.innerText = 'Add Entry';
    addEntryButton.style.padding = '10px 20px';
    addEntryButton.style.border = '0.2px solid #4E4E4E';
    addEntryButton.style.backgroundColor = '#2F2F2F';
    addEntryButton.style.color = '#fff';
    addEntryButton.style.borderRadius = '50px';
    addEntryButton.style.cursor = 'pointer';

    addEntryButton.onmouseover = () => {
        addEntryButton.style.backgroundColor = '#424242';
    };
    addEntryButton.onmouseout = () => {
        addEntryButton.style.backgroundColor = 'transparent';
    };

// Adding Entries
let currentEditingKey = null; // This keeps track of the current key being edited

// Add or Edit Entry Button
addEntryButton.onclick = function () {
    if (!selectedProfile) {
        alert('Please select a profile before adding entries.');
        return;
    }

    const key = keyInput.value.trim();
    const value = `<Event: ${valueInput.value.trim()}>`;
    const probability = probabilityInput.value.trim();
    const timeRange = timeRangeInput.value.trim();
    const fullKey = `${selectedProfile}.events:${key}`;

    if (key && value) {
        // Check if we are editing an existing entry
        if (currentEditingKey) {
            // Check if we are attempting to edit to a key that already exists
            if (currentEditingKey !== fullKey && localStorage.getItem(fullKey)) {
                alert('An entry with this key already exists. Please use a different key.');
                return;
            }

            // Remove the old entry if the key has changed
            if (currentEditingKey !== fullKey) {
                localStorage.removeItem(currentEditingKey);
            }

            // Update or add the new entry
            const entryData = {
                value: value,
                probability: probability || '100',
                timeRange: timeRange || '0-24'
            };
            localStorage.setItem(fullKey, JSON.stringify(entryData));
            currentEditingKey = null; // Reset the editing key

        } else {
            // If adding a new entry
            if (!localStorage.getItem(fullKey)) {
                const entryData = {
                    value: value,
                    probability: probability || '100',
                    timeRange: timeRange || '0-24'
                };
                localStorage.setItem(fullKey, JSON.stringify(entryData));
            } else {
                alert('Entry with this key already exists. Please use a different key.');
                return;
            }
        }

        loadEntries();

        // Clear the input fields after adding/editing the entry
        keyInput.value = '';
        valueInput.value = '';
        probabilityInput.value = '100';
        timeRangeInput.value = '0-24';
    }
};
keyValueContainer.appendChild(addEntryButton);

// Append containers to profilePanel
eventsProfilePanel.appendChild(profileListContainer);
eventsProfilePanel.appendChild(keyValueContainer);



    // Load saved profiles and entries
    let selectedProfile = localStorage.getItem('selectedProfile.events');

    function loadProfiles() {
        profileList.innerHTML = '';
        for (let key in localStorage) {
            if (key.startsWith('events.profile:')) {
                const profileName = key.replace('events.profile:', '');
                const listItem = document.createElement('li');
                listItem.style.display = 'flex';
                listItem.style.alignItems = 'center';
                listItem.style.cursor = 'pointer';

                const nameSpan = document.createElement('span');
                nameSpan.innerText = profileName;
                nameSpan.style.flex = '1';
                listItem.appendChild(nameSpan);

                listItem.onclick = function() {
                    if (selectedProfile === profileName) {
                        selectedProfile = null;
                        localStorage.setItem('selectedProfile.events', '');
                        listItem.style.backgroundColor = '';
                        loadEntries();
                    } else {
                        selectedProfile = profileName;
                        localStorage.setItem('selectedProfile.events', selectedProfile);
                        loadEntries();
                        highlightSelectedProfile(listItem);
                    }
                };

                const deleteButton = document.createElement('button');
    //            deleteButton.innerText = 'x';
deleteButton.style.backgroundColor = 'transparent';
deleteButton.style.borderRadius = '50%';
deleteButton.style.marginLeft = '10px';
deleteButton.style.border = 'none';
deleteButton.style.color = '#ffffff';
deleteButton.style.cursor = 'pointer';
deleteButton.style.padding = '14px';
deleteButton.style.width = '15px';
deleteButton.style.height = '15px';
deleteButton.style.display = 'flex';
deleteButton.style.alignItems = 'center';
deleteButton.style.justifyContent = 'center';

deleteButton.style.transition = 'background-color 0.1s';

// Hover effect
deleteButton.addEventListener('mouseenter', () => {
//    closeButton.style.transform = 'scale(1.1)';
    deleteButton.style.backgroundColor = '#676767';
});

deleteButton.addEventListener('mouseleave', () => {
//    closeButton.style.transform = 'scale(1)';
    deleteButton.style.backgroundColor = 'transparent';
});



const closeIcon2 = document.createElement('span');
closeIcon2.innerText = '✕';
closeIcon2.style.fontSize = '16px';
closeIcon2.style.color = '#ffffff';
closeIcon2.style.position = 'relative';
closeIcon2.style.top = '-1px'; // Adjust this value to move the character up

deleteButton.appendChild(closeIcon2);



deleteButton.onclick = function(event) {
    event.stopPropagation();
    localStorage.removeItem(`events.profile:${profileName}`);
        if (selectedProfile === profileName) {
            selectedProfile = null;
            localStorage.setItem('selectedProfile.events', '');
        }
    loadProfiles();
    loadEntries();
};
listItem.appendChild(deleteButton);

if (selectedProfile === profileName) {
    highlightSelectedProfile(listItem);
}
profileList.appendChild(listItem);
        }
    }
}

function openAddProfileDialog() {
    const dialog = document.createElement('div');
    dialog.style.position = 'fixed';
    dialog.style.top = '50%';
    dialog.style.left = '50%';
    dialog.style.transform = 'translate(-50%, -50%)';
    dialog.style.backgroundColor = '#424242';
    dialog.style.padding = '20px';
    dialog.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)';
    dialog.style.zIndex = '1100';

    const input = document.createElement('input');
    input.type = 'text';
    input.placeholder = 'Enter profile name';
    dialog.appendChild(input);

    const addButton = document.createElement('button');
    addButton.innerText = 'Add';
    addButton.style.marginLeft = '10px';
    addButton.onclick = function() {
        const profileName = input.value.trim();
        if (profileName) {
            // Perform a case-insensitive check for existing profiles
            const existingProfiles = Object.keys(localStorage).filter(key => key.startsWith('events.profile:'));
            const profileExists = existingProfiles.some(key => key.toLowerCase() === `events.profile:${profileName.toLowerCase()}`);

            if (!profileExists) {
                localStorage.setItem(`events.profile:${profileName}`, JSON.stringify({}));
                loadProfiles();
                document.body.removeChild(dialog);
            } else {
                alert('Profile name already exists. Please choose a different name.');
            }
        }
    };
    dialog.appendChild(addButton);

    const cancelButton = document.createElement('button');
    cancelButton.innerText = 'Cancel';
    cancelButton.style.marginLeft = '10px';
    cancelButton.onclick = function() {
        document.body.removeChild(dialog);
    };
    dialog.appendChild(cancelButton);

    document.body.appendChild(dialog);
}


function loadEntries() {
    entriesList.innerHTML = '';
    // Add header back after clearing
    if (selectedProfile) {
        const prefix = `${selectedProfile}.events:`.toLowerCase();

        for (let key in localStorage) {
            if (key.toLowerCase().startsWith(prefix)) {
                const entryData = JSON.parse(localStorage.getItem(key));
                const row = document.createElement('div');
                    row.style.padding = '10px';
                    row.style.margin = '5px 0';
                    row.style.borderRadius = '10px';
                    row.style.marginBottom = '12px';
                    row.style.backgroundColor = '#424242';
                    row.style.display = 'flex';
                    row.style.alignItems = 'center';

                    // Create cells for key, value, probability, and time range
                    const keyCell = document.createElement('div');
                    keyCell.innerText = key.split(':')[1];
                    keyCell.style.padding = '5px';
                    keyCell.style.width = '15%';
                    row.appendChild(keyCell);

                    const valueCell = document.createElement('div');
                    valueCell.innerText = entryData.value.replace(/^<Event:\s*/, '').slice(0, -1); // Remove surrounding brackets
                    valueCell.style.padding = '5px';
                    valueCell.style.width = '60%';
                    row.appendChild(valueCell);

                    const probabilityCell = document.createElement('div');
                    probabilityCell.innerText = `${entryData.probability}%`;
                    probabilityCell.style.padding = '5px';
                    probabilityCell.style.width = '10%';
                    row.appendChild(probabilityCell);

                    const timeRangeCell = document.createElement('div');
                    timeRangeCell.innerText = entryData.timeRange;
                    timeRangeCell.style.padding = '5px';
                    timeRangeCell.style.width = '10%';
                    row.appendChild(timeRangeCell);

                    // Add remove button for each entry
                    const actionCell = document.createElement('div');
                    actionCell.style.padding = '5px';
                    actionCell.style.width = '5%';
                    const removeButton = document.createElement('button');
                //    removeButton.innerText = '✕';
removeButton.style.backgroundColor = 'transparent';
removeButton.style.border = 'none';
removeButton.style.cursor = 'pointer';
removeButton.style.display = 'flex';
removeButton.style.alignItems = 'center';
removeButton.style.justifyContent = 'center';
removeButton.style.width = '100%';
removeButton.style.height = '100%';
removeButton.style.transition = 'background-color 0.2s ease';
removeButton.style.borderRadius = '50%';
removeButton.style.width = '28px';
removeButton.style.height = '28px';
removeButton.style.marginLeft = '-3px';
removeButton.style.boxSizing = 'border-box';
                    removeButton.onclick = function() {
                        localStorage.removeItem(key);
                        loadEntries();
                    };

const closeIcon1 = document.createElement('span');
closeIcon1.innerText = '✕';
closeIcon1.style.fontSize = '16px';
closeIcon1.style.position = 'relative';
closeIcon1.style.color = '#ffffff';
closeIcon1.style.top = '-1px'; // Adjust this value to move the character up

                // Append the span to the button
                    removeButton.appendChild(closeIcon1);
                    actionCell.appendChild(removeButton);
                    row.appendChild(actionCell);

// Hover effect
removeButton.addEventListener('mouseenter', () => {
    removeButton.style.backgroundColor = '#676767';
});

removeButton.addEventListener('mouseleave', () => {
    removeButton.style.backgroundColor = 'transparent';
});


// Make the row editable when clicked
// Make the row editable when clicked
row.onclick = function() {
    keyInput.value = key.split(':')[1]; // If key processing remains as is
    valueInput.value = entryData.value.replace(/^<Event:\s*/, '').slice(0, -1); // Remove <Event: > prefix and surrounding brackets
    probabilityInput.value = entryData.probability;
    timeRangeInput.value = entryData.timeRange;
    currentEditingKey = key; // Set the current key for editing
};

                    entriesList.appendChild(row);
                }
            }
        }
    }





    function highlightSelectedProfile(selectedItem) {
        // Remove highlight from all items
        Array.from(profileList.children).forEach(item => {
            item.style.backgroundColor = '';
        });
        // Highlight the selected item
        selectedItem.style.backgroundColor = '#444444';
        selectedItem.style.borderRadius = '10px';
        selectedItem.style.padding = '10px';
    }

    loadProfiles();
    loadEntries();

    // Append profilePanel to body
    document.body.appendChild(eventsProfilePanel);
}

}

// ==================================================================== RULES ===================================================================
function RulesScript() {

    // Custom texts to cycle through
    let customRules = [];

    let currentIndex = 0;

    // Function to determine the current rule index by scanning last two messages
    function determineCurrentIndex() {
        const messageItems = document.querySelectorAll('li[class^="messageListItem_"]');

        if (messageItems.length >= 1) {
            // Check the last message first
            const lastMessage = Array.from(messageItems[messageItems.length - 1].querySelectorAll('span')).map(span => span.innerText).join('') || messageItems[messageItems.length - 1].innerText;

            for (let i = 0; i < customRules.length; i++) {
                if (lastMessage.includes(`<Rule${i + 1}:`)) {
                    currentIndex = (i + 1) % customRules.length;
                    return;
                }
            }
        }

        // If not found in the last message, check the second to last message
        if (messageItems.length >= 2) {
            const secondLastMessage = Array.from(messageItems[messageItems.length - 2].querySelectorAll('span')).map(span => span.innerText).join('') || messageItems[messageItems.length - 2].innerText;

            for (let i = 0; i < customRules.length; i++) {
                if (secondLastMessage.includes(`<Rule${i + 1}:`)) {
                    currentIndex = (i + 1) % customRules.length;
                    return;
                }
            }
        }
    }

    // Expose necessary elements to be used by the second script
    window.customRuleLogic = {
        customRules,
        determineCurrentIndex,
        getCurrentText: function() {
            determineCurrentIndex();
            const customRule = '\n' + customRules[currentIndex];
            currentIndex = (currentIndex + 1) % customRules.length;
            return customRule;
        }
    };

    // Create Button and Panel UI for Local Storage Key Management


window.manageRulesButton = document.createElement('div');
window.manageRulesButton.innerHTML = `
    <button id="toggle-rules-panel"
        style="
            position: relative;
            top: 10px;
            right: 0px;
            left: 10px;
            padding: 7px 15px;


            background: transparent;
            color: #b0b0b0;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            text-align: center;
            cursor: pointer;
            width: 90%;
            transition: background-color 0.1s, color 0.1s;
            z-index: 1001;">
        Manage Rules
    </button>
`;

const rulesButtonElement = manageRulesButton.querySelector('button');
rulesButtonElement.onmouseover = () => {
    rulesButtonElement.style.backgroundColor = '#212121';
    rulesButtonElement.style.color = '#ffffff';
};
rulesButtonElement.onmouseout = () => {
    rulesButtonElement.style.backgroundColor = 'transparent';
    rulesButtonElement.style.color = '#b0b0b0';
};

const rulesPanel = document.createElement('div');
rulesPanel.style.position = 'fixed';
rulesPanel.style.top = '50%';
rulesPanel.style.left = '50%';
rulesPanel.style.transform = 'translate(-50%, -50%)';
// Size different for Mobile and Desktop
if (window.innerWidth <= 768) {
    rulesPanel.style.width = '90%';
    rulesPanel.style.height = '90%';
} else {
    rulesPanel.style.width = '800px';
    rulesPanel.style.height = '700px';
}
rulesPanel.style.backgroundColor = '#2f2f2f';
rulesPanel.style.padding = '20px';
rulesPanel.style.overflowY = 'auto';
rulesPanel.style.display = 'none';
rulesPanel.style.zIndex = 1000;
rulesPanel.style.borderRadius = '10px';
document.body.appendChild(rulesPanel);

const title = document.createElement('h2');
title.innerText = 'Manage Rules';
title.style.textAlign = 'center';
title.style.color = '#ffffff';
title.style.fontSize = '24px';
title.style.fontWeight = '550';
title.style.marginBottom = '20px';
rulesPanel.appendChild(title);

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';

closeButton.addEventListener('mouseenter', () => {
    closeButton.style.backgroundColor = '#676767';
});
closeButton.addEventListener('mouseleave', () => {
    closeButton.style.backgroundColor = 'transparent';
});

closeButton.addEventListener('click', () => {
    rulesPanel.style.display = 'none';
});
rulesPanel.appendChild(closeButton);

manageRulesButton.addEventListener('click', () => {
    rulesPanel.style.display = rulesPanel.style.display === 'none' ? 'block' : 'none';
    renderPanel();
});

function renderPanel() {
    rulesPanel.innerHTML = '';
    rulesPanel.appendChild(title);
    rulesPanel.appendChild(closeButton);

    customRules.forEach((rule, index) => {
        const ruleContainer = document.createElement('div');
        ruleContainer.style.marginBottom = '15px';
        ruleContainer.style.display = 'flex';
        ruleContainer.style.alignItems = 'center';
ruleContainer.style.width = '95%';
        ruleContainer.style.gap = '5px'; // Reduced gap to bring elements closer

        const ruleLabel = document.createElement('label');
        ruleLabel.textContent = `Rule ${index + 1}:`;
ruleLabel.style.color = 'white';
      ruleLabel.style.marginLeft = '5%';
        ruleLabel.style.flex = '0.5'; // Reduced flex to bring the label closer to the input
        ruleContainer.appendChild(ruleLabel);

        const ruleInput = document.createElement('input');
        ruleInput.type = 'text';
        ruleInput.placeholder = rule.replace(/<Rule\d+: (.*?)>/, '$1'); // Only display the inner text as a placeholder
        ruleInput.style.flex = '2';
        ruleInput.style.padding = '5px';
        ruleInput.style.borderRadius = '5px';
        ruleInput.style.border = '0.5px solid #ccc';
        ruleInput.style.backgroundColor = '#2F2F2F';
        ruleInput.style.color = 'gray'; // Default color to indicate unsaved state
        ruleContainer.appendChild(ruleInput);

        // Change color to indicate unsaved changes
        ruleInput.addEventListener('input', () => {
            ruleInput.style.color = '#D16262';
        });

        const updateButton = document.createElement('button');
        updateButton.textContent = 'Update';
        updateButton.style.padding = '5px 10px';
        updateButton.style.border = 'none';
        updateButton.style.backgroundColor = '#1E1E1E';
        updateButton.style.color = 'white';
        updateButton.style.borderRadius = '5px';
        updateButton.style.cursor = 'pointer';
        updateButton.addEventListener('click', () => {
            customRules[index] = `<Rule${index + 1}: ${ruleInput.value}>`;
            updateLocalStorageKeys();
            ruleInput.style.color = 'black'; // Change color to indicate saved state
        });
        ruleContainer.appendChild(updateButton);

        const deleteButton = document.createElement('button');
        deleteButton.textContent = 'Delete';
        deleteButton.style.padding = '5px 10px';
        deleteButton.style.border = 'none';
        deleteButton.style.backgroundColor = '#1E1E1E';
        deleteButton.style.color = 'white';
        deleteButton.style.marginLeft = '5px';
        deleteButton.style.borderRadius = '5px';
        deleteButton.style.cursor = 'pointer';
        deleteButton.addEventListener('click', () => {
            customRules.splice(index, 1);
            updateLocalStorageKeys();
            renderPanel();
        });
        ruleContainer.appendChild(deleteButton);

        // Move rule up/down container
        const moveContainer = document.createElement('div');
        moveContainer.style.display = 'flex';
        moveContainer.style.flexDirection = 'column';
        moveContainer.style.gap = '3px';

        // Move rule up
        if (index > 0) {
            const upButton = document.createElement('button');
            upButton.textContent = '▲';
            upButton.style.padding = '3px';
            upButton.style.border = 'none';
            upButton.style.backgroundColor = 'transparent';
            upButton.style.color = 'white';
            upButton.style.borderRadius = '5px';
            upButton.style.cursor = 'pointer';
            upButton.addEventListener('click', () => {
                [customRules[index - 1], customRules[index]] = [customRules[index], customRules[index - 1]];
                customRules = customRules.map((rule, i) => `<Rule${i + 1}: ${rule.match(/<Rule\d+: (.*?)>/)[1]}>`);
                updateLocalStorageKeys();
                renderPanel();
            });
            moveContainer.appendChild(upButton);
        }

        // Move rule down
        if (index < customRules.length - 1) {
            const downButton = document.createElement('button');
            downButton.textContent = '▼';
            downButton.style.padding = '3px';
            downButton.style.border = 'none';
            downButton.style.backgroundColor = 'transparent';
            downButton.style.color = 'white';
            downButton.style.borderRadius = '5px';
            downButton.style.cursor = 'pointer';
            downButton.addEventListener('click', () => {
                [customRules[index], customRules[index + 1]] = [customRules[index + 1], customRules[index]];
                customRules = customRules.map((rule, i) => `<Rule${i + 1}: ${rule.match(/<Rule\d+: (.*?)>/)[1]}>`);
                updateLocalStorageKeys();
                renderPanel();
            });
            moveContainer.appendChild(downButton);
        }

        ruleContainer.appendChild(moveContainer);
        rulesPanel.appendChild(ruleContainer);
    });

    const addButton = document.createElement('button');
    addButton.textContent = 'Add Rule';
    addButton.style.margin = '15px auto';
    addButton.style.display = 'block';
    addButton.style.padding = '10px';
    addButton.style.border = 'none';
  addButton.style.width = '90%';
    addButton.style.backgroundColor = '#e0e0e0';
    addButton.style.borderRadius = '20px';
    addButton.style.cursor = 'pointer';
    addButton.addEventListener('click', () => {
        const newRule = `<Rule${customRules.length + 1}: Define your rule here>`;
        customRules.push(newRule);
        updateLocalStorageKeys();
        renderPanel();
    });
    rulesPanel.appendChild(addButton);
}


function updateLocalStorageKeys() {
    customRules.forEach((_, index) => localStorage.removeItem(`Rule${index + 1}`));
    customRules.forEach((rule, index) => {
        localStorage.setItem(`Rule${index + 1}`, rule);
    });
}

    // Load rules from localStorage
    for (let i = 0; i < localStorage.length; i++) {
        const savedRule = localStorage.getItem(`Rule${i + 1}`);
        if (savedRule) {
            customRules.push(savedRule);
        }
    }
}

// ===================================================================== MP3 ====================================================================
function mp3Script() {

// Function to get API key from local storage or prompt user to input it
function getApiKey() {
    let apiKey = localStorage.getItem('google_cloud_api_key');
    return apiKey;
}

// Function to set the API key in local storage
document.addEventListener('input', (event) => {
    if (event.target.id === 'api-key-input') {
        const apiKey = event.target.value;
        if (apiKey) {
            localStorage.setItem('google_cloud_api_key', apiKey);
            alert('API key saved successfully.');
        }
    }
});

// Fetch the API key
let API_KEY = getApiKey();

const API_URL = `https://speech.googleapis.com/v1/speech:recognize?key=${API_KEY}`;

// Create a button to toggle the transcription panel
window.mp3ToggleButton = document.createElement('div');
mp3ToggleButton.innerHTML = `
    <button id="toggle-transcription-panel"
        style="
            position: relative;
            top: 10px;
            right: 0px;
            left: 10px;
            padding: 7px 15px;
            margin-top: 20px;

            background: transparent;
            color: #b0b0b0;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            text-align: center;
            cursor: pointer;
            width: 90%;
            transition: background-color 0.1s, color 0.1s;
            z-index: 1001;">
        Show MP3 Transcription
    </button>
`;

const buttonElement = mp3ToggleButton.querySelector('button');
buttonElement.onmouseover = () => {
    buttonElement.style.backgroundColor = '#212121';
    buttonElement.style.color = '#ffffff';
};
buttonElement.onmouseout = () => {
    buttonElement.style.backgroundColor = 'transparent';
    buttonElement.style.color = '#b0b0b0';
};

// Append the button to the body
document.body.appendChild(mp3ToggleButton);

// Add a simple panel to the webpage
const panelHTML = `
    <div id="transcription-panel" style="display: none;">
        <h3>MP3 Transcription Tool</h3>
        <input type="text" id="api-key-input" placeholder="Enter Google Cloud API key here" />
        <input type="text" id="mp3-url" placeholder="Enter MP3 URL here" />
        <button id="transcribe-button">Transcribe</button>
        <textarea id="transcription-result" placeholder="Transcript will appear here..." readonly></textarea>
    </div>
`;

document.body.insertAdjacentHTML('beforeend', panelHTML);

// Set the API key input value if it exists in local storage
document.addEventListener('DOMContentLoaded', () => {
    const apiKeyInput = document.getElementById('api-key-input');
    if (apiKeyInput) {
        const savedApiKey = getApiKey();
        if (savedApiKey) {
            apiKeyInput.value = savedApiKey;
            API_KEY = savedApiKey;
        }
    }
});

// Add styles for the panel
GM_addStyle(`
    #transcription-panel {
        position: fixed;
        bottom: 50px;
        right: 10px;
        width: 300px;
        background: #f8f9fa;
        border: 1px solid #ccc;
        padding: 10px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        z-index: 9999;
        font-family: Arial, sans-serif;
    }
    #transcription-panel h3 {
        margin: 0 0 10px;
        font-size: 16px;
    }
    #transcription-panel input, #transcription-panel textarea {
        width: 100%;
        margin-bottom: 10px;
        padding: 5px;
        box-sizing: border-box;
    }
    #transcription-panel button {
        width: 100%;
        padding: 5px;
        cursor: pointer;
        background: #007bff;
        color: white;
        border: none;
        border-radius: 3px;
    }
`);

// Add event listener to the toggle button
document.addEventListener('click', (event) => {
    // Check if the clicked element is the button
    const button = event.target.closest('#toggle-transcription-panel');
    if (button) {
        const panel = document.getElementById('transcription-panel');
        if (panel) {
            if (panel.style.display === 'none') {
                panel.style.display = 'block';
                button.innerText = 'Hide MP3 Transcription';
            } else {
                panel.style.display = 'none';
                button.innerText = 'Show MP3 Transcription';
            }
        } else {
            console.error('Transcription panel not found!');
        }
    }
});



    // Add event listener to the Transcribe button
    document.getElementById('transcribe-button').addEventListener('click', transcribe);
    // Function to transcribe the entered MP3 URL
    function transcribe() {
        const mp3Url = document.getElementById('mp3-url').value.trim();
        if (!mp3Url) {
            alert('Please enter a valid MP3 URL.');
            return;
        }

        // Check if the transcript already exists in local storage
        const storedTranscript = localStorage.getItem(mp3Url);
        if (storedTranscript) {
            document.getElementById('transcription-result').value = storedTranscript;
            return;
        }

        // Fetch MP3 file using GM_xmlhttpRequest and process it
        GM_xmlhttpRequest({
            method: 'GET',
            url: mp3Url,
            responseType: 'arraybuffer', // Required for audio data
            onload: (response) => {
                // Convert the audio file to Base64
                const audioBase64 = arrayBufferToBase64(response.response);

                // Send the Base64-encoded audio to Google Cloud Speech-to-Text API
                sendToGoogleCloud(audioBase64, mp3Url);
            },
            onerror: (err) => {
                alert('Failed to fetch the MP3 file.');
                console.error(err);
            },
        });
    }

    // Function to send the Base64 audio data to Google Cloud Speech-to-Text API
    function sendToGoogleCloud(audioBase64, mp3Url) {
        GM_xmlhttpRequest({
            method: 'POST',
            url: API_URL,
            headers: { 'Content-Type': 'application/json' },
            data: JSON.stringify({
                config: {
                    encoding: 'MP3',
                    sampleRateHertz: 16000,
                    languageCode: 'en-US',
                },
                audio: {
                    content: audioBase64,
                },
            }),
            onload: (response) => {
                const result = JSON.parse(response.responseText);
                if (result.error) {
                    alert(`Error: ${result.error.message}`);
                } else {
                    const transcript = result.results
                        ?.map((r) => r.alternatives[0].transcript)
                        .join('\n');
                    document.getElementById('transcription-result').value =
                        transcript || 'No transcript found.';

                    // Store the transcript in local storage
                    localStorage.setItem(mp3Url, transcript || 'No transcript found.');

                    // Limit local storage to 3 entries
                    manageLocalStorageLimit();

                    // Show "Transcript done!" message
                    showTranscriptionDoneMessage();
                }
            },
            onerror: (err) => {
                alert('Failed to process the transcription.');
                console.error(err);
            },
        });
    }

    // Function to convert ArrayBuffer to Base64
    function arrayBufferToBase64(buffer) {
        const binary = [];
        const bytes = new Uint8Array(buffer);
        const len = bytes.byteLength;
        for (let i = 0; i < len; i++) {
            binary.push(String.fromCharCode(bytes[i]));
        }
        return btoa(binary.join(''));
    }

    // Observe the conversation for changes and detect MP3 links
    const observer = new MutationObserver(() => {
        const messageItems = document.querySelectorAll('div[class*="messageContent_"]');
        const lastMessage = messageItems[messageItems.length - 1];

        if (lastMessage) {
            const mp3LinkMatch = lastMessage.innerText.match(/https:\/\/files\.shapes\.inc\/.*\.mp3/);
            if (mp3LinkMatch) {
                const mp3Link = mp3LinkMatch[0];
                const storedLink = localStorage.getItem('lastMp3Link');

                // Check if the link is new or different
                if (mp3Link !== storedLink) {
                    localStorage.setItem('lastMp3Link', mp3Link); // Store the new link
                    document.getElementById('mp3-url').value = mp3Link; // Populate the input
                    transcribe(); // Automatically transcribe the new link
                }
            }
        }
    });

    // Start observing the document body for new messages
    observer.observe(document.body, { childList: true, subtree: true });

    // Function to manage local storage limit of 3 entries
    function manageLocalStorageLimit() {
        const keys = Object.keys(localStorage).filter((key) => key.startsWith('http'));
        if (keys.length > 10) {
            // Remove oldest entries until only 3 remain
            while (keys.length > 10) {
                localStorage.removeItem(keys.shift());
            }
        }
    }

    // Function to show "Transcript done!" message
    function showTranscriptionDoneMessage() {
        let messageDiv = document.getElementById('transcription-done-message');
        if (!messageDiv) {
            messageDiv = document.createElement('div');
            messageDiv.id = 'transcription-done-message';
            messageDiv.innerText = 'Transcript done!';
            document.body.appendChild(messageDiv);
        }

        messageDiv.style.display = 'block';
        setTimeout(() => {
            messageDiv.style.display = 'none';
        }, 3000);
    }

}

// =================================================================== STYLES ===================================================================
function StylesScript() {

    // Add custom CSS rule to modify the channel text area
    const style = document.createElement('style');
    style.innerHTML = `
        .channelTextArea_bdf0de {
            position: relative;
            width: 120%;
            text-indent: 0;
            border-radius: 8px;
        }
        .themedBackground_bdf0de {
            background: #2F2F2F;
        }
        .chatContent_a7d72e {
            position: relative;
            display: flex;
            flex-direction: column;
            min-width: 0;
            min-height: 0;
            flex: 1 1 auto;
            background: #212121 !important;
        }

        .theme-dark .container_ee69e0 {
            background: #191919;
        }
        .theme-dark .themed_fc4f04 {
            background: #212121;
        }

        .footer_f8ec41 {
            background: #131313;
        }
        .theme-dark .container_b2ca13 {
            background: #191919;
        }

.wrapper_fea3ef {
            background-color: #131313;
    display: none !important;

}



    `;
    document.head.appendChild(style);

    // Function to hide the targeted elements
    function hideElements() {
        // Select all elements that match the provided pattern
        const elements = document.querySelectorAll("[id^='message-accessories-'] > article > div > div > div.embedProvider_b0068a.embedMargin_b0068a, [id^='message-accessories-'] > article > div > div > div.embedTitle_b0068a.embedMargin_b0068a, .buttons_bdf0de .expression-picker-chat-input-button.buttonContainer_bdf0de, .channelAppLauncher_df39bd .buttonContainer_df39bd.app-launcher-entrypoint");

        // Iterate over each element and hide it
        elements.forEach(element => {
            element.style.display = 'none';
        });
    }

    // Run the function initially to hide elements present at page load
    hideElements();

    // Observe mutations to the DOM and hide elements when new ones are added
    const observer = new MutationObserver(hideElements);
    observer.observe(document.body, { childList: true, subtree: true });

// Create the toggleButton div
// Create the toggleButton div
window.serverbartoggleButton  = document.createElement('div');
serverbartoggleButton .innerHTML = `
    <button id="toggle-server-panel"
        style="
            position: relative;
            top: 10px;
            right: 0px;
            left: 10px;
            padding: 7px 15px;
            margin-top: 10px;

            background: transparent;
            color: #b0b0b0;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            text-align: center;
            cursor: pointer;
            width: 90%;
            transition: background-color 0.1s, color 0.1s;
            z-index: 1001;">
        Toggle Sidebar
    </button>
`;

// Append the toggleButton to the desired parent element (e.g., `DCstoragePanel`)
//window.DCstoragePanel.appendChild(serverbartoggleButton);

// Function to toggle .itemsContainer_fea3ef visibility
function servertoggleItemsContainer() {
    const serveritemsContainer = document.querySelectorAll('.wrapper_fea3ef');
    serveritemsContainer.forEach(container => {
        const currentDisplay = window.getComputedStyle(container).getPropertyValue('display');

        if (currentDisplay === 'none') {
            container.setAttribute('style', 'display: flex !important;');
        } else {
            container.setAttribute('style', 'display: none !important;');
        }
    });
}


    // Add event listener to the toggle button
    serverbartoggleButton.addEventListener('click', servertoggleItemsContainer);

const serverbuttonElement = serverbartoggleButton.querySelector('button');
serverbuttonElement.onmouseover = () => {
    serverbuttonElement.style.backgroundColor = '#212121';
    serverbuttonElement.style.color = '#ffffff';
};
serverbuttonElement.onmouseout = () => {
    serverbuttonElement.style.backgroundColor = 'transparent';
    serverbuttonElement.style.color = '#b0b0b0';
};


}

// ================================================================== < > HIDER =================================================================
function HiderScript() {
    function hideEnclosedEntries() {
        const messageItems = document.querySelectorAll('li[class^="messageListItem_"]');

        messageItems.forEach(messageItem => {
            const spans = messageItem.querySelectorAll('div[class*="messageContent_"] span');

            let isHiding = false;
            spans.forEach(span => {
                const text = span.textContent.trim();

                // Start hiding when encountering '<'
                if (text.startsWith('<') && !isHiding) {
                    isHiding = true;
                }

                // Apply hiding style if within an enclosed entry
                if (isHiding) {
                    span.style.opacity = '0'; // Make it invisible
                    span.style.position = 'absolute'; // Remove it from the document flow
                }

                // Stop hiding when encountering '>'
                if (text.endsWith('>') && isHiding) {
                    isHiding = false;
                }
            });
        });
    }

    // Observe for new messages being added to the DOM
    const observer = new MutationObserver(mutations => {
        mutations.forEach(() => {
            hideEnclosedEntries();
        });
    });

    // Start observing the entire document body for changes
    observer.observe(document.body, { childList: true, subtree: true });

    // Initial run
    hideEnclosedEntries();

}

// ================================================================= MAIN LOGIC =================================================================
function MainLogicScript() {
    // 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 the settings window
        window.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);


        // 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));
        });


// Function to get the correct input element based on the mode
// Function to get the correct input element based on the mode
// 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_"]');
}

// Add event listener to handle Enter key behavior
window.addEventListener('keydown', function(event) {
    const inputElement = getInputElement();

    if (event.key === 'Enter' && !event.shiftKey && !enterKeyDisabled) {
        if (inputElement && inputElement.nodeName === 'TEXTAREA') {
            // Mobile version: Only allow line break
            return;
        }

        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

// Add event listener to the send button to execute handleEnterKey when clicked
window.addEventListener('click', function(event) {
    const sendButton = document.querySelector('button[aria-label="Nachricht senden"]');
    if (sendButton && sendButton.contains(event.target)) {
        // Execute main handler for Enter key
        handleEnterKey();
    }
}, true);

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

// Function to apply custom rules for the input field
function applyCustomRule(inputElement) {
    const customRule = window.customRuleLogic ? window.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') {
        // For mobile version where input is <textarea>
        inputElement.selectionStart = inputElement.selectionEnd = inputElement.value.length;
    } else {
        // For desktop version where input is a Slate editor
        inputElement.focus();

        // Simulate repeated Ctrl + ArrowRight key press events to move cursor to the end
        const repeatPresses = 150; // Number of times to simulate Ctrl + ArrowRight
        for (let i = 0; i < repeatPresses; i++) {
            const ctrlArrowRightEvent = new KeyboardEvent('keydown', {
                key: 'ArrowRight',
                code: 'ArrowRight',
                keyCode: 39, // ArrowRight key code
                charCode: 0,
                which: 39,
                bubbles: true,
                cancelable: true,
                ctrlKey: true // Set Ctrl key to true
            });
            inputElement.dispatchEvent(ctrlArrowRightEvent);
        }
    }
}

// Function to send the message (either click send button or simulate Enter key)
function sendMessage(inputElement) {
    if (inputElement.nodeName === 'TEXTAREA') {
        // Mobile version: Do not send message, just return to allow linebreak
        return;
    }

    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 get the current profile from local storage
function getCurrentProfile() {
    return localStorage.getItem('selectedProfile.lorebook');
}



// 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_"]');
        let relevantMessages = Array.from(messageItems).slice(-15); // Last 15 messages
        const lastMessage = Array.from(messageItems).slice(-1); // Last message only


// Iterate over the last 15 messages to extract hidden bracket content
relevantMessages = relevantMessages.map(msg => {
    // Retrieve all span elements within the message
    const spans = msg.querySelectorAll('span');

    // Filter out the spans based on both style conditions: opacity and position
    const hiddenSpans = Array.from(spans).filter(span => {
        const style = window.getComputedStyle(span);
        return style.opacity === '0' && style.position === 'absolute';
    });

    // Join the text content of all matching spans, converting them to lowercase
    const bracketContent = hiddenSpans.map(span => span.textContent.toLowerCase()).join('');

    // Extract content within square brackets, if any
    const match = bracketContent.match(/\[(.*?)\]/);
    return match ? match[1] : null;
}).filter(content => content !== null);

// Log the filtered messages for debugging purposes
console.log("Filtered Relevant Messages (content in brackets, last 15):", relevantMessages);
        console.log("Last Message:", lastMessage.map(msg => msg.textContent));

        // Track how many entries have been appended
        let appendedCount = 0;
        const maxAppends = 3;

        // Check if the last message contains a specific link pattern
        const mp3LinkPattern = /https:\/\/files\.shapes\.inc\/.*\.mp3/;
        let mp3LinkValue = null;

        if (lastMessage.length > 0) {
        const lastMessageText = lastMessage[0].textContent.toLowerCase();

            const mp3LinkMatch = lastMessageText.match(mp3LinkPattern);
            if (mp3LinkMatch) {
                const mp3LinkKey = mp3LinkMatch[0];
                mp3LinkValue = localStorage.getItem(mp3LinkKey);
                console.log(`MP3 Link detected: ${mp3LinkKey}. Retrieved value: ${mp3LinkValue}`);
            }
        }

        // Create an array to hold all entry keys that need to be checked
        let allEntryKeys = [];

        // 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 => {
                    allEntryKeys.push({ entryKey, entryValue });
                });
            }
        });

        // If mp3LinkValue is present, parse it for keywords as well
        if (mp3LinkValue) {
            console.log(`Scanning MP3 link value for keywords: ${mp3LinkValue}`);
            const mp3Keywords = mp3LinkValue.split(',');
            mp3Keywords.forEach(keyword => {
                const trimmedKeyword = keyword.trim();
                console.log(`Adding keyword from MP3 value: ${trimmedKeyword}`);
                // Add mp3 keywords but set entryValue to an empty string instead of null
                allEntryKeys.push({ entryKey: trimmedKeyword, entryValue: '' });
            });
        }

        // Iterate over all collected entry keys and perform the checks
        allEntryKeys.forEach(({ entryKey, entryValue }) => {
            if (appendedCount >= maxAppends) return; // Stop if max appends reached

            // Log each keyword being checked
            console.log(`Checking keyword: ${entryKey}`);

            // Check input element text for complete word match of keyword (case-insensitive)
            const inputText = inputElement.value || inputElement.textContent;

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

            console.log(`Keyword '${entryKey}' in input: ${isKeywordInInput}, in last message: ${isKeywordInLastMessage}, in MP3 value: ${isKeywordInMp3LinkValue}`);

            if ((isKeywordInInput || isKeywordInLastMessage || isKeywordInMp3LinkValue) && entryValue) {
                const keywordAlreadyUsed = relevantMessages.some(bracketContent => {
                    return new RegExp(`\\b${entryKey}\\b`, 'i').test(bracketContent);
                });

                if (!keywordAlreadyUsed) {
                    // Append the entryValue to the input element only if entryValue is not null or empty
                    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);
                    }
                    appendedCount++; // Increment the count
                    console.log(`Keyword '${entryKey}' detected. Appended lorebook entry to the input.`);
                } else {
                    console.log(`Keyword '${entryKey}' already found in recent bracketed messages or entryValue is null/empty. Skipping append.`);
                }
            }
        });

        // Log the total number of entries appended
        console.log(`Total lorebook entries appended: ${appendedCount}`);
    }
}




function getRandomEntry(inputElement) {
    const selectedProfile = localStorage.getItem('selectedProfile.events');
    if (selectedProfile) {
        let profileEntries = [];
        const currentHour = new Date().getHours();
for (let key in localStorage) {
    if (key.startsWith(`${selectedProfile}.events:`)) {
        const entryData = JSON.parse(localStorage.getItem(key));
        const [startHour, endHour] = entryData.timeRange.split('-').map(Number);
        // Check if current hour is within the time range
        if (
            (startHour <= endHour && currentHour >= startHour && currentHour < endHour) || // Normal range
            (startHour > endHour && (currentHour >= startHour || currentHour < endHour)) // Crosses midnight
        ) {
            profileEntries.push({ key, ...entryData });
        }
    }
}

        if (profileEntries.length > 0) {
            const probability = parseInt(localStorage.getItem('events.probability') || '100', 10);
            let selectedEntry = null;
            while (profileEntries.length > 0) {
                // Randomly select an entry from the available entries
                const randomIndex = Math.floor(Math.random() * profileEntries.length);
                const randomEntry = profileEntries[randomIndex];
                // Check if the entry passes the individual probability check
                if (Math.random() * 100 < randomEntry.probability) {
                    selectedEntry = randomEntry;
                    break;
                } else {
                    // Remove the entry from the list if it fails the probability check
                    profileEntries.splice(randomIndex, 1);
                }
            }
            if (selectedEntry && Math.random() * 100 < probability) {
                console.log(`Random Entry Selected: ${selectedEntry.value}`);
                appendToInput(inputElement, selectedEntry.value); // Append the random entry to the input element
            }
        } else {
            console.log('No entries available for the selected profile in the current time range.');
        }
    } else {
        console.log('No profile selected. Please select a profile to retrieve a random entry.');
    }
}

// Helper function to append text to the input element
function appendToInput(inputElement, text) {
    const lineBreak = '\n';
    if (!inputElement) {
        console.error('Input element not found.');
        return;
    }

    if (inputElement.nodeName === 'TEXTAREA') {
        // Mobile: Append text to <textarea>
        const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
        nativeInputValueSetter.call(inputElement, inputElement.value + `${lineBreak}${text}`);

        const inputEvent = new Event('input', {
            bubbles: true,
            cancelable: true,
        });
        inputElement.dispatchEvent(inputEvent);
    } else if (inputElement.hasAttribute('data-slate-editor')) {
        // Desktop: Append text for Slate editor
        const inputEvent = new InputEvent('beforeinput', {
            bubbles: true,
            cancelable: true,
            inputType: 'insertText',
            data: `${lineBreak}${text}`,
        });
        inputElement.dispatchEvent(inputEvent);
    } else {
        console.error('Unsupported input element type.');
    }
}



// Expose the function to be accessible from other scripts
window.getRandomEntry = getRandomEntry;


  }

}

// =================================================================== BUTTONS ==================================================================
function initializeButton() {


DCstoragePanel.appendChild(openLorebookButton);
DCstoragePanel.appendChild(eventsButton);
DCstoragePanel.appendChild(manageRulesButton);
DCstoragePanel.appendChild(serverbartoggleButton);
DCstoragePanel.appendChild(mp3ToggleButton);
DCstoragePanel.appendChild(exportButton);
DCstoragePanel.appendChild(importButton);
DCstoragePanel.appendChild(settingsWindow);

    }


// ============================================================ SCRIPT LOADING ORDER ============================================================
LorebookScript();
ImportExportScript();
EventsScript();
RulesScript();
mp3Script();
StylesScript();
HiderScript();
MainLogicScript();
initializeButton();


})();

QingJ © 2025

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