ChatGPT Message Queue

Queue messages when ChatGPT is still composing responses

// ==UserScript==
// @name        ChatGPT Message Queue
// @match       https://chat.openai.com/*
// @match       https://chatgpt.com/*
// @description Queue messages when ChatGPT is still composing responses
// @version 0.0.1.20250319105457
// @namespace https://greasyfork.org/users/1435046
// ==/UserScript==

(function() {
    'use strict';
    
    let queueCount = 0;
    let queueObserver;
    let processingMessage = false;
    const queueDisplay = document.createElement('div');
    
    // Minimal UI setup
    queueDisplay.innerHTML = `
        <span>Queue: ${queueCount}</span>
        <button id="queue-reset">×</button>
    `;
    queueDisplay.style.cssText = `
        position:fixed; bottom:100px; right:20px;
        background:rgba(0,0,0,0.7); color:white;
        padding:5px 10px; border-radius:4px; display:flex; gap:8px;
    `;
    document.body.appendChild(queueDisplay);
    
    // Reset queue count when button is clicked
    document.getElementById('queue-reset').addEventListener('click', () => {
        queueCount = 0;
        queueDisplay.children[0].textContent = `Queue: ${queueCount}`;
    });
    
    // Function to start queue processing
    function startQueueObserver() {
        if (queueObserver) return;  // Prevent duplicate observers
        
        queueObserver = new MutationObserver(() => {
            // Only proceed if we have messages in queue and we're not currently processing
            if (queueCount > 0 && !processingMessage) {
                const sendButton = document.querySelector('[data-testid="send-button"]');
                const textArea = document.getElementById('prompt-textarea');
                
                // Only click if the send button is enabled and textarea is accessible
                if (sendButton && !sendButton.disabled && textArea) {
                    processingMessage = true;
                    
                    // Wait for the current response to complete
                    const checkCompletion = setInterval(() => {
                        // Look for indicators that the AI has finished responding
                        const isResponding = document.querySelector('.result-streaming') || 
                                          document.querySelector('[data-testid="stop-generating"]');
                        
                        if (!isResponding) {
                            clearInterval(checkCompletion);
                            
                            // Wait a bit for the UI to fully update
                            setTimeout(() => {
                                // Now we can send the next message
                                sendButton.click();
                                queueCount--;
                                queueDisplay.children[0].textContent = `Queue: ${queueCount}`;
                                processingMessage = false;
                                
                                // Stop observing when queue is empty
                                if (queueCount === 0) {
                                    queueObserver.disconnect();
                                    queueObserver = null;
                                }
                            }, 500);
                        }
                    }, 1000);
                }
            }
        });
        
        queueObserver.observe(document.body, {childList: true, subtree: true});
    }
    
    // Core logic: Monitor input field
    new MutationObserver((_, observer) => {
        const textarea = document.getElementById('prompt-textarea');
        if (textarea && !textarea.dataset.queuer) {
            textarea.dataset.queuer = true;
            textarea.addEventListener('keydown', e => {
                if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
                    // Allow DOM update
                    setTimeout(() => {
                        if (textarea.textContent.trim()) {
                            queueCount++;
                            queueDisplay.children[0].textContent = `Queue: ${queueCount}`;
                            startQueueObserver(); // Start processing queue
                        }
                    }, 100);
                }
            });
        }
    }).observe(document.body, {childList: true, subtree: true});
})();