c.ai X Panel

Adds a Description and an Autoscroll Button

// ==UserScript==
// @name         c.ai X Panel
// @namespace    c.ai X Panel
// @version      0.4
// @description  Adds a Description and an Autoscroll Button
// @author       Vishanka
// @license     MIT
// @match        https://character.ai/*
// @grant        none
// @icon        https://i.imgur.com/ynjBqKW.png
// ==/UserScript==


(function() {
    'use strict';

    var Description_ToggleButton;
    var DescriptionTextContainer;

    function addDescriptionButton() {
        var parentElement = document.querySelector('div.flex:nth-child(5)');
        if (!parentElement) {
            parentElement = document.querySelector('div.flex:nth-child(4)');
        }

if (parentElement) {
    Description_ToggleButton = document.createElement('button');
    Description_ToggleButton.id = 'Description_ToggleButton';
    Description_ToggleButton.style.display = 'flex';
    Description_ToggleButton.style.alignItems = 'center';
    Description_ToggleButton.style.textAlign = 'left';
    Description_ToggleButton.style.paddingLeft = '17px';
    Description_ToggleButton.style.fontSize = '14px';
    Description_ToggleButton.style.width = '287px';
    Description_ToggleButton.style.height = '40px';
    Description_ToggleButton.style.borderRadius = '8px';

// Mouseover event with softer animation
    Description_ToggleButton.addEventListener('mouseover', function() {
      Description_ToggleButton.style.transition = 'background-color 0.3s ease';
      Description_ToggleButton.style.backgroundColor = '#1F1F23';
    });
    Description_ToggleButton.addEventListener('mouseout', function() {
      Description_ToggleButton.style.transition = 'background-color 0.3s ease';
      Description_ToggleButton.style.backgroundColor = '';
    });

// Create a divider
var DescriptionDivider = document.createElement('div');
DescriptionDivider.style.height = '1px'; // Thin line
DescriptionDivider.style.width = '100%'; // Full width
DescriptionDivider.style.backgroundColor = '#3A3A3D';
DescriptionDivider.style.margin = '0px 0'; // Margin above and below for spacing

// Add the divider to the parent element before the button
parentElement.appendChild(DescriptionDivider);

    var DescriptionImage = document.createElement('img');
    DescriptionImage.src = 'https://i.imgur.com/1DnLhLG.png';
    DescriptionImage.style.marginRight = '12px';
    DescriptionImage.style.width = '18px';
    DescriptionImage.style.height = '18px';
    DescriptionImage.style.display = 'block';
    DescriptionImage.style.flexShrink = 0;

    // Wrap both button text and image in a div
    var DescriptionAndImagecontentWrapper = document.createElement('div');
    DescriptionAndImagecontentWrapper.style.display = 'flex';
    DescriptionAndImagecontentWrapper.style.alignItems = 'center';
    DescriptionAndImagecontentWrapper.appendChild(DescriptionImage);
    DescriptionAndImagecontentWrapper.appendChild(document.createTextNode('Description'));

    Description_ToggleButton.appendChild(DescriptionAndImagecontentWrapper);

    parentElement.appendChild(Description_ToggleButton);
    console.log("Button added successfully.");



            DescriptionTextContainer = document.createElement('div');
            DescriptionTextContainer.style.wordWrap = 'break-word';
            DescriptionTextContainer.style.overflowWrap = 'break-word';
            DescriptionTextContainer.style.maxWidth = '100%';
            DescriptionTextContainer.style.display = 'none';
            DescriptionTextContainer.style.fontSize = '15px';
            DescriptionTextContainer.style.hyphens = 'auto';
            DescriptionTextContainer.style.color = '#a2a2ac';
            parentElement.appendChild(DescriptionTextContainer);

            // Add event listener for button click
            Description_ToggleButton.addEventListener('click', function() {
                var currentURL = document.location.href;
                var afterChat = currentURL.substring(currentURL.indexOf('https://character.ai/chat/') + 'https://character.ai/chat/'.length);
                var currentURL1 = afterChat.split('?hist')[0];
                var description = sessionStorage.getItem(currentURL1 + '_description');
                console.log("currentURL1:", currentURL1);

                if (DescriptionTextContainer.style.display === 'none') {
                    DescriptionTextContainer.innerHTML = description;
                    DescriptionTextContainer.style.display = 'block';
                } else {
                    DescriptionTextContainer.innerHTML = '';
                    DescriptionTextContainer.style.display = 'none';
                }
            });


    let intervalId;
    let autoPressEnabled = false;

    function ArrowRightKeyDown() {
        document.body.dispatchEvent(
            new KeyboardEvent('keydown', {
                bubbles: true,
                key: 'ArrowRight',
            })
        );
        console.log("Arrow right pressed");
    }

function toggleAutoPress() {
    autoPressEnabled = !autoPressEnabled;
    if (autoPressEnabled) {
        // Trigger 30 key presses to the right at once
        for (let i = 0; i < 30; i++) {
            ArrowRightKeyDown();
        }
        intervalId = setInterval(ArrowRightKeyDown, 1000); // Repeat every 1 second
autoscrollButton.innerHTML = '<span style="color: #A2A2AC; margin-left: 5px; margin-right: 13px;">■</span> Stop Autoscroll';


    } else {
        clearInterval(intervalId);
autoscrollButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="28" viewBox="0 0 16 32" fill="none" class="h-full" style="margin-right: 10px;"><path d="M9.59998 19.1998L12.8 15.9998L9.59998 12.7998" stroke="#A2A2AC" stroke-width="1.28" stroke-linecap="round" stroke-linejoin="round"></path><path d="M3.59998 19.1998L6.79998 15.9998L3.59998 12.7998" stroke="#A2A2AC" stroke-width="1.28" stroke-linecap="round" stroke-linejoin="round"></path></svg> Start Autoscroll';
    }
}


var autoscrollButton = document.createElement('button');
autoscrollButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="28" viewBox="0 0 16 32" fill="none" class="h-full" style="margin-right: 10px;"><path d="M9.59998 19.1998L12.8 15.9998L9.59998 12.7998" stroke="#A2A2AC" stroke-width="1.28" stroke-linecap="round" stroke-linejoin="round"></path><path d="M3.59998 19.1998L6.79998 15.9998L3.59998 12.7998" stroke="#A2A2AC" stroke-width="1.28" stroke-linecap="round" stroke-linejoin="round"></path></svg> Start Autoscroll';
autoscrollButton.style.display = 'flex';
autoscrollButton.style.alignItems = 'center';
autoscrollButton.style.textAlign = 'left';
autoscrollButton.style.paddingLeft = '17px';
autoscrollButton.style.fontSize = '14px';
autoscrollButton.style.width = '287px'; //
autoscrollButton.style.height = '40px'; //
autoscrollButton.style.borderRadius = '8px';
autoscrollButton.addEventListener('click', toggleAutoPress);

// Mouseover event with softer animation
autoscrollButton.addEventListener('mouseover', function() {
    autoscrollButton.style.transition = 'background-color 0.3s ease';
    autoscrollButton.style.backgroundColor = '#1F1F23';
});
autoscrollButton.addEventListener('mouseout', function() {
    autoscrollButton.style.transition = 'background-color 0.3s ease';
    autoscrollButton.style.backgroundColor = '';
});


parentElement.appendChild(autoscrollButton);


        } else {
            console.log("Parent element not found.");
        }
    }


function fetchDescription() {
    const originalOpen = XMLHttpRequest.prototype.open; // Use const for unchanged values
    const interceptedData = {}; // Single object for all intercepted data

    XMLHttpRequest.prototype.open = function(method, url, async) {
        if (url.startsWith('https://plus.character.ai/chat/character/info') ||
            url.startsWith('https://beta.character.ai/chat/character/info')) {
            this.addEventListener('load', () => {
                if (this.status >= 200 && this.status < 300) {
                    try {
                        const response = JSON.parse(this.responseText);
                        if (response && response.character) {
                            const { description, external_id } = response.character;
                            if (description !== undefined) {
                                interceptedData[external_id] = { description };
                                console.log(`NextDescription: ${description}`);
                                console.log(`ExternalID: ${external_id}`);

                                sessionStorage.setItem(`${external_id}_description`, description);
                            } else {
                                console.error("Invalid or empty description field in response");
                            }
                        }
                    } catch (error) {
                        console.error(`Error parsing JSON response: ${error}`);
                    }
                } else {
                    console.error(`Request failed with status: ${this.status}`);
                }
            });
        }
        originalOpen.apply(this, arguments); // Preserve the context of `this`
    };
}

fetchDescription();




// HERE ARE THE FUNCTIONS THAT MAKE SURE THAT THE BUTTON IS ADDED
function addButtonsWithRetry() {
    // Only run on specific pages
    if (!/https:\/\/character\.ai\/chat\//.test(window.location.href)) {
        return;
    }

    var attempts = 0;
    var maxAttempts = 10;
    var interval = setInterval(function() {
        if (!document.getElementById('Description_ToggleButton')) {
            addDescriptionButton(); // Ensure this function is defined elsewhere in your code
            attempts++;
        }
        if (document.getElementById('Description_ToggleButton') || attempts >= maxAttempts) {
            clearInterval(interval); // Stop retrying if button is added or max attempts reached
        }
    }, 1000); // Retry every second
}

addButtonsWithRetry();

// Check for URL changes
var currentUrl = window.location.href;
setInterval(function() {
    if (window.location.href !== currentUrl) {
        console.log("URL changed, checking for button...");
        currentUrl = window.location.href;
        addButtonsWithRetry(); // Reapply the button if URL changes
    }
}, 1000);


})();