// ==UserScript==
// @name Meklin Shutdownchat Script
// @version 1.5
// @description Modified Shutdownchat, unmatched scripts, brace to be thunderstruck
// @author MeKLiN
// @namespace https://greasyfork.org/en/scripts/483405-meklin-shutdownchat-script
// @match https://www.shutdown.chat/rooms*
// @icon https://www.google.com/s2/favicons?sz=64&domain=shutdown.chat
// @license MIT
// @grant none
// @exclude https://www.shutdown.chat/profiles*
// @exclude https://www.shutdown.chat/manage*
// @run-at document-start
// @require https://cdnjs.cloudflare.com/ajax/libs/jshint/2.9.7/jshint.js
// @require https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.5/es6-shim.min.js
// ==/UserScript==
console.log("MSS 1.1 STARTED");
debugger;
// Function to create a button to clear the JSON local saved cache
function createClearCacheButton() {
console.log("createClearCacheButton function is called");
var clearCacheButton = document.createElement("button");
clearCacheButton.innerText = "clr";
clearCacheButton.style.position = "fixed";
clearCacheButton.style.top = "50px";
clearCacheButton.style.left = "10px";
clearCacheButton.addEventListener("click", function () {
// Clear the JSON local saved cache
localStorage.removeItem('blocked_uuids');
showNotification("Cache cleared. Please refresh the page.");
});
// Check if the body is available
if (document.body) {
// Append the clearCacheButton to the body
document.body.appendChild(clearCacheButton);
} else {
// If the body is not available, wait for DOMContentLoaded event
document.addEventListener("DOMContentLoaded", function () {
// Append the clearCacheButton to the body
document.body.appendChild(clearCacheButton);
});
}
}
// Call the function to create the clear cache button
createClearCacheButton();
// Function to create a button to collapse the view
function createCollapseButton() {
console.log("createCollapseButton function is called");
var collapseButton = document.createElement("button");
// Set the inner HTML with an SVG and additional text
collapseButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M8 4v5l-2.5-1.5L3 9V4l5-2zm8 0l5 2v5l-2.5-1.5L16 9V4zM3 11l3.5-1.5L8 11V9L3 7zm13 0l3.5-1.5L21 11V9l-5-2z"/>
</svg>min`;
// Adjust the font size of the text
collapseButton.style.fontSize = "12px"; // Adjust the font size as needed
collapseButton.style.position = "fixed";
collapseButton.style.top = "90px";
collapseButton.style.left = "10px";
// Function to append the button to the body
function appendButtonToBody() {
document.body.appendChild(collapseButton);
}
// Check if the body is available
if (document.body) {
// Append the collapseButton to the body
appendButtonToBody();
} else {
// If the body is not available, wait for DOMContentLoaded event
document.addEventListener("DOMContentLoaded", appendButtonToBody);
}
collapseButton.addEventListener("click", function () {
// Toggle visibility of the chatbox
var chatbox = document.querySelector('.chatbox');
chatbox.style.display = (chatbox.style.display === 'none' || chatbox.style.display === '') ? 'block' : 'none';
});
// Get the chatbox element after creating the button
var chatbox = document.querySelector('.chatbox');
// Check if the chatbox element is found
if (chatbox) {
// Initialize the observer if not already initialized
if (!observer) {
observer = new MutationObserver(function (mutations) {
// Handle mutations
console.log("Mutations:", mutations);
// You can add your logic to handle mutations here
});
}
// Start observing the chatbox
observer.observe(chatbox, { childList: true });
} else {
console.error("Chatbox element not found. Cannot add event listener.");
}
}
// Call the function to create the collapse button
createCollapseButton();
var blocked_uuids = JSON.parse(localStorage.getItem('blocked_uuids')) || [];
function getNickname(fcuserSpan) {
if (!fcuserSpan) return;
// Check if fcuserSpan is a direct child of p
var isDirectChild = fcuserSpan.parentNode.nodeName === "P";
var nickname;
if (isDirectChild) {
nickname = fcuserSpan.innerText.replace(/[:\-]/g, '').trim();
} else {
// If not a direct child, assume it's under an anchor tag (a) in the user list
nickname = fcuserSpan.parentNode.querySelector('.fcuser').innerText.replace(/[:\-]/g, '').trim();
}
return nickname;
}
// Function to handle the new chat messages
function handleNewChatMessages() {
// Get the chatbox element
var chatbox = document.querySelector('.chatbox');
if (!chatbox) {
console.error("Chatbox element not found. Cannot add event listener.");
return;
}
// Continue with handling new chat messages
var chatboxElems = chatbox.getElementsByTagName('p');
for (var i = 0; i < chatboxElems.length; i++) {
var chatElem = chatboxElems[i];
if (!chatElem.handled) {
chatElem.handled = true;
// Remove text containing 'roll'
if (chatElem.textContent.toLowerCase().includes('roll')) {
chatElem.style.display = 'none'; // hide the message
}
// Alter messages of the type .fs_3
if (chatElem.classList.contains('fs_3')) {
chatElem.style.fontSize = '12px';
chatElem.style.color = 'white';
}
// Check if the user is ignored
var fcuserSpan = chatElem.querySelector('.nm.fcuser, .nm.fcmod, .user');
var uuid = fcuserSpan ? fcuserSpan.dataset.uuid : null;
console.log("fcuserSpan:", fcuserSpan); // Add this line to log fcuserSpan
console.log("uuid:", uuid); // Add this line to log uuid
if (uuid) {
// Check if the user is ignored
var isIgnored = blocked_uuids.includes(uuid);
// Modify the appearance based on whether the user is ignored or not
if (isIgnored) {
chatElem.style.display = 'none'; // hide the message
} else {
// Add an "ignore" button to the user menu
addIgnoreButtonToUserMenu(uuid);
}
}
}
}
}
// Function to add an "ignore" button to the user menu
function addIgnoreButtonToUserMenu(chatElem) {
// Check if the user menu exists
var userMenu = document.querySelector('.usermenu');
if (userMenu && chatElem && chatElem.querySelector) {
// Check if the user is already ignored
var uuid = chatElem.querySelector('.nm.fcuser, .nm.fcmod')?.dataset.uuid;
var isIgnored = blocked_uuids.includes(uuid);
// Create a button for either ignoring or unignoring the user
var ignoreButton = document.createElement('button');
ignoreButton.textContent = isIgnored ? 'Unignore' : 'Ignore';
// Add an event listener to handle ignoring/unignoring the user
ignoreButton.addEventListener('click', function () {
if (isIgnored) {
// Unignore the user
unignoreUser(uuid);
} else {
// Ignore the user
ignoreUser(uuid);
}
});
// Append the button to the user menu
userMenu.appendChild(ignoreButton);
} else {
console.error("Invalid userMenu, chatElem, or querySelector is not supported. Conditions: userMenu=" + userMenu + ", chatElem=" + chatElem + ", chatElem.querySelector=" + (chatElem ? chatElem.querySelector : null));
}
}
// Function to observe mutations in the chatbox
function observeChatboxMutations() {
var chatbox = document.querySelector('.chatbox');
if (chatbox instanceof Node) {
// Create a mutation observer to monitor changes in the chatbox
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
mutation.addedNodes.forEach(function (node) {
if (node.nodeName === "P" && node.dataset.t === "c") {
// Your logic for handling new chat messages goes here
}
});
});
});
// Start observing the chatbox
observer.observe(chatbox, { childList: true });
} else {
console.error("Chatbox element not found or is not a valid Node. Cannot add event listener.");
}
}
// Wait for the DOM to be fully loaded before setting up the MutationObserver
document.addEventListener('DOMContentLoaded', function () {
// Call the initial function to start handling new chat messages
handleNewChatMessages();
// Call the function to observe mutations in the chatbox
observeChatboxMutations();
});
// Function to ignore a user
function ignoreUser(uuid) {
// Add your logic here to handle ignoring a user
// For example, you can add the user's UUID to the blocked_uuids array
blocked_uuids.push(uuid);
// Save the updated blocked_uuids to localStorage
localStorage.setItem('blocked_uuids', JSON.stringify(blocked_uuids));
// You can also add additional logic as needed
console.log("Ignoring user with UUID:", uuid);
}
// Function to unignore a user
function unignoreUser(uuid) {
blocked_uuids = blocked_uuids.filter(function (blockedUuid) {
return blockedUuid !== uuid;
});
// Add additional logic as needed
console.log("Unignoring user with UUID:", uuid);
}
// Call the initial function to start handling new chat messages
handleNewChatMessages();
// Get the chatbox element
var chatbox = document.querySelector(".chatbox");
// Log the chatbox element to the console
console.log("Chatbox element:", chatbox);
// Check if the chatbox element is found
if (chatbox instanceof Node) {
// Check if the chatbox element is found
if (!observer) {
observer = new MutationObserver(function (mutations) {
// Handle mutations
console.log("Mutations:", mutations);
// You can add your logic to handle mutations here
});
}
// Start observing the chatbox
observer.observe(chatbox, { childList: true });
} else {
console.error("Chatbox element not found or is not a valid Node. Cannot add event listener.");
}
// Function to get the user UUID from a chat message
function getUserUUIDFromChatMessage(messageNode) {
var uuidElement = messageNode.querySelector('.nm.fcuser, .nm.fcmod');
if (uuidElement) {
return uuidElement.dataset.uuid;
} else {
console.error("UUID element not found in the chat message:", messageNode);
return null;
}
}
// Function to handle different types of chat messages
function handleChatMessage(node) {
// Check if the node is a chat message
if (node.nodeName === "P" && node.dataset.t === "c") {
// Get the uuid of the user who sent the message
var uuid = getUserUUIDFromChatMessage(node);
if (uuid) {
console.log("Found message with UUID:", uuid);
// Check if the uuid is in the blocked list
if (blocked_uuids.includes(uuid)) {
console.log("Blocking message with UUID:", uuid);
// Hide the message
node.style.display = "none";
} else {
// Alter messages of the type .fs_3
if (node.classList.contains('fs_3')) {
node.style.fontSize = '12px';
node.style.color = 'white';
}
// Add an "ignore" button to the user menu
addIgnoreButtonToUserMenu(node);
}
}
} else if (node.nodeName === "P" && node.querySelector(".sysmsg.fcsys")) {
// Handle system messages
handleSystemMessage(node);
}
}
// Function to handle system messages
function handleSystemMessage(systemNode) {
// Move system messages to the bottom right in their own DIV
var systemDiv = document.createElement("div");
systemDiv.className = "system-message";
systemDiv.style.position = "fixed";
systemDiv.style.bottom = "10px";
systemDiv.style.right = "10px";
systemDiv.style.backgroundColor = "#f0f0f0";
systemDiv.style.padding = "10px";
systemDiv.appendChild(systemNode.cloneNode(true));
document.body.appendChild(systemDiv);
}
// Create a mutation observer to monitor changes in the chatbox
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
mutation.addedNodes.forEach(function (node) {
handleChatMessage(node);
// Check if the node is a chat message
if (node.nodeName === "P" && node.dataset.t === "c") {
// Get the uuid of the user who sent the message
var uuid = getUserUUIDFromChatMessage(node);
if (uuid) {
console.log("Found message with UUID:", uuid);
// Check if the uuid is in the blocked list
if (blocked_uuids.includes(uuid)) {
console.log("Blocking message with UUID:", uuid);
// Hide the message
node.style.display = "none";
} else {
// Alter messages of the type .fs_3
if (node.classList.contains('fs_3')) {
node.style.fontSize = '12px';
node.style.color = 'white';
}
// Add an "ignore" button to the user menu
addIgnoreButtonToUserMenu(node);
}
}
}
});
});
});
// Start observing the chatbox
observer.observe(chatbox, { childList: true });
// Function to show a notification
function showNotification(message) {
var notification = document.createElement("div");
notification.innerHTML = `<div style="position: fixed; bottom: 10px; left: 10px; background-color: #000000; padding: 10px; border: 1px solid #ccc; border-radius: 5px; font-size: 12px; color: #C0FF00; opacity: 1; transition: opacity 2s ease-in-out;">${message}</div>`;
document.body.appendChild(notification);
// Set a timeout to fade out the notification
setTimeout(function () {
notification.style.opacity = 0;
}, 2000); // Adjust the timeout value as needed
// Remove the notification from the DOM after fading out
setTimeout(function () {
document.body.removeChild(notification);
}, 3000); // Adjust the timeout value to match the fade-out duration
}
// Function to block/unblock a user
function blockUser(uuid) {
console.log("blockUser function is called");
var index = blocked_uuids.indexOf(uuid);
if (index !== -1) {
// User is already blocked, so unblock
blocked_uuids.splice(index, 1);
showNotification("User unblocked!");
} else {
// User is not blocked, so block
blocked_uuids.push(uuid);
showNotification("User blocked!");
}
// Save the updated blocked_uuids to localStorage
localStorage.setItem('blocked_uuids', JSON.stringify(blocked_uuids));
}
// Function to create a button to view the ignore list
function createIgnoreListButton() {
console.log("createIgnoreListButton function is called");
var ignoreListButton = document.createElement("button");
ignoreListButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M20 18V8a6 6 0 0 0-12 0v10h12zM12 2C6.48 2 2 6.48 2 12v10h2V12a5.978 5.978 0 0 1 5.985-6H12V2zm8.293 2.293a1 1 0 0 1 1.414 0l1.414 1.414a1 1 0 0 1 0 1.414L19.414 10l3.707 3.707a1 1 0 0 1 0 1.414l-1.414 1.414a1 1 0 0 1-1.414 0L18 13.414l-3.707 3.707a1 1 0 0 1-1.414 0l-1.414-1.414a1 1 0 0 1 0-1.414L14.586 12 10.88 8.293a1 1 0 0 1 0-1.414L12.294 5.465a1 1 0 0 1 1.414 0z"/></svg>lst`;
ignoreListButton.style.position = "fixed";
ignoreListButton.style.top = "10px";
ignoreListButton.style.left = "10px";
ignoreListButton.addEventListener("click", function () {
// Display the ignore list (you can customize this part)
alert("Ignore List:\n" + blocked_uuids.join(", "));
});
document.body.appendChild(ignoreListButton);
}
// Call the function to create the ignore list button
createIgnoreListButton();
// Get the user list element
var userlist = document.querySelector(".userlist");
// Create the block and ignore buttons and append them to each user
var users = userlist.querySelectorAll(".fcuser");
users.forEach(function (user) {
var uuid = user.dataset.uuid;
// Create the block button
var blockButton = document.createElement("button");
blockButton.innerText = "Block";
blockButton.addEventListener("click", function() {
blockUser(uuid);
});
// Create the ignore button with a unique class
var ignoreButton = document.createElement("button");
ignoreButton.innerText = "Ignore";
ignoreButton.setAttribute("data-btntype", "ignore"); // Set a new attribute for identification
ignoreButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M20 18V8a6 6 0 0 0-12 0v10h12zM12 2C6.48 2 2 6.48 2 12v10h2V12a5.978 5.978 0 0 1 5.985-6H12V2zm8.293 2.293a1 1 0 0 1 1.414 0l1.414 1.414a1 1 0 0 1 0 1.414L19.414 10l3.707 3.707a1 1 0 0 1 0 1.414l-1.414 1.414a1 1 0 0 1-1.414 0L18 13.414l-3.707 3.707a1 1 0 0 1-1.414 0l-1.414-1.414a1 1 0 0 1 0-1.414L14.586 12 10.88 8.293a1 1 0 0 1 0-1.414L12.294 5.465a1 1 0 0 1 1.414 0z"/></svg>`;
ignoreButton.style.marginLeft = "5px";
ignoreButton.style.cursor = "pointer";
// Add a unique class to the ignore button
ignoreButton.classList.add("ignoreButtonClass");
ignoreButton.addEventListener("click", function () {
// Dynamically fetch the user UUID when the "Ignore" button is clicked
var clickedUserUUID = user.dataset.uuid;
blockUser(clickedUserUUID);
});
// Create a container div for the buttons
var buttonContainer = document.createElement("div");
buttonContainer.style.display = "flex";
buttonContainer.style.alignItems = "center";
// Append the buttons to the container
buttonContainer.appendChild(blockButton);
buttonContainer.appendChild(ignoreButton);
// Append the container to the user element
user.parentElement.appendChild(buttonContainer);
});
// usermenu block button event listener:
document.querySelector('.usermenu button[data-btntype="block"]').addEventListener('click', function() {
console.log("User menu block button clicked");
// Get the parent element of the button, assuming it contains user-related data
var userContainer = this.closest('.user-container');
// Assuming the user UUID is stored in a data attribute called data-uuid
var userUUID = userContainer ? userContainer.dataset.uuid : null;
// Check if userUUID is not null before blocking
if (userUUID) {
// Now you have the user UUID, and you can proceed to block the user
blockUser(userUUID);
} else {
console.error("User UUID not found. Unable to block user.");
}
});
// Function to create an ignore button in the user menu
function createIgnoreButton() {
console.log("createIgnoreButton function is called");
// Check if the ignore button is already created
var ignoreButton = document.querySelector('.usermenu button[data-btntype="ignore"]');
if (!ignoreButton) {
ignoreButton = document.createElement("button");
ignoreButton.innerText = "Ignore";
ignoreButton.setAttribute("data-btntype", "ignore"); // Set a new attribute for identification
ignoreButton.style.display = "block";
ignoreButton.style.marginTop = "5px"; // Adjust the styling as needed
// Insert the ignore button into the user menu
var userMenu = document.querySelector('.usermenu');
if (userMenu) {
userMenu.insertBefore(ignoreButton, userMenu.firstChild);
// Add click event directly to the button
ignoreButton.addEventListener("click", function () {
// Log to console to check if the button click is being registered
console.log("Ignore button clicked");
// Invoke the function to get the user UUID from the user list
var userUUID = getUserUUIDFromUserList();
// Check if the user UUID is found
if (userUUID) {
blockUser(userUUID);
} else {
console.error("User UUID not found. Ignoring user without blocking.");
}
});
} else {
console.error("User menu not found.");
}
}
}
// Call the function to create the ignore button in the user menu
createIgnoreButton();
// Function to get the user UUID from the chat log
function getUserUUIDFromChatLog() {
var chatLog = document.querySelector('.chatbox');
if (chatLog) {
// Find the first chat message in the log
var firstChatMessage = chatLog.querySelector('p[data-t="c"]');
if (firstChatMessage) {
// Get the UUID from the first chat message
var uuidElement = firstChatMessage.querySelector('.nm.fcuser, .nm.fcmod');
if (uuidElement) {
return uuidElement.dataset.uuid;
} else {
// Handle the case where UUID element is not found
console.error("UUID element not found in the first chat message:", firstChatMessage);
return null;
}
} else {
// Handle the case where no chat messages are found
console.error("No chat messages found in the chat log.");
return null;
}
} else {
// Handle the case where the chatbox element is not found
console.error("Chatbox element not found.");
return null;
}
}
// Function to get the user UUID from the user list within FreeChat context
function getUserUUIDFromUserList() {
var userContainer = document.querySelector("#chat > div.fc > div.gridbox_list > div.userlist p.user.fcuser[data-uuid]");
if (userContainer) {
return userContainer.dataset.uuid;
} else {
// If user container is not found, set up a MutationObserver to wait for changes
var observer = new MutationObserver(function (mutations) {
userContainer = document.querySelector("#chat > div.fc > div.gridbox_list > div.userlist p.user.fcuser[data-uuid]");
if (userContainer) {
console.log("User container found after mutation.");
console.log("User UUID: ", userContainer.dataset.uuid);
// Stop observing once the user container is found
observer.disconnect();
}
});
// Start observing changes in the user list
observer.observe(document.querySelector("#chat > div.fc > div.gridbox_list > div.userlist"), { childList: true, subtree: true });
console.error("User container not found in the user list within FreeChat context. Waiting for mutations...");
return null;
}
}
// Create the ignore list div once and append the content dynamically
var ignoreListDiv = document.createElement("div");
ignoreListDiv.style.position = "fixed";
ignoreListDiv.style.bottom = "10px"; // Move to the bottom
ignoreListDiv.style.left = "10px";
ignoreListDiv.style.backgroundColor = "white"; // Adjust styling as needed
ignoreListDiv.style.padding = "10px";
ignoreListDiv.style.border = "1px solid black"; // Add border for visibility
ignoreListDiv.style.fontSize = "12px"; // Set font size to 12px
// Create a heading for the ignore list
var ignoreListHeading = document.createElement("h3");
ignoreListHeading.innerText = "Ignore List";
ignoreListDiv.appendChild(ignoreListHeading);
// Create a list to display ignored users
var ignoreList = document.createElement("ul");
ignoreList.style.listStyleType = "none"; // Remove default list styling
ignoreListDiv.appendChild(ignoreList);
// Append the ignore list div to the body
document.body.appendChild(ignoreListDiv);
// Function to create a list item with the ignore list entry and remove button
function createIgnoreListItem(uuid, username) {
var listItem = document.createElement("li");
listItem.innerText = `${username} (${uuid})`;
// Create a remove button for each entry
var removeButton = document.createElement("button");
removeButton.innerText = "Remove";
removeButton.addEventListener("click", function () {
// Remove the entry when the button is clicked
removeIgnoreEntry(uuid);
});
// Append the remove button to the list item
listItem.appendChild(removeButton);
// Append the list item to the ignore list
ignoreList.appendChild(listItem);
}
// Function to refresh the ignore list display
function refreshIgnoreList() {
// Clear the existing content
ignoreList.innerHTML = "";
// Populate the ignore list with entries and remove buttons
blocked_uuids.forEach(function (uuid) {
createIgnoreListItem(uuid);
});
}
// Populate the ignore list with entries and remove buttons
blocked_uuids.forEach(function (uuid) {
createIgnoreListItem(uuid);
});
// Function to handle removing an entry from the ignore list
function removeIgnoreEntry(uuid) {
var index = blocked_uuids.indexOf(uuid);
if (index !== -1) {
// Remove the entry from the ignore list
blocked_uuids.splice(index, 1);
// Refresh the ignore list display after removal
refreshIgnoreList();
}
}
// Function to save blocked_uuids to a text file
function saveToTextFile() {
var textToSave = blocked_uuids.join('\n');
var blob = new Blob([textToSave], { type: 'text/plain' });
var link = document.createElement('a');
link.download = 'ignore_list.txt';
link.href = window.URL.createObjectURL(blob);
link.onclick = function () {
document.body.removeChild(link);
};
link.style.display = 'none';
document.body.appendChild(link);
link.click();
}
// Function to load blocked_uuids from a text file
function loadFromTextFile() {
var input = document.createElement('input');
input.type = 'file';
input.accept = '.txt';
input.onchange = function (event) {
var file = event.target.files[0];
if (file) {
var reader = new FileReader();
reader.onload = function (e) {
// Parse the content of the file and update blocked_uuids
blocked_uuids = e.target.result.split('\n').map(function (uuid) {
return uuid.trim();
});
// Update the ignore list display
refreshIgnoreList();
};
reader.readAsText(file);
}
};
input.click();
}
// Function to create a button to save and load ignore list
function createSaveLoadButtons() {
var saveButton = document.createElement("button");
saveButton.innerText = "Save to Text File";
saveButton.addEventListener("click", function () {
saveToTextFile();
});
var loadButton = document.createElement("button");
loadButton.innerText = "Load from Text File";
loadButton.addEventListener("click", function () {
loadFromTextFile();
});
var buttonContainer = document.createElement("div");
buttonContainer.style.marginTop = "10px";
buttonContainer.appendChild(saveButton);
buttonContainer.appendChild(loadButton);
// Append the button container to the ignore list div
ignoreListDiv.appendChild(buttonContainer);
}
// Call the function to create the save and load buttons
createSaveLoadButtons();