🔰 ADK - ChatGPT QoL Buttons Plus 🔰

Enhance your ChatGPT experience with custom buttons and a sleek popup interface

// AsheshDevelopment
// filename: ADK_ChatGPT_QoL_Buttons_Plus.user.js

// ==UserScript==
// @name         🔰 ADK - ChatGPT QoL Buttons Plus 🔰
// @namespace    http://tampermonkey.net/
// @version      3.0.3
// @description  Enhance your ChatGPT experience with custom buttons and a sleek popup interface
// @author       Ashesh Development
// @license      https://gitlab.com/AsheshPlays/tampermonkey-userscripts/-/raw/main/LICENSE
// @match        *://chatgpt.com/*
// @match        *://chat.openai.com/*
// @icon         https://media.chatgptautocontinue.com/images/icons/openai/black/icon48.png?07bf6b7
// @icon64       https://media.chatgptautocontinue.com/images/icons/openai/black/icon64.png?07bf6b7
// @grant        GM_registerMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function () {
    'use strict';
    const style = document.createElement('style');
    style.innerHTML = `
        .navigation-buttons {
            margin: 10px 0 0 14px;
            text-align: center;
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
        }
        .navigation-buttons button {
            margin: 5px;
            padding: 5px 15px;
            font-size: 14px;
            cursor: pointer;
            background: #66d9ef;
            color: #272822;
            border: none;
            border-radius: 5px;
            transition: background 0.3s;
        }
        .navigation-buttons button:hover {
            background: #a6e22e;
        }
        .author-note {
            margin-top: 10px;
            font-size: 12px;
            color: black;
            background: #D3A52D;
            padding: 5px;
            border-radius: 3px;
            text-align: center;
        }
        .conversation-number {
            position: absolute;
            left: 18px;
            top: 60px;
            font-size: 16px;
            font-weight: bold;
            color: #f92672;
            z-index: 1;
            background: rgba(39, 40, 34, 0.8);
            padding: 9px 12px;
            border-radius: 7px;
            border: 1px solid #f92672;
            cursor: pointer;
        }
        .xl\\:max-w-\\[48rem\\] {
            max-width: 100%;
        }
        [class^="react-scroll-to-bottom--"]::-webkit-scrollbar {
            width: 20px;
        }
        [class^="react-scroll-to-bottom--"]::-webkit-scrollbar-thumb {
            min-height: 5%;
            background: #fd971f;
        }
        .md\\:items-end {
            align-items: flex-end;
            position: absolute;
            left: 0;
            bottom: -45px;
        }
        button.btn.relative.btn-neutral.whitespace-nowrap.-z-0.border-0.md\\:border {
            border-radius: 10px;
            background: #ee0008;
            border: 1px solid #ee0008;
            color: #fff;
        }
        button.btn.relative.btn-neutral.whitespace-nowrap.-z-0.border-0.md\\:border:hover {
            background: #9c1519;
            border: 1px solid #9c1519;
            transition: 0.25s;
        }
        button.btn.relative.btn-neutral.whitespace-nowrap.-z-0.border-0.md\\:border .flex.w-full.gap-2.items-center.justify-center:after {
            content: "last response";
        }
        .dark.bg-gray-950.rounded-md.border-\\[0\\.5px\\].border-token-border-medium {
            display: flex;
            flex-direction: column;
            height: 100%;
        }
        .overflow-y-auto.p-4 {
            order: 1;
            flex-grow: 1;
        }
        .flex.items-center.relative.text-token-text-secondary.bg-token-main-surface-secondary.px-4.py-2.text-xs.font-sans.justify-between.rounded-t-md {
            order: 2;
            direction: rtl;
            background: darkslateblue;
            color: lightgrey;
        }
    `;
    document.head.appendChild(style);

    function addNavigationButtons() {
        const targetDiv = document.querySelector('.relative.px-2.py-2.text-center.text-xs.text-token-text-secondary');
        if (targetDiv) {
            let authorNote = document.querySelector('.author-note');
            if (!authorNote) {
                authorNote = document.createElement('div');
                authorNote.className = 'author-note';
                authorNote.textContent = 'Script by Ashesh Development';
                targetDiv.appendChild(authorNote);
            }
            let navContainer = document.querySelector('.navigation-buttons');
            if (!navContainer) {
                navContainer = document.createElement('div');
                navContainer.className = 'navigation-buttons';
                navContainer.innerHTML = `
                    <button id="prevBtn">Prev.</button>
                    <button id="nextBtn">Next</button>
                    <button id="fullCodeBtn">Full Code</button>
                    <button id="fullCodePlusBtn">Full Code+</button>
                `;
                targetDiv.appendChild(navContainer);
                document.getElementById("nextBtn").addEventListener("click", function () {
                    navigateResponse(1);
                });
                document.getElementById("prevBtn").addEventListener("click", function () {
                    navigateResponse(-1);
                });
                document.getElementById("fullCodeBtn").addEventListener("click", function () {
                    sendMessage("Write the full script without the placeholders and no commented lines. Just write everything without extra line and no explanations. I want the script ready to copy and paste into my IDE and I need it production ready.");
                });
                document.getElementById("fullCodePlusBtn").addEventListener("click", function () {
                    sendMessage("Please write the full script without any placeholders, removing all comments except those necessary for documentation. The script should include all necessary imports, class definitions, methods, logic, and detailed debug logs colorized using the RETRASH color scheme. It must be very detailed, easy to understand, fully functional, complete, and ready to paste directly into my JetBrains Rider IDE. The script must be production-ready, following all specified guidelines, including proper documentation within the code. Ensure that nothing is omitted, and the script is fully complete from start to finish. Always indicate 'AsheshDevelopment' in the first line of the script as a comment and the filename also as a comment on the second line of the script. The debug logs should use the following RETRASH color palette.");
                });
            }
        }
    }

    function sendMessage(message, autosend = true) {
        const textarea = document.querySelector('#prompt-textarea');
        if (textarea) {
            textarea.innerHTML = `<p>${message}</p>`;
            const inputEvent = new Event('input', { bubbles: true });
            textarea.dispatchEvent(inputEvent);
            if (autosend) {
                setTimeout(() => {
                    const keydownEvent = new KeyboardEvent('keydown', {
                        bubbles: true,
                        cancelable: true,
                        key: 'Enter',
                        code: 'Enter',
                        keyCode: 13
                    });
                    textarea.dispatchEvent(keydownEvent);
                }, 250);
            }
        }
    }

    function navigateResponse(direction) {
        const responses = document.querySelectorAll('[data-testid^="conversation-turn-"]');
        let closestIndex = findClosestResponseIndex(responses);
        closestIndex += direction;
        if (closestIndex >= 0 && closestIndex < responses.length) {
            responses[closestIndex].scrollIntoView({ behavior: "smooth" });
        }
    }

    function findClosestResponseIndex(responses) {
        let closestIndex = 0;
        let minDistance = Infinity;
        const viewportTop = window.scrollY;
        const viewportBottom = viewportTop + window.innerHeight;
        responses.forEach((response, index) => {
            const rect = response.getBoundingClientRect();
            const responseTop = rect.top + window.scrollY;
            const responseBottom = rect.bottom + window.scrollY;
            const distance = Math.min(
                Math.abs(viewportTop - responseTop),
                Math.abs(viewportBottom - responseBottom)
            );
            if (distance < minDistance) {
                minDistance = distance;
                closestIndex = index;
            }
        });
        return closestIndex;
    }

    setTimeout(() => {
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', () => {
                addNavigationButtons();
            });
        } else {
            addNavigationButtons();
        }
    }, 2000);

    setInterval(addNavigationButtons, 2000);

    registerMenu();

    const liveLineNumbers = GM_getValue('liveLineNumbers', true);

    function createLineNumbersElement() {
        const lineNumbersElement = document.createElement('div');
        lineNumbersElement.classList.add('line-numbers-inline');
        lineNumbersElement.style.display = 'flex';
        lineNumbersElement.style.flexDirection = 'column';
        lineNumbersElement.style.paddingTop = '0.07rem';
        lineNumbersElement.style.textAlign = 'right';
        lineNumbersElement.style.userSelect = 'none';
        lineNumbersElement.style.pointerEvents = 'none';
        lineNumbersElement.style.color = '#aaa';
        lineNumbersElement.style.background = '#1e1e1e';
        lineNumbersElement.style.lineHeight = '1.5';
        lineNumbersElement.style.zIndex = '2';
        lineNumbersElement.style.position = 'sticky';
        lineNumbersElement.style.left = '0';
        lineNumbersElement.style.minWidth = 'auto';
        lineNumbersElement.style.transform = 'none';
        return lineNumbersElement;
    }

    function updateLineNumbers(codeBlock, lineNumbersElement) {
        const lines = codeBlock.textContent.split('\n');
        lineNumbersElement.innerHTML = '';
        const maxLineNumber = lines.length;
        const digits = maxLineNumber.toString().length;
        const minWidth = `${digits}ch`;
        lineNumbersElement.style.minWidth = minWidth;
        codeBlock.style.paddingLeft = "1ch";
        lines.forEach((_, index) => {
            const lineNumber = document.createElement('div');
            lineNumber.style.lineHeight = '1.5';
            lineNumber.style.margin = '0';
            lineNumber.style.padding = '0';
            lineNumber.textContent = (index + 1).toString();
            lineNumbersElement.appendChild(lineNumber);
        });
    }

    function addLineNumbersInline(container, useLiveUpdates) {
        const codeBlock = container.querySelector('code');
        if (!codeBlock || container.querySelector('.line-numbers-inline')) return;
        container.style.position = 'relative';
        container.style.display = 'flex';
        container.style.alignItems = 'flex-start';
        container.style.padding = '0';
        container.style.margin = '0';
        container.style.overflowX = 'auto';
        container.style.overflowY = 'hidden';
        const lineNumbersElement = createLineNumbersElement();
        container.insertBefore(lineNumbersElement, codeBlock);
        if (useLiveUpdates) {
            updateLineNumbers(codeBlock, lineNumbersElement);
            let updateScheduled = false;
            const observer = new MutationObserver(() => {
                if (!updateScheduled) {
                    updateScheduled = true;
                    requestAnimationFrame(() => {
                        updateLineNumbers(codeBlock, lineNumbersElement);
                        updateScheduled = false;
                    });
                }
            });
            observer.observe(codeBlock, {
                childList: true,
                subtree: true,
                characterData: true,
            });
        } else {
            let updateTimeout;
            function debouncedUpdate() {
                clearTimeout(updateTimeout);
                updateTimeout = setTimeout(() => {
                    updateLineNumbers(codeBlock, lineNumbersElement);
                }, 500);
            }
            const observer = new MutationObserver(mutations => {
                let shouldUpdate = false;
                mutations.forEach(mutation => {
                    if (mutation.type === 'childList' || mutation.type === 'characterData') {
                        shouldUpdate = true;
                    }
                });
                if (shouldUpdate) {
                    debouncedUpdate();
                }
            });
            observer.observe(codeBlock, {
                childList: true,
                subtree: true,
                characterData: true,
            });
            debouncedUpdate();
        }
    }

    function observeCodeBlocks(useLiveUpdates) {
        const observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                if (mutation.addedNodes.length > 0) {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === 1) {
                            const codeContainers = node.querySelectorAll('div.overflow-y-auto');
                            codeContainers.forEach(container => addLineNumbersInline(container, useLiveUpdates));
                        }
                    });
                }
            });
        });
        observer.observe(document.body, {
            childList: true,
            subtree: true,
        });
        document.querySelectorAll('div.overflow-y-auto').forEach(container => {
            addLineNumbersInline(container, useLiveUpdates);
        });
    }

    observeCodeBlocks(liveLineNumbers);

    function registerMenu() {
        GM_registerMenuCommand(
            `Live line numbers: ${GM_getValue('liveLineNumbers', true) ? 'ON' : 'OFF'}`,
            toggleLiveLineNumbers
        );
    }

    function toggleLiveLineNumbers() {
        const isLive = GM_getValue('liveLineNumbers', true);
        GM_setValue('liveLineNumbers', !isLive);
        location.reload();
    }
})();

QingJ © 2025

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