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