concatenated raw chat log stumblechat

Automatic Moderation

// ==UserScript==
// @name         concatenated raw chat log stumblechat
// @namespace    http://tampermonkey.net/
// @version      1.13
// @description  Automatic Moderation
// @author       MeKLiN
// @match        https://stumblechat.com/room/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=stumblechat.com
// @grant        none
// @license      MIT
// ==/UserScript==
let webSocket;

(function() {
    'use strict';

    let selfHandleSet = false; // Variable to track if the 'self' handle has been set
    let selfHandle; // Variable to store the 'self' handle

    const handleUserMap = {}; // Initialize handleUserMap as an empty object
    // Define yourHandle variable
    const yourHandle = "myHandle"; // Replace "myHandle" with the actual handle

    function parseWebSocketMessage(message) {
        const parsedMessage = JSON.parse(message);
        if (parsedMessage.stumble === "join") {
            const { handle, username } = parsedMessage;
            if (!selfHandleSet) {
                // If 'self' handle hasn't been set yet, set it now
                selfHandle = handle;
                handleUserMap[handle] = "self"; // Set the first entry as 'self'
                selfHandleSet = true;
            } else {
                handleUserMap[handle] = username;
            }
            addUserToUserList({ handle, username });
            const joinMessage = `${username} joined the chat.`;
            displayWebSocketMessage(joinMessage);
        } else if (parsedMessage.stumble === "quit") {
            const handle = parsedMessage.handle;
            const username = handleUserMap[handle];
            if (username) {
                delete handleUserMap[handle];
                removeUserFromUserList(handle);
                const quitMessage = `${username} left the chat.`;
                displayWebSocketMessage(quitMessage);
            }
        } else if (parsedMessage.stumble === "msg") {
            // Handle additional changes to the user list for specific "msg" messages
        }
    }

let webSocketURL; // Global variable to store the WebSocket URL!

// Function to set up WebSocket listener
function setupWebSocketListener() {
    // Override WebSocket constructor to intercept WebSocket creation
    const originalWebSocket = window.WebSocket;
    window.WebSocket = function(url, protocols) {
        webSocket = new originalWebSocket(url, protocols); // Assign to global webSocket variable
        console.log('WebSocket URL:', webSocketURL);

        // Call original WebSocket constructor
        const ws = new originalWebSocket(url, protocols);

        // Event listener for receiving messages
        webSocket.addEventListener('message', event => {
            handleWebSocketMessage(event.data);
        });

        return webSocket;
    };
}

// WebSocket Listener: Override WebSocket constructor to intercept WebSocket creation
const originalWebSocket = window.WebSocket;
window.WebSocket = function(url, protocols) {

    // Call original WebSocket constructor
    const ws = new originalWebSocket(url, protocols);

    // Event listener for receiving messages
    ws.addEventListener('message', event => {
        const parsedMessage = JSON.parse(event.data);

        // Check if the message is a "joined" message
        if (parsedMessage.stumble === "joined") {
            // Extracting our own handle from the "self" object in the message
            const selfHandle = parsedMessage.self.handle;
            // Update handleUserMap and custom user list when a user joins
            const userList = parsedMessage.userlist;
            if (userList && userList.length > 0) {
                userList.forEach(user => {
                    // Check if the user being added is ourselves
                    const isSelf = user.handle === selfHandle;
                    // If it's our own user, update handleUserMap with our own handle
                    if (isSelf) {
                        handleUserMap[user.handle] = user.username || user.nick;
                        console.log('Found self, handleUserMap updated with self handle');
                    } else {
                        // If it's not ourselves, update the map with the new user
                        handleUserMap[user.handle] = user.username || user.nick;
                    }
                });
            }
        } else if (parsedMessage.stumble === "join") {
            // Handle join messages
            const { handle, username } = parsedMessage;
            if (handle !== yourHandle) {
                handleUserMap[handle] = username;
            }
        } else if (parsedMessage.stumble === "quit") {
            // Handle quit messages
            const handle = parsedMessage.handle;
            const username = handleUserMap[handle];
            if (username) {
                delete handleUserMap[handle];
                console.log('User left:', username);
            }
        } else if (parsedMessage.stumble === "msg") {
            // Handle message messages
            const { handle, text } = parsedMessage;
            const username = handleUserMap[handle] || handle;
            displayWebSocketMessage(event.data);
        }

        // Check if the message is a system message
        if (parsedMessage.stumble === "system") {
            const systemMessage = parsedMessage.message;
            if (systemMessage.startsWith('"Client Version:')) {
                console.log("System message detected, client version info received.");
            }
        }
    });

    return ws;
};



// Function to update handleUserMap with user data from the loaded file
function updateHandleUserMap(fileContent) {
    // Split the file content into lines
    const lines = fileContent.split('\n');

    // Iterate over each line to parse user data
    lines.forEach(line => {
        const userData = line.trim().split(' '); // Splitting by space to separate username and handle
        if (userData.length === 2) {
            const username = userData[0].trim();
            const handle = userData[1].trim();

            // Check if the handle already exists in the handleUserMap
            if (!handleUserMap.hasOwnProperty(handle)) {
                // Update user map with the new username and handle
                handleUserMap[handle] = username;
            }
        }
    });
}

// Function to get the user's own handle number (implement your own logic)
function getOwnHandle() {
    // Implement your logic to retrieve the user's own handle number
    // For demonstration purposes, return a hardcoded value
    return "123456"; // Replace with your actual handle number
 }

// WebSocket listener for handling messages
function handleWebSocketMessage(message) {
    const parsedMessage = JSON.parse(message);
    const ownHandle = getOwnHandle(); // Function to get the user's own handle number

    if (parsedMessage.stumble === "msg" && ownHandle === parsedMessage.handle) {
        const text = parsedMessage.text;
        // No ban logic, so just checking if it's a message
        // You can handle other message types here if necessary
    }
}

// Call functions to set up WebSocket listener
setupWebSocketListener();


// List of blocked usernames
const blockedUsers = ['AccountNameHere', 'hell']; // Modify this list as needed

// Track if blocking is enabled
let isBlockingEnabled = true;

// Flag to control whether messages should be concatenated or displayed individually
let isMessagesConcatenated = true;

// Function to toggle between concatenated and individual message displays
function toggleConcatenation() {
    isMessagesConcatenated = !isMessagesConcatenated;
    console.log(`Message display mode: ${isMessagesConcatenated ? "Concatenated" : "Individual"}`);

    // If we want to clear all previous concatenated messages when switching modes
    const webSocketMessagesDiv = document.getElementById("webSocketMessages");
    if (webSocketMessagesDiv) {
        webSocketMessagesDiv.innerHTML = ''; // Clear all messages
    }

    // You can decide whether to clear the messages completely or preserve the chat history
    // based on your specific requirements.
}
// Modify the `displayWebSocketMessage` function to handle both concatenated and individual modes
function displayWebSocketMessage(message) {
    const parsedMessage = JSON.parse(message);
    if (parsedMessage.stumble === "join") {
        const { handle, username } = parsedMessage;
        handleUserMap[handle] = username;
        addUserToUserList({ handle, username }, "join");
    } else if (parsedMessage.stumble === "msg") {
        const { handle, text } = parsedMessage;
        const username = handleUserMap[handle] || handle;

        if (isMessagesConcatenated) {
            // Handle concatenated messages
            const webSocketMessagesDiv = document.getElementById("webSocketMessages");
            if (webSocketMessagesDiv) {
                let existingMessage = webSocketMessagesDiv.querySelector(`#message-${handle}`);
                if (existingMessage) {
                    existingMessage.textContent += ` . ${text}`;
                } else {
                    const messageDiv = document.createElement("div");
                    messageDiv.id = `message-${handle}`;
                    messageDiv.textContent = `${username}: ${text}`;
                    webSocketMessagesDiv.appendChild(messageDiv);
                }
                webSocketMessagesDiv.scrollTop = webSocketMessagesDiv.scrollHeight;
            }
        } else {
            // Handle individual messages (unconcatenated)
            const webSocketMessagesDiv = document.getElementById("webSocketMessages");
            if (webSocketMessagesDiv) {
                const messageDiv = document.createElement("div");
                messageDiv.id = `message-${handle}`;
                messageDiv.textContent = `${username}: ${text}`;
                webSocketMessagesDiv.appendChild(messageDiv);
                webSocketMessagesDiv.scrollTop = webSocketMessagesDiv.scrollHeight;
            }
        }

        // Additional logic for handling commands
        if (text === "#join") {
            console.log("join");
        } else if (text === "#icon") {
            console.log("icon");
        } else if (text === "#tokes") {
            console.log("tokes");
            TokesSendEnter();
        } else if (text.startsWith("#ai ")) {
            console.log("ai");
            const word = text.substring(4);
            console.log("Word after '#ai':", word);
        }
    } else if (parsedMessage.stumble === "joined") {
        const userList = parsedMessage.userlist;
        if (userList && userList.length > 0) {
            userList.forEach(user => {
                const username = user.username || user.nick;
                handleUserMap[user.handle] = username;
                addUserToUserList({ handle: user.handle, username }, "joined");
            });
        }
    } else if (parsedMessage.stumble === "quit") {
        const handle = parsedMessage.handle;
        const username = handleUserMap[handle];
        if (username) {
            delete handleUserMap[handle];
            removeUserFromUserList(handle);
            console.log('line 323 user departed')
        }
    }
}

// Create a button to toggle concatenation mode
const toggleConcatenateButton = document.createElement("button");
toggleConcatenateButton.textContent = "T";
toggleConcatenateButton.style.position = "fixed";
toggleConcatenateButton.style.top = "40px"; // Below the checkbox
toggleConcatenateButton.style.left = "10px";
toggleConcatenateButton.style.zIndex = "9999"; // Ensure the button is on top of other elements

// Add event listener to toggle the concatenation mode
toggleConcatenateButton.addEventListener("click", toggleConcatenation);

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

// Create a checkbox to toggle blocking functionality
const blockMessagesCheckbox = document.createElement("input");
blockMessagesCheckbox.type = "checkbox";
blockMessagesCheckbox.checked = isBlockingEnabled; // Initially checked
blockMessagesCheckbox.id = "blockMessagesCheckbox";

// Create a label for the checkbox
const checkboxLabel = document.createElement("label");
checkboxLabel.setAttribute("for", "blockMessagesCheckbox");
checkboxLabel.textContent = "Block messages from ignored users";

// Style the checkbox and label
blockMessagesCheckbox.style.position = "fixed";
blockMessagesCheckbox.style.top = "10px";
blockMessagesCheckbox.style.left = "10px";
blockMessagesCheckbox.style.zIndex = "9999"; // Ensure the checkbox is on top of other elements

checkboxLabel.style.position = "fixed";
checkboxLabel.style.top = "10px";
checkboxLabel.style.left = "40px";
checkboxLabel.style.zIndex = "9999"; // Ensure the label is on top of other elements
checkboxLabel.style.fontSize = "14px";
checkboxLabel.style.color = "white";

// Add event listener to the checkbox to toggle the blocking functionality
blockMessagesCheckbox.addEventListener("change", function () {
    isBlockingEnabled = blockMessagesCheckbox.checked;
    console.log(`Message blocking ${isBlockingEnabled ? "enabled" : "disabled"}`);
});

// Append the checkbox and label to the body
document.body.appendChild(blockMessagesCheckbox);
document.body.appendChild(checkboxLabel);


// Function to add user to user list with appropriate icon based on user type
function addUserToUserList(user, userType) {
    const userList = document.getElementById("userList");
    if (!userList) return;

    const userItem = document.createElement("div");
    userItem.textContent = `${user.username}`;

    // Define the default dot color and icon
    let dotColor; // Default dot color
    let icon; // Default icon

    // Set dot color and icon based on user type
    if (userType === "self") {
        console.log('[function addUserToList] found "self" for purple dot. Applying!')
        dotColor = "purple";
        icon = "🟣";

    } else if (userType === "join") {
        console.log('[function addUserToList] found "join" for green dot. Applying!')
        dotColor = "green";
        icon = "🟢";

    } else if (userType === "joined") {
        console.log('[function addUserToList] found "joined" for blue dot. Applying!')
        dotColor = "blue";
        icon = "🔵";

    } else {
        // For other user types, default to red dot
        console.log('[function addUserToList] found "userList" for green dot. Applying!')
        dotColor = "green";
        icon = "🟢";
        //dotColor = "red"; // FOR QUIT MSG
        //icon = "🔴";
    }

    // Add colored dot based on user status
    const dot = document.createElement("span");
    dot.textContent = icon;
    dot.style.color = dotColor;
    userItem.appendChild(dot);

    // Add custom icon for the user
    if (user.icon) {
        const customIcon = document.createElement("span");
        customIcon.textContent = user.icon;
        customIcon.style.marginLeft = "5px"; // Adjust margin as needed
        userItem.appendChild(customIcon);
    }

    userList.appendChild(userItem); // Append user item to the user list

    // If user is not active and not yourself, show popup for 5 seconds
    //if (!user.active && user.handle !== yourHandle) {
        //const popup = document.createElement("div");
        //popup.textContent = "WELCOME TO STUMBLECHAT YEOPARDY!";
        //popup.style.fontSize = "48px";
        //popup.style.position = "fixed";
        //popup.style.top = "50%";
        //popup.style.left = "50%";
        //popup.style.transform = "translate(-50%, -50%)";
        //popup.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
        //popup.style.color = "white";
        //popup.style.padding = "10px";
        //popup.style.borderRadius = "5px";
        //document.body.appendChild(popup);

}
// Function to update handleUserMap without affecting the user list div
function updateUserListAndMapOnJoin(user) {
    // Update handleUserMap with the new user
    handleUserMap[user.handle] = user.username || user.nick; // Derive username from handle or nick
}

// Call the function to update the user list
function updateUserListOnMessage(userList) {
    return function(message) {
        const parsedMessage = JSON.parse(message);
        if (parsedMessage.stumble === "join" || parsedMessage.stumble === "msg" || parsedMessage.stumble === "joined") {
            // Add user to user list
            addUserToUserList(parsedMessage);
        }
    };
}

// Function to create WebSocket messages div
function createWebSocketMessagesDiv() {
    const div = document.createElement("div");
    div.id = "webSocketMessages";
    div.style.position = "fixed";
    div.style.height = "100%";
    div.style.paddingLeft = "2px";
    div.style.visibility = "visible"; // Ensure the div is visible
    div.style.willChange = "transform";
    div.style.boxSizing = "border-box";
    div.style.overflowX = "hidden";
    div.style.overflowY = "auto";
    div.style.color = "#ffffff"; // Set font color to white
    div.style.padding = "10px"; // Example padding
    div.style.zIndex = "2"; // Set a higher z-index value for the WebSocket messages div

    // Additional styles for specific scenarios
    div.style.display = "flex";
    div.style.flexDirection = "column";
    div.style.justifyContent = "flex-end";
    div.style.fontSize = "18px";

    div.style.whiteSpace = "pre-wrap"; // Allow text to wrap within the container
    div.style.wordWrap = "break-word"; // Allow long words to break and wrap

    // Locate the chat-position div
    const chatPositionDiv = document.getElementById("chat-position");
    if (chatPositionDiv) {
        // Append custom div to the chat-position div
        chatPositionDiv.appendChild(div);
    } else {
        // If chat-position div not found, append to document body as fallback
        document.body.appendChild(div);
    }
}

// Call the function to create the WebSocket messages div
createWebSocketMessagesDiv();

function toggleWebSocketMessagesDiv() {
    const webSocketMessagesDiv = document.getElementById("webSocketMessages");
    const chatContentDiv = document.getElementById("chat-content");
    if (webSocketMessagesDiv && chatContentDiv) {
        // Check the current display style of the WebSocket messages div
        const webSocketMessagesDisplayStyle = webSocketMessagesDiv.style.display;

        // Toggle the display of both divs based on the current display style of the WebSocket messages div
        if (webSocketMessagesDisplayStyle === "none") {
            // If WebSocket messages div is hidden, show it and hide chat content div
            webSocketMessagesDiv.style.display = "block";
            chatContentDiv.style.display = "none";
        } else {
            // If WebSocket messages div is visible, hide it and show chat content div
            webSocketMessagesDiv.style.display = "none";
            chatContentDiv.style.display = "block";
        }
    }
}
// This line keeps the default style and hides the socket log by default remove for default wss log
toggleWebSocketMessagesDiv()

// Add a button to toggle visibility of WebSocket messages div
const toggleMessagesButton = document.createElement("button");
toggleMessagesButton.textContent = "M";
toggleMessagesButton.style.position = "fixed";
toggleMessagesButton.style.right = "0px";
toggleMessagesButton.style.bottom = "0px";
toggleMessagesButton.addEventListener("click", toggleWebSocketMessagesDiv);
document.body.appendChild(toggleMessagesButton);

// Call the function to create the user list div


 // Function to remove user from custom user list
 function removeUserFromUserList(handle) {
    const userList = document.getElementById("userList");
    if (userList) {
        const userElements = userList.querySelectorAll("div");
        userElements.forEach(userElement => {
            if (userElement.textContent.includes(`(${handle})`)) {
                userElement.remove();
                console.log('line 490 user remove/depart')
            }
        });
    }
}



    // Function to clear messages
    function clr() {
        const webSocketMessagesDiv = document.getElementById("webSocketMessages");
        if (webSocketMessagesDiv) {
            webSocketMessagesDiv.innerHTML = "";
        }
    }

// Function to apply font size to WebSocket messages
function applyFontSize(fontSize) {
    const webSocketMessagesDiv = document.getElementById("webSocketMessages");
    if (webSocketMessagesDiv) {
        webSocketMessagesDiv.style.fontSize = `${fontSize}px`;
    }
}

/* Additional compacting styles */
/*@-moz-document url-prefix("https://stumblechat.com/room/") {*/
// Compact message styles
const compactStyles = `
.message .nickname ~ .content {
    display: inline-block;
    top: -7px;
    position: relative;
    margin-left: 2px;
    margin-right: 1em;
}
.content + .content {
    display: inline-block!important;
    margin-right: 1em;
}
.message .nickname ~ .content span {
    line-height: 1.5em;
}
`;

// Apply compact styles to the document
const style = document.createElement('style');
style.textContent = compactStyles;
document.head.appendChild(style);
/*}*/

// Function to send the "Tokes in 20 seconds" message and simulate Enter key press
function TokesSendEnter() {
    // Insert predefined text
    const textArea = document.getElementById("textarea");
    textArea.value += 'Tokes in 20 seconds\n';

    // Simulate Enter key press
    const event = new KeyboardEvent('keypress', {
        key: 'Enter',
        code: 'Enter',
        keyCode: 13,
        which: 13,
        bubbles: true
    });
    textArea.dispatchEvent(event);

    // Set a timeout to display "tokes started" message after 20 seconds
    setTimeout(function() {
        textArea.value += 'tokes started\n'; // Send message indicating tokes has started

        // Simulate Enter key press again
        textArea.dispatchEvent(event);
    }, 20000); // 20 seconds delay
}


// Function to create input element
function createInputBox() {
    const input = document.createElement('input');
    input.type = 'text';
    input.placeholder = 'Type your message...';
    input.style.position = 'fixed'; // Set position to fixed
    input.style.bottom = '50px'; // Adjust bottom position as needed
    input.style.left = '10px'; // Adjust left position as needed
    input.style.zIndex = '9999'; // Set a high z-index value to ensure it's above other elements

    // Add event listener to detect when user presses Enter key
    input.addEventListener('keypress', function(event) {
        if (event.key === 'Enter') {
            const msg = input.value.trim();
            // Check if the message starts with '/kick'
            if (msg.startsWith('/kick')) {
                // Extract the username from the input text
                const username = msg.substring(6).trim(); // Assuming '/kick ' is 6 characters long
                // Check if the username exists in the handleUserMap
                const handle = Object.keys(handleUserMap).find(key => handleUserMap[key] === username);
                if (handle) {
                    // Send kick message to WebSocket server
                    webSocket.send(JSON.stringify({
                        "stumble": "kick",
                        "handle": handle
                    }));
                } else {
                    console.error('Username not found');
                }
                // Clear the input field after sending the message
                input.value = "";
            }
            // Check if the message starts with '/ban'
            else if (msg.startsWith('/ban')) {
                // Extract the username from the input text
                const username = msg.substring(5).trim(); // Assuming '/ban ' is 5 characters long
                // Check if the username exists in the handleUserMap
                const handle = Object.keys(handleUserMap).find(key => handleUserMap[key] === username);
                if (handle) {
                    // Send ban message to WebSocket server
                    webSocket.send(JSON.stringify({
                        "stumble": "ban",
                        "handle": handle
                    }));
                } else {
                    console.error('Username not found');
                }
                // Clear the input field after sending the message
                input.value = "";
            }
            // If the message is not a kick or ban command, send it as a regular message
            else {
                // Send normal message via sendMessage function
                sendMessage();
            }
        }
    });

    return input;
}

// Call the function to create input box
const input = createInputBox();

// Append input to the document body or wherever you want it to appear
document.body.appendChild(input);

// Function to handle sending message
function sendMessage() {
    // Get the value of the input
    const msg = input.value.trim();

    // Check if the WebSocket is not null and the message is not empty
    if (webSocket !== undefined && msg !== "") { // Check if webSocket is defined
        // Send the message via WebSocket
        webSocket.send(JSON.stringify({
            "stumble": "msg",
            "text": msg
        }));

        // Clear the input field after sending the message
        input.value = "";
    }
}

// Add event listener to input for the 'Enter' key press to send message
input.addEventListener('keydown', function(event) {
    if (event.key === 'Enter') {
        sendMessage();
    }
});





})();

QingJ © 2025

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