Hunter

Blacklist

  1. // ==UserScript==
  2. // @name Hunter
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.94
  5. // @description Blacklist
  6. // @author MeKLiN
  7. // @match https://stumblechat.com/room/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=stumblechat.com
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15. const handleUserMap = {}; // Initialize handleUserMap as an empty object
  16. // Define yourHandle variable
  17. const yourHandle = "myHandle"; // Replace "myHandle" with the actual handle
  18.  
  19. function parseWebSocketMessage(message) {
  20. const parsedMessage = JSON.parse(message);
  21. if (parsedMessage.stumble === "joined") {
  22. const userList = parsedMessage.userlist;
  23. if (userList && userList.length > 0) {
  24. userList.forEach(user => {
  25. const username = user.username || user.nick;
  26. handleUserMap[user.handle] = username;
  27. addUserToUserList({ handle: user.handle, username });
  28. });
  29. }
  30. const joinMessage = "A user or users joined the chat."; // Example join message
  31. displayWebSocketMessage(joinMessage);
  32. } else if (parsedMessage.stumble === "join") {
  33. const { handle, username } = parsedMessage;
  34. handleUserMap[handle] = username;
  35. addUserToUserList({ handle, username });
  36. const joinMessage = `${username} joined the chat.`;
  37. displayWebSocketMessage(joinMessage);
  38. } else if (parsedMessage.stumble === "quit") {
  39. const handle = parsedMessage.handle;
  40. const username = handleUserMap[handle];
  41. if (username) {
  42. delete handleUserMap[handle];
  43. removeUserFromUserList(handle);
  44. const quitMessage = `${username} left the chat.`;
  45. displayWebSocketMessage(quitMessage);
  46. }
  47. } else if (parsedMessage.stumble === "msg") {
  48. // Handle additional changes to the user list for specific "msg" messages
  49.  
  50. }
  51. }
  52.  
  53. // WebSocket Listener: Override WebSocket constructor to intercept WebSocket creation
  54. const originalWebSocket = window.WebSocket;
  55. window.WebSocket = function(url, protocols) {
  56. console.log('WebSocket URL:', url);
  57.  
  58. // Call original WebSocket constructor
  59. const ws = new originalWebSocket(url, protocols);
  60.  
  61. // Event listener for receiving messages
  62. ws.addEventListener('message', event => {
  63. const parsedMessage = JSON.parse(event.data);
  64. // Check if the message is a "joined" message
  65. if (parsedMessage.stumble === "joined") {
  66. // Extracting our own handle from the "self" object in the message
  67. const selfHandle = parsedMessage.self.handle;
  68. // Update handleUserMap and custom user list when a user joins
  69. const userList = parsedMessage.userlist;
  70. if (userList && userList.length > 0) {
  71. userList.forEach(user => {
  72. // Check if the user being added is ourselves
  73. const isSelf = user.handle === selfHandle;
  74. // If it's our own user, update handleUserMap and display our own handle in the user list
  75. if (isSelf) {
  76. // Update handleUserMap with our own handle and username
  77. handleUserMap[user.handle] = user.username || user.nick;
  78. // Add our own handle to the custom user list with purple icon
  79. addUserToUserList({
  80. username: user.username,
  81. handle: user.handle,
  82. active: true, // We just joined, so we're considered active
  83. icon: "🟣" // Purple icon for our own user entry
  84. }, "self");
  85. } else {
  86. // If it's not our own user, proceed as usual and add them to the user list
  87. updateUserListAndMapOnJoin(user);
  88. }
  89. });
  90. }
  91. } else if (parsedMessage.stumble === "join") {
  92. // Handle join messages
  93. const { handle, username } = parsedMessage;
  94. // Check if the user being added is not ourselves
  95. if (handle !== yourHandle) {
  96. handleUserMap[handle] = username;
  97. addUserToUserList({ handle, username }, "join");
  98. }
  99. } else if (parsedMessage.stumble === "quit") {
  100. // Handle quit messages
  101. const handle = parsedMessage.handle;
  102. const username = handleUserMap[handle];
  103. if (username) {
  104. delete handleUserMap[handle];
  105. removeUserFromUserList(handle);
  106. setTimeout(() => {
  107. removeUserFromUserList(handle);
  108. }, 30000); // 30 seconds delay
  109. addUserToUserList({ handle, username }, "quit");
  110. }
  111. } else if (parsedMessage.stumble === "msg") {
  112. // Handle message messages
  113. const { handle, text } = parsedMessage;
  114. const username = handleUserMap[handle] || handle;
  115. displayWebSocketMessage(event.data);
  116. }
  117.  
  118. // Check if the message is a system message
  119. if (parsedMessage.stumble === "system") {
  120. const systemMessage = parsedMessage.message;
  121.  
  122. // Check if the system message contains the client version
  123. if (systemMessage.startsWith('"Client Version:')) {
  124. // Save the user list to a file
  125. console.log("sysmsgdetected");
  126. }
  127. }
  128. });
  129.  
  130. return ws;
  131. };
  132.  
  133. // Function to create user list div
  134. function createUserListDiv() {
  135. const userListDiv = document.createElement("div");
  136. userListDiv.id = "userList";
  137. userListDiv.style.position = "absolute"; // Change to absolute positioning
  138. userListDiv.style.top = "100px"; // Adjust top position as needed
  139. userListDiv.style.left = "10px"; // Adjust left position as needed
  140. userListDiv.style.height = "calc(100% - 100px)"; // Adjust height to fill remaining space
  141. userListDiv.style.overflowY = "auto";
  142. userListDiv.style.color = "#ffffff";
  143. userListDiv.style.padding = "10px";
  144. userListDiv.style.zIndex = "2"; // Set a higher z-index value
  145. userListDiv.style.display = "none"; // Hide the custom user list by default
  146. return userListDiv;
  147. }
  148.  
  149. // Function to append new content to users.txt file
  150. function appendToUserListFile(newContent) {
  151. // Create a Blob object containing the new content
  152. const blob = new Blob([newContent], { type: "text/plain" });
  153.  
  154. // Create a temporary anchor element to trigger the download
  155. const a = document.createElement("a");
  156. const url = URL.createObjectURL(blob);
  157. a.href = url;
  158. a.download = "users.txt";
  159.  
  160. // Simulate a click on the anchor element to start the download
  161. document.body.appendChild(a);
  162. a.click();
  163.  
  164. // Remove the temporary anchor element
  165. document.body.removeChild(a);
  166.  
  167. // Release the Object URL
  168. URL.revokeObjectURL(url);
  169. }
  170.  
  171. // Function to save user list to users.txt file
  172. function saveUserListToFile() {
  173. // Extracting user information from handleUserMap
  174. const users = [];
  175. for (const handle in handleUserMap) {
  176. const username = handleUserMap[handle];
  177. users.push(`${username} (${handle}) B`); // Append 'B' to the handle
  178. }
  179.  
  180. // Convert the user list to a string
  181. const userListString = users.join("\n");
  182.  
  183. // Append the new content to the existing users.txt file
  184. appendToUserListFile(userListString);
  185. }
  186.  
  187. // Function to display the user list (handle map)
  188. function displayUserList() {
  189. const userList = document.getElementById("userListDisplay");
  190. if (userList) {
  191. // Clear the user list before updating
  192. userList.innerHTML = "";
  193. // Iterate over the handleUserMap and display each handle and username
  194. for (const handle in handleUserMap) {
  195. const username = handleUserMap[handle];
  196. const listItem = document.createElement("li");
  197. listItem.textContent = `${username} (${handle})`;
  198. userList.appendChild(listItem);
  199. }
  200. }
  201. }
  202.  
  203. // Function to create and append the pop-up window overlay with input menu and close button
  204. function createUserOverlay() {
  205. const overlay = document.createElement("div");
  206. overlay.id = "overlay";
  207. overlay.style.position = "fixed";
  208. overlay.style.top = "50%";
  209. overlay.style.width = "80%"; // container width
  210. overlay.style.left = "50%";
  211. overlay.style.transform = "translate(-50%, -50%)";
  212. overlay.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
  213. overlay.style.zIndex = "9999";
  214. overlay.style.padding = "20px";
  215. overlay.style.textAlign = "center";
  216.  
  217. const closeButton = document.createElement("button");
  218. closeButton.textContent = "Close";
  219. closeButton.style.position = "absolute";
  220. closeButton.style.top = "10px";
  221. closeButton.style.right = "10px";
  222. closeButton.addEventListener("click", () => {
  223. overlay.remove(); // Remove the overlay when the close button is clicked
  224. });
  225. overlay.appendChild(closeButton);
  226.  
  227. const userListContainer = document.createElement("div");
  228. userListContainer.style.display = "flex";
  229. userListContainer.style.justifyContent = "space-between"; // Align columns to left and right edges
  230. overlay.appendChild(userListContainer);
  231.  
  232. const userListHandleMap = document.createElement("ul");
  233. userListHandleMap.id = "userListHandleMap";
  234. userListHandleMap.style.listStyleType = "none";
  235. userListHandleMap.style.padding = "0";
  236. userListHandleMap.style.width = "50%"; // Adjust the percentage based on your layout needs
  237. userListHandleMap.style.color = "lime";
  238. userListHandleMap.style.backgroundColor = "black";
  239. userListContainer.appendChild(userListHandleMap);
  240.  
  241. // Second column for data from loadUsersFromFile() function
  242. const userListLoadedFromFile = document.createElement("ul");
  243. userListLoadedFromFile.id = "userListLoadedFromFile"; // Add an id to reference the user list later
  244. userListLoadedFromFile.style.listStyleType = "none";
  245. userListLoadedFromFile.style.padding = "0";
  246. userListLoadedFromFile.style.color = "cyan"; // Set font color to cyan
  247. userListLoadedFromFile.style.backgroundColor = "black"; // Set background color to black
  248. userListLoadedFromFile.style.flex = "1"; // Use flex to make the column expand to fill available space
  249. userListLoadedFromFile.style.marginLeft = "10px"; // Add margin to separate from the first column
  250. userListContainer.appendChild(userListLoadedFromFile);
  251.  
  252. function populateUserListHandleMap() {
  253. userListHandleMap.innerHTML = "";
  254. for (const handle in handleUserMap) {
  255. if (handleUserMap.hasOwnProperty(handle)) {
  256. const listItem = document.createElement("li");
  257. listItem.textContent = `${handleUserMap[handle]} (${handle})`;
  258. listItem.style.marginBottom = "5px";
  259. userListHandleMap.appendChild(listItem);
  260. }
  261. }
  262. }
  263.  
  264. function populateUserListLoadedFromFile(loadedUsers) {
  265. userListLoadedFromFile.innerHTML = "";
  266. loadedUsers.forEach(user => {
  267. const listItem = document.createElement("li");
  268. listItem.textContent = `${user.username} (${user.handle})`;
  269. listItem.style.marginBottom = "5px";
  270. userListLoadedFromFile.appendChild(listItem);
  271. });
  272. }
  273.  
  274. populateUserListHandleMap();
  275.  
  276. const inputLabel = document.createElement("label");
  277. inputLabel.textContent = "Add 'B' to user handles:";
  278. inputLabel.style.color = "#ffffff";
  279. inputLabel.style.marginTop = "20px";
  280. overlay.appendChild(inputLabel);
  281.  
  282. const inputField = document.createElement("input");
  283. inputField.id = "handleInput";
  284. inputField.type = "text";
  285. inputField.style.margin = "10px auto";
  286. inputField.style.display = "block";
  287. overlay.appendChild(inputField);
  288.  
  289. const applyButton = document.createElement("button");
  290. applyButton.textContent = "Apply";
  291. applyButton.style.margin = "10px auto";
  292. applyButton.style.display = "block";
  293. overlay.appendChild(applyButton);
  294.  
  295. document.body.appendChild(overlay);
  296. }
  297.  
  298.  
  299.  
  300. // Function to create and append the input box overlay with user list display
  301. function createTartOverlay() {
  302. const overlay = document.createElement("div");
  303. overlay.id = "overlay";
  304. overlay.style.position = "fixed";
  305. overlay.style.bottom = "50px";
  306. overlay.style.left = "0px";
  307. overlay.style.zIndex = "9999";
  308. overlay.style.display = "flex";
  309. overlay.style.flexDirection = "column";
  310. overlay.style.alignItems = "flex-start";
  311.  
  312. const userList = document.createElement("ul");
  313. userList.id = "userList";
  314. userList.style.listStyleType = "none";
  315. overlay.appendChild(userList);
  316.  
  317. const inputField = document.createElement("input");
  318. inputField.id = "commandInput";
  319. inputField.type = "text";
  320. inputField.placeholder = "Type command here...";
  321. inputField.style.margin = "10px";
  322. inputField.style.width = "200px"; // Adjust width as needed
  323. overlay.appendChild(inputField);
  324.  
  325. // Listen for input changes
  326. inputField.addEventListener("input", () => {
  327. const command = inputField.value.trim();
  328. if (command.startsWith("#ban")) {
  329. const handle = command.replace("#ban", "").trim();
  330. if (handle !== "") {
  331. addBToHandleOrUsername(handle);
  332. inputField.value = ""; // Clear input field after processing command
  333. }
  334. }
  335. // Add more command listeners here as needed
  336. });
  337.  
  338. document.body.appendChild(overlay);
  339. }
  340.  
  341. // Function to create buttons for other overlays
  342. function createButtonsForOverlays() {
  343. // Create button for Tart overlay
  344. const tartButton = document.createElement("button");
  345. tartButton.textContent = "Open Tart Overlay";
  346. tartButton.style.position = "fixed";
  347. tartButton.style.bottom = "50px";
  348. tartButton.style.left = "210px"; // Adjust position as needed
  349. tartButton.style.zIndex = "9999";
  350. tartButton.addEventListener("click", createTartOverlay);
  351. document.body.appendChild(tartButton);
  352.  
  353. // Create button for User overlay
  354. const userButton = document.createElement("button");
  355. userButton.textContent = "Open User Overlay";
  356. userButton.style.position = "fixed";
  357. userButton.style.bottom = "50px";
  358. userButton.style.left = "420px"; // Adjust position as needed
  359. userButton.style.zIndex = "9999";
  360. userButton.addEventListener("click", createUserOverlay);
  361. document.body.appendChild(userButton);
  362. }
  363.  
  364. // Call the function to create buttons for other overlays
  365. createButtonsForOverlays();
  366.  
  367. // Function to create and append the input box overlay
  368. function createBox() {
  369. const overlay = document.createElement("div");
  370. overlay.id = "overlay";
  371. overlay.style.position = "fixed";
  372. overlay.style.bottom = "50px";
  373. overlay.style.left = "0px";
  374. overlay.style.zIndex = "9999";
  375.  
  376. const inputField = document.createElement("input");
  377. inputField.id = "commandInput";
  378. inputField.type = "text";
  379. inputField.placeholder = "Type command here...";
  380. inputField.style.margin = "10px";
  381. inputField.style.width = "200px"; // Adjust width as needed
  382. overlay.appendChild(inputField);
  383.  
  384. let commandBuffer = ""; // Buffer to store the command until Enter is pressed
  385.  
  386. // Listen for input changes
  387. inputField.addEventListener("input", () => {
  388. commandBuffer = inputField.value.trim(); // Update command buffer with current input
  389. });
  390.  
  391. // Listen for keydown event
  392. inputField.addEventListener("keydown", (event) => {
  393. if (event.key === "Enter") {
  394. // Process the command when Enter key is pressed
  395. if (commandBuffer.startsWith("#ban ")) {
  396. const usernameOrHandle = commandBuffer.replace("#ban ", "").trim();
  397. if (usernameOrHandle !== "") {
  398. addBToHandleOrUsername(usernameOrHandle);
  399. inputField.value = ""; // Clear input field after processing command
  400. } else {
  401. alert("Username or handle not provided!");
  402. }
  403. } else {
  404. alert("Invalid command! Please use '#ban usernameOrHandle'");
  405. }
  406. commandBuffer = ""; // Clear the command buffer after processing
  407. }
  408. });
  409.  
  410. document.body.appendChild(overlay);
  411. }
  412.  
  413. // Call the function to create the input box overlay
  414. createBox();
  415.  
  416. function addBToHandleOrUsername(handleOrUsername) {
  417. let handle = handleOrUsername;
  418. let found = false;
  419.  
  420. // Check if the handle exists in the handleUserMap
  421. if (handleUserMap.hasOwnProperty(handleOrUsername)) {
  422. handle = handleOrUsername;
  423. found = true;
  424. }
  425.  
  426. if (found) {
  427. // Add 'B' next to the handle number
  428. handleUserMap[handle] += " B";
  429. // Update the user list display
  430. displayUserList();
  431. // Save the updated user list to the file
  432. saveUserListToFile();
  433. } else {
  434. alert("User not found!");
  435. }
  436. }
  437.  
  438. // Function to load users from the users.txt file
  439. function loadUsersFromFile() {
  440. const fileInput = document.createElement('input');
  441. fileInput.type = 'file';
  442. fileInput.accept = '.txt';
  443.  
  444. fileInput.addEventListener('change', function() {
  445. const file = fileInput.files[0];
  446. const reader = new FileReader();
  447.  
  448. reader.onload = function(event) {
  449. const fileContent = event.target.result;
  450. // Update handleUserMap with user data from the loaded file
  451. updateHandleUserMap(fileContent);
  452. // Display loaded users
  453. console.log("Loaded Users:");
  454. for (const handle in handleUserMap) {
  455. if (handleUserMap.hasOwnProperty(handle)) {
  456. console.log(`${handleUserMap[handle]} (${handle})`);
  457. }
  458. }
  459. // Define and populate loadedUsers based on handleUserMap
  460. const loadedUsers = Object.keys(handleUserMap).map(handle => ({
  461. handle: handle,
  462. username: handleUserMap[handle]
  463. }));
  464. // Example usage of addBToHandleOrUsername with loadedUsers
  465. addBToHandleOrUsername("handleOrUsername", loadedUsers);
  466. };
  467.  
  468. reader.readAsText(file);
  469. });
  470.  
  471. fileInput.click();
  472. }
  473.  
  474. // Function to update handleUserMap with user data from the loaded file
  475. function updateHandleUserMap(fileContent) {
  476. // Split the file content into lines
  477. const lines = fileContent.split('\n');
  478.  
  479. // Iterate over each line to parse user data
  480. lines.forEach(line => {
  481. const userData = line.trim().split(' '); // Splitting by space to separate username and handle
  482. if (userData.length === 2) {
  483. const username = userData[0].trim();
  484. const handle = userData[1].trim();
  485.  
  486. // Check if the handle already exists in the handleUserMap
  487. if (!handleUserMap.hasOwnProperty(handle)) {
  488. // Update user map with the new username and handle
  489. handleUserMap[handle] = username;
  490. }
  491. }
  492. });
  493. }
  494.  
  495.  
  496. // Function to update the user list display
  497. function updateUserListDisplay() {
  498. // Get the user list element
  499. const userList = document.getElementById("userList");
  500. if (userList) {
  501. // Update the display with modified handleUserMap
  502. userList.innerHTML = ""; // Clear the user list
  503. for (const handle in handleUserMap) {
  504. const username = handleUserMap[handle];
  505. // Append the user to the user list with 'B' if present
  506. const listItem = document.createElement("li");
  507. listItem.textContent = `${username} (${handle})`;
  508. userList.appendChild(listItem);
  509. }
  510. }
  511. }
  512.  
  513. // WebSocket listener for handling messages
  514. function handleWebSocketMessage(message) {
  515. const parsedMessage = JSON.parse(message);
  516. const ownHandle = getOwnHandle(); // Function to get the user's own handle number
  517.  
  518. if (parsedMessage.stumble === "msg" && ownHandle === parsedMessage.handle) {
  519. const text = parsedMessage.text;
  520. if (text.startsWith("#ban")) {
  521. // Extract the handle from the message
  522. const handleToBan = text.replace("#ban", "").trim();
  523. if (handleToBan !== "") {
  524. // Check if the handle exists in the handleUserMap
  525. if (handleUserMap.hasOwnProperty(handleToBan)) {
  526. // Add 'B' next to the handle number
  527. handleUserMap[handleToBan] += " B";
  528. // Update the user list display
  529. updateUserListDisplay();
  530. // Update the users.txt file
  531. saveUserListToFile();
  532. } else {
  533. alert("Handle not found!");
  534. }
  535. } else {
  536. alert("Invalid handle!");
  537. }
  538. }
  539. }
  540. }
  541. // Function to get the user's own handle number (implement your own logic)
  542. function getOwnHandle() {
  543. // Implement your logic to retrieve the user's own handle number
  544. // For demonstration purposes, return a hardcoded value
  545. return "123456"; // Replace with your actual handle number
  546. }
  547. // Function to set up WebSocket listener
  548. function setupWebSocketListener() {
  549. // Override WebSocket constructor to intercept WebSocket creation
  550. const originalWebSocket = window.WebSocket;
  551. window.WebSocket = function(url, protocols) {
  552. console.log('WebSocket URL:', url);
  553.  
  554. // Call original WebSocket constructor
  555. const ws = new originalWebSocket(url, protocols);
  556.  
  557. // Event listener for receiving messages
  558. ws.addEventListener('message', event => {
  559. handleWebSocketMessage(event.data);
  560. });
  561.  
  562. return ws;
  563. };
  564. }
  565.  
  566. // Call functions to set up overlay, WebSocket listener, and initial user list display
  567.  
  568. setupWebSocketListener();
  569. updateUserListDisplay();
  570.  
  571. // Function to display WebSocket messages and update user list
  572. function displayWebSocketMessage(message) {
  573. const parsedMessage = JSON.parse(message);
  574. if (parsedMessage.stumble === "join") {
  575. // Handle join messages: Extract handle and username from the message
  576. const { handle, username } = parsedMessage;
  577. // Map handle to username in handleUserMap
  578. handleUserMap[handle] = username;
  579. // Add the user to the custom user list with the appropriate icon (join user)
  580. addUserToUserList({ handle, username }, "join");
  581. } else if (parsedMessage.stumble === "msg") {
  582. // Handle message messages: Extract handle and text from the message
  583. const { handle, text } = parsedMessage;
  584. // Retrieve username from handleUserMap or use handle if not found
  585. const username = handleUserMap[handle] || handle;
  586. // Display the message in the WebSocket messages div
  587. const webSocketMessagesDiv = document.getElementById("webSocketMessages");
  588. if (webSocketMessagesDiv) {
  589. // Append the message with a newline character
  590. webSocketMessagesDiv.textContent += `${username}: ${text}\n`;
  591. // Scroll to the bottom of the messages div
  592. webSocketMessagesDiv.scrollTop = webSocketMessagesDiv.scrollHeight;
  593. }
  594.  
  595. // Additional logic for handling commands
  596. if (text === "#join") {
  597. console.log("join");
  598. // Add your logic here
  599. } else if (text === "#icon") {
  600. console.log("icon");
  601. // Add your logic here
  602. } else if (text === "#tokes") {
  603. console.log("tokes");
  604. // Call your tokes function here
  605. TokesSendEnter();
  606. } else if (text.startsWith("#ai ")) {
  607. console.log("ai");
  608. // Extract the word after "#ai"
  609. const word = text.substring(4);
  610. console.log("Word after '#ai':", word);
  611. // Call your AI function here with the extracted word
  612. DoAi(word); // Adjust parameters as needed
  613. }
  614. } else if (parsedMessage.stumble === "joined") {
  615. // Handle joined messages: Add users to handleUserMap and custom user list
  616. const userList = parsedMessage.userlist;
  617. if (userList && userList.length > 0) {
  618. userList.forEach(user => {
  619. // Extract username from either "username" or "nick"
  620. const username = user.username || user.nick;
  621. // Map handle to username in handleUserMap
  622. handleUserMap[user.handle] = username;
  623. // Add the user to the custom user list with the appropriate icon
  624. addUserToUserList({ handle: user.handle, username }, "joined");
  625. });
  626. }
  627. } else if (parsedMessage.stumble === "quit") {
  628. // Handle quit messages: Remove users from handleUserMap and custom user list
  629. const handle = parsedMessage.handle;
  630. const username = handleUserMap[handle];
  631. if (username) {
  632. // Remove the handle from handleUserMap
  633. delete handleUserMap[handle];
  634. // Remove the user from the custom user list
  635. removeUserFromUserList(handle);
  636. }
  637. }
  638. }
  639.  
  640.  
  641.  
  642. // Function to add user to user list with appropriate icon based on user type
  643. function addUserToUserList(user, userType) {
  644. const userList = document.getElementById("userList");
  645. if (!userList) return;
  646.  
  647. const userItem = document.createElement("div");
  648. userItem.textContent = `${user.username}`;
  649.  
  650. // Define the default dot color and icon
  651. let dotColor = "red"; // Default dot color
  652. let icon = "🔴"; // Default icon for inactive users
  653.  
  654. // Set dot color and icon based on user type
  655. if (userType === "self") {
  656. dotColor = "purple"; // Purple for self user
  657. icon = "🟣"; // Purple circle icon
  658. } else if (userType === "join") {
  659. dotColor = "blue"; // Blue for join user
  660. icon = "🔵"; // Blue circle icon
  661. } else if (userType === "joined") { // "self" user type listener for user list"
  662. dotColor = "green"; // Green for joined user
  663. icon = "🟢"; // Green circle icon
  664. }
  665.  
  666. // Add colored dot based on user status
  667. const dot = document.createElement("span");
  668. dot.textContent = icon;
  669. dot.style.color = dotColor;
  670. userItem.appendChild(dot);
  671.  
  672. // Add custom icon for the user
  673. if (user.icon) {
  674. const customIcon = document.createElement("span");
  675. customIcon.textContent = user.icon;
  676. customIcon.style.marginLeft = "5px"; // Adjust margin as needed
  677. userItem.appendChild(customIcon);
  678. }
  679.  
  680. userList.appendChild(userItem); // Append user item to the user list
  681.  
  682. // If user is not active and not yourself, show popup for 5 seconds
  683. //if (!user.active && user.handle !== yourHandle) {
  684. //const popup = document.createElement("div");
  685. //popup.textContent = "WELCOME TO STUMBLECHAT YEOPARDY!";
  686. //popup.style.fontSize = "48px";
  687. //popup.style.position = "fixed";
  688. //popup.style.top = "50%";
  689. //popup.style.left = "50%";
  690. //popup.style.transform = "translate(-50%, -50%)";
  691. //popup.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
  692. //popup.style.color = "white";
  693. //popup.style.padding = "10px";
  694. //popup.style.borderRadius = "5px";
  695. //document.body.appendChild(popup);
  696. }
  697. // Function to update handleUserMap and add users to custom user list
  698. function updateUserListAndMapOnJoin(user) {
  699. // Update handleUserMap with the new user
  700. handleUserMap[user.handle] = user.username || user.nick; // Derive username from handle or nick
  701. // Add the new user to the custom user list
  702. addUserToUserList(user);
  703. }
  704.  
  705. // Call the function to update the user list
  706. function updateUserListOnMessage(userList) {
  707. return function(message) {
  708. const parsedMessage = JSON.parse(message);
  709. if (parsedMessage.stumble === "join" || parsedMessage.stumble === "msg" || parsedMessage.stumble === "joined") {
  710. // Add user to user list
  711. addUserToUserList(parsedMessage);
  712. }
  713. };
  714. }
  715.  
  716. // Function to create WebSocket messages div
  717. function createWebSocketMessagesDiv() {
  718. const div = document.createElement("div");
  719. div.id = "webSocketMessages";
  720. div.style.position = "relative";
  721. div.style.height = "25%";
  722. div.style.paddingLeft = "2px";
  723. div.style.visibility = "visible"; // Ensure the div is visible
  724. div.style.willChange = "transform";
  725. div.style.boxSizing = "border-box";
  726. div.style.overflowX = "hidden";
  727. div.style.overflowY = "auto";
  728. div.style.color = "#ffffff"; // Set font color to white
  729. div.style.padding = "10px"; // Example padding
  730. div.style.zIndex = "2"; // Set a higher z-index value for the WebSocket messages div
  731.  
  732. // Additional styles for specific scenarios
  733. div.style.display = "flex";
  734. div.style.flexDirection = "column";
  735. div.style.justifyContent = "flex-end";
  736. div.style.fontSize = "18px";
  737.  
  738. div.style.whiteSpace = "pre-wrap"; // Allow text to wrap within the container
  739. div.style.wordWrap = "break-word"; // Allow long words to break and wrap
  740.  
  741. // Locate the chat-position div
  742. const chatPositionDiv = document.getElementById("chat-position");
  743. if (chatPositionDiv) {
  744. // Append custom div to the chat-position div
  745. chatPositionDiv.appendChild(div);
  746. } else {
  747. // If chat-position div not found, append to document body as fallback
  748. document.body.appendChild(div);
  749. }
  750. }
  751.  
  752. // Call the function to create the WebSocket messages div
  753. createWebSocketMessagesDiv();
  754.  
  755. // Call the function to create the user list div
  756. const userListDiv = createUserListDiv();
  757. const chatContainer = document.getElementById("chat-container");
  758. if (chatContainer) {
  759. chatContainer.appendChild(userListDiv); // Append to chat container instead
  760. } else {
  761. document.body.appendChild(userListDiv);
  762. }
  763.  
  764. // Function to remove user from custom user list
  765. function removeUserFromUserList(handle) {
  766. const userList = document.getElementById("userList");
  767. if (userList) {
  768. const userElements = userList.querySelectorAll("div");
  769. userElements.forEach(userElement => {
  770. if (userElement.textContent.includes(`(${handle})`)) {
  771. userElement.remove();
  772. }
  773. });
  774. }
  775. }
  776.  
  777. // Function to toggle visibility of custom user list
  778. function toggleCustomUserList() {
  779. const userListDiv = document.getElementById("userList");
  780. if (userListDiv) {
  781. userListDiv.style.display = userListDiv.style.display === "none" ? "block" : "none";
  782. }
  783. }
  784.  
  785. // Add a button to toggle visibility of custom user list
  786. const toggleButton = document.createElement("button");
  787. toggleButton.textContent = "U";
  788. toggleButton.style.position = "fixed";
  789. toggleButton.style.top = "10px";
  790. toggleButton.style.left = "10px";
  791. toggleButton.addEventListener("click", toggleCustomUserList);
  792. document.body.appendChild(toggleButton);
  793.  
  794. // Function to clear messages
  795. function clr() {
  796. const webSocketMessagesDiv = document.getElementById("webSocketMessages");
  797. if (webSocketMessagesDiv) {
  798. webSocketMessagesDiv.innerHTML = "";
  799. }
  800. }
  801.  
  802. // Function to create fadeaway popup text with "WELCOME" message
  803. function showWelcomePopupText() {
  804. const popup = document.createElement("div");
  805. popup.textContent = "WELCOME";
  806. popup.classList.add("fadeaway-popup");
  807. document.body.appendChild(popup);
  808.  
  809. // Remove the popup after 3 seconds
  810. setTimeout(() => {
  811. popup.remove();
  812. }, 3000); // 3 seconds delay
  813. }
  814.  
  815. // Function to create SVG animation
  816. function createSVGAnimation() {
  817. // Create SVG element
  818. const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  819. svg.setAttribute("width", "100");
  820. svg.setAttribute("height", "100");
  821.  
  822. // Create rectangle inside SVG
  823. const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
  824. rect.setAttribute("width", "100");
  825. rect.setAttribute("height", "100");
  826. rect.setAttribute("fill", "blue");
  827. svg.appendChild(rect);
  828.  
  829. // Append SVG to body
  830. document.body.appendChild(svg);
  831.  
  832. // Animate SVG
  833. const animation = document.createElementNS("http://www.w3.org/2000/svg", "animate");
  834. animation.setAttribute("attributeName", "x");
  835. animation.setAttribute("from", "-100");
  836. animation.setAttribute("to", "100%");
  837. animation.setAttribute("dur", "5s");
  838. animation.setAttribute("repeatCount", "indefinite");
  839. rect.appendChild(animation);
  840. }
  841. // Call the function to show the welcome popup with SVG animation
  842. showWelcomePopupText();
  843. // Call the function to create SVG animation
  844. createSVGAnimation();
  845.  
  846. function IrcMode() {
  847. const chatContent = document.getElementById("chat-content");
  848. if (chatContent) {
  849. // Remove the chat-content div from the DOM
  850. chatContent.remove();
  851. // Move the webSocketMessagesDiv and the form input to fixed position
  852. const webSocketMessagesDiv = document.getElementById("webSocketMessages");
  853. const formInput = document.getElementById("input");
  854. if (webSocketMessagesDiv && formInput) {
  855. webSocketMessagesDiv.style.position = "fixed";
  856. webSocketMessagesDiv.style.top = "0px";
  857. webSocketMessagesDiv.style.height = "90%"; // Adjust height to 90%
  858. webSocketMessagesDiv.style.overflowY = "auto"; // Add scrollbar
  859. formInput.style.position = "fixed";
  860. formInput.style.bottom = "0px";
  861. }
  862. // Create Save Text button
  863. createSaveTextButton();
  864. }
  865. // Disable the room.js functionality
  866. disableRoomJS();
  867. }
  868.  
  869. // Function to save text content without <br> elements
  870. async function saveText() {
  871. console.log("Save Text button clicked."); // Debugging: Log button click
  872. const webSocketMessagesDiv = document.getElementById("webSocketMessages");
  873. if (webSocketMessagesDiv) {
  874. console.log("webSocketMessagesDiv found:", webSocketMessagesDiv); // Debugging: Log webSocketMessagesDiv
  875. const textContent = webSocketMessagesDiv.textContent.replaceAll('\n', '\r\n');
  876. console.log("Text content:", textContent); // Debugging: Log extracted text content
  877. try {
  878. // Use File System Access API to prompt user to save text content to a file
  879. const handle = await window.showSaveFilePicker({
  880. types: [{
  881. description: 'Text Files',
  882. accept: {
  883. 'text/plain': ['.txt']
  884. }
  885. }]
  886. });
  887. const writable = await handle.createWritable();
  888. await writable.write(textContent);
  889. await writable.close();
  890. console.log("Text content saved."); // Debugging: Log text saving success
  891. } catch (error) {
  892. console.error("Error saving text content:", error); // Log error if saving fails
  893. }
  894. } else {
  895. console.log("webSocketMessagesDiv not found."); // Debugging: Log if webSocketMessagesDiv is not found
  896. }
  897. }
  898.  
  899. // Function to create Save Text button
  900. function createSaveTextButton() {
  901. const saveTextButton = document.createElement("button");
  902. saveTextButton.id = "saveTextButton";
  903. saveTextButton.textContent = "Save Text";
  904. saveTextButton.style.position = "fixed"; // Position fixed
  905. saveTextButton.style.bottom = "10px"; // Adjust bottom position
  906. saveTextButton.style.left = "10px"; // Adjust left position
  907. saveTextButton.style.background = "black";
  908. saveTextButton.style.color = "lime";
  909. saveTextButton.style.border = "none";
  910. saveTextButton.style.padding = "5px 10px";
  911. saveTextButton.style.cursor = "pointer";
  912. saveTextButton.type = "button"; // Specify that it's a button and not submit
  913. saveTextButton.addEventListener("click", saveText);
  914. document.body.appendChild(saveTextButton); // Append to document body
  915. }
  916.  
  917. // Function to remove Save Text button
  918. function removeSaveTextButton() {
  919. const saveTextButton = document.getElementById("saveTextButton");
  920. if (saveTextButton) {
  921. saveTextButton.remove();
  922. }
  923. }
  924.  
  925. // Call the function to remove the Save Text button initially
  926. removeSaveTextButton();
  927.  
  928. // Function to disable room.js functionality
  929. function disableRoomJS() {
  930. // Remove the event listener for message reception
  931. window.removeEventListener('messageReceived', handleMessageReceived);
  932. }
  933.  
  934.  
  935.  
  936. // Example function that handles incoming messages in room.js
  937. function handleMessageReceived(event) {
  938. // Logic to process incoming messages
  939. }
  940.  
  941. // Modify the handleKeyPress function to handle button clicks as well
  942. function handleKeyPress(event) {
  943. if ((event.key === 'Enter' || event.code === 'Enter') && !event.shiftKey) {
  944. event.preventDefault(); // Prevent the default behavior (creating a new line)
  945. // Call your message sending function here
  946. sendMessage();
  947. // Reset the input box's content
  948. resetInputBox();
  949. }
  950. }
  951.  
  952. // Function to send the "Tokes in 20 seconds" message and simulate Enter key press
  953. function TokesSendEnter() {
  954. // Insert predefined text
  955. const textArea = document.getElementById("textarea");
  956. textArea.value += 'Tokes in 20 seconds\n';
  957.  
  958. // Simulate Enter key press
  959. const event = new KeyboardEvent('keypress', {
  960. key: 'Enter',
  961. code: 'Enter',
  962. keyCode: 13,
  963. which: 13,
  964. bubbles: true
  965. });
  966. textArea.dispatchEvent(event);
  967.  
  968. // Set a timeout to display "tokes started" message after 20 seconds
  969. setTimeout(function() {
  970. textArea.value += 'tokes started\n'; // Send message indicating tokes has started
  971.  
  972. // Simulate Enter key press again
  973. textArea.dispatchEvent(event);
  974. }, 20000); // 20 seconds delay
  975. }
  976.  
  977.  
  978. // Function to insert predefined text and simulate Enter key press
  979. function insertPredefinedTextAndPressEnter() {
  980. // Insert predefined text
  981. const textArea = document.getElementById("textarea");
  982. textArea.value += "(╭☞ ͡ ͡°͜ ʖ ͡ ͡ )╭☞";
  983.  
  984. // Simulate Enter key press
  985. const event = new KeyboardEvent('keypress', {
  986. key: 'Enter',
  987. code: 'Enter',
  988. keyCode: 13,
  989. which: 13,
  990. bubbles: true
  991. });
  992. textArea.dispatchEvent(event);
  993. }
  994.  
  995. // Create a button to insert predefined text and press Enter
  996. function createInsertTextButton() {
  997. const insertTextButton = document.createElement("button");
  998. insertTextButton.textContent = "☞";
  999. insertTextButton.style.background = "black";
  1000. insertTextButton.style.color = "lime";
  1001. insertTextButton.style.border = "none";
  1002. insertTextButton.style.padding = "5px 10px";
  1003. insertTextButton.style.cursor = "pointer";
  1004. insertTextButton.type = "button"; // Specify that it's a button and not submit
  1005. insertTextButton.addEventListener("click", insertPredefinedTextAndPressEnter);
  1006. const textArea = document.getElementById("textarea");
  1007. textArea.parentElement.appendChild(insertTextButton);
  1008. }
  1009.  
  1010. // Call the function to create the insert text button
  1011. createInsertTextButton();
  1012.  
  1013. // Function to reset the input box's content
  1014. function resetInputBox() {
  1015. const textArea = document.getElementById("textarea");
  1016. if (textArea) {
  1017. textArea.value = ""; // Clear the textarea
  1018. }
  1019. }
  1020.  
  1021. function createPopup() {
  1022. const popup = document.createElement("div");
  1023. popup.id = "messagePopup";
  1024. popup.style.position = "fixed";
  1025. popup.style.top = "50%";
  1026. popup.style.left = "50%";
  1027. popup.style.transform = "translate(-50%, -50%)";
  1028. popup.style.background = "#fff";
  1029. popup.style.padding = "20px";
  1030. popup.style.border = "1px solid #ccc";
  1031. popup.style.boxShadow = "0 0 10px rgba(0, 0, 0, 0.1)";
  1032. popup.style.zIndex = "9999";
  1033.  
  1034. const textarea = document.createElement("textarea");
  1035. textarea.id = "popupTextarea";
  1036. textarea.placeholder = "Type a message";
  1037. textarea.maxLength = "500";
  1038. textarea.style.width = "100%";
  1039. textarea.style.marginBottom = "10px";
  1040. popup.appendChild(textarea);
  1041.  
  1042. const sendButton = document.createElement("button");
  1043. sendButton.textContent = "Send";
  1044. sendButton.style.background = "black";
  1045. sendButton.style.color = "lime";
  1046. sendButton.style.border = "none";
  1047. sendButton.style.padding = "5px 10px";
  1048. sendButton.style.cursor = "pointer";
  1049. sendButton.addEventListener("click", sendMessage);
  1050. popup.appendChild(sendButton);
  1051.  
  1052. document.body.appendChild(popup);
  1053. }
  1054.  
  1055. function openPopup() {
  1056. const popup = document.getElementById("messagePopup");
  1057. if (popup) {
  1058. popup.style.display = "block";
  1059. } else {
  1060. createPopup();
  1061. }
  1062. }
  1063.  
  1064. function closePopup() {
  1065. const popup = document.getElementById("messagePopup");
  1066. if (popup) {
  1067. popup.style.display = "none";
  1068. }
  1069. }
  1070.  
  1071. function sendMessage() {
  1072. const textArea = document.getElementById("popupTextarea");
  1073. if (textArea) {
  1074. const message = textArea.value.trim();
  1075. if (message !== "") {
  1076. // Modify your logic here to match the behavior of their Message.send function
  1077. // For example, if you're directly sending to the WebSocket:
  1078. StumbleChat.WebSocket.send(JSON.stringify({
  1079. "stumble": "msg",
  1080. "text": message
  1081. }));
  1082. // Clear the textarea after sending the message
  1083. textArea.value = "";
  1084. closePopup();
  1085. }
  1086. }
  1087. }
  1088.  
  1089. function clrall() {
  1090. const chatContent = document.getElementById("chat-content");
  1091. const webSocketMessagesDiv = document.getElementById("webSocketMessages");
  1092. if (chatContent && webSocketMessagesDiv) {
  1093. // Clear all child elements of chatContent
  1094. chatContent.innerHTML = "";
  1095. // Move webSocketMessagesDiv to the bottom
  1096. chatContent.appendChild(webSocketMessagesDiv);
  1097. // Adjust height of webSocketMessagesDiv
  1098. webSocketMessagesDiv.style.height = "75%";
  1099. }
  1100. }
  1101.  
  1102. // Function to toggle compact view
  1103. function toggleCompactView() {
  1104. const messages = document.querySelectorAll('.message .content');
  1105. messages.forEach(message => {
  1106. message.classList.toggle('compact');
  1107. });
  1108. }
  1109.  
  1110. // Function to create and populate handle-username dropdown menu
  1111. function createHandleUsernameDropdown() {
  1112. const handleUsernameDropdown = document.createElement("select");
  1113. handleUsernameDropdown.id = "handleUsernameDropdown";
  1114. handleUsernameDropdown.style.margin = "0 5px";
  1115. handleUsernameDropdown.innerHTML = '<option value="" disabled selected>who</option>';
  1116. for (const handle in handleUserMap) {
  1117. const option = document.createElement("option");
  1118. option.value = handle;
  1119. option.textContent = handleUserMap[handle];
  1120. handleUsernameDropdown.appendChild(option);
  1121. }
  1122. return handleUsernameDropdown;
  1123. }
  1124.  
  1125. // Create top buttons
  1126. function createTopButtons() {
  1127. const topButtonsDiv = document.createElement("div");
  1128. topButtonsDiv.id = "topButtons";
  1129. topButtonsDiv.style.position = "fixed";
  1130. topButtonsDiv.style.top = "10px";
  1131. topButtonsDiv.style.left = "50%";
  1132. topButtonsDiv.style.transform = "translateX(-50%)";
  1133. topButtonsDiv.style.zIndex = "9999";
  1134.  
  1135. // Clear WebSocket messages button
  1136. const clrButton = document.createElement("button");
  1137. clrButton.textContent = "clr";
  1138. clrButton.style.background = "black";
  1139. clrButton.style.color = "lime";
  1140. clrButton.addEventListener("click", clr);
  1141. topButtonsDiv.appendChild(clrButton);
  1142.  
  1143. // Clear WebSocket messages button
  1144. const clrallButton = document.createElement("button");
  1145. clrallButton.textContent = "clrall";
  1146. clrallButton.style.background = "black";
  1147. clrallButton.style.color = "lime";
  1148. clrallButton.addEventListener("click", clr);
  1149. topButtonsDiv.appendChild(clrallButton);
  1150.  
  1151. // Delete chat and switch to IRC only mode
  1152. const IrcModeButton = document.createElement("button");
  1153. IrcModeButton.textContent = "irc";
  1154. IrcModeButton.style.background = "black";
  1155. IrcModeButton.style.color = "lime";
  1156. IrcModeButton.addEventListener("click", IrcMode);
  1157. topButtonsDiv.appendChild(IrcModeButton);
  1158.  
  1159. // Dropdown menu for handle-username mapping
  1160. const handleUsernameDropdown = createHandleUsernameDropdown();
  1161. topButtonsDiv.appendChild(handleUsernameDropdown);
  1162.  
  1163. // Color picker button
  1164. const colorPickerButton = document.createElement("button");
  1165. colorPickerButton.textContent = "Color";
  1166. colorPickerButton.style.background = "black";
  1167. colorPickerButton.style.color = "lime";
  1168. colorPickerButton.style.margin = "0 5px";
  1169. colorPickerButton.addEventListener("click", () => {
  1170. openColorPickerPopup();
  1171. });
  1172. topButtonsDiv.appendChild(colorPickerButton);
  1173.  
  1174. // Font size dropdown
  1175. const fontSizeDropdown = document.createElement("select");
  1176. fontSizeDropdown.id = "fontSizeDropdown";
  1177. fontSizeDropdown.style.margin = "0 5px";
  1178. for (let i = 1; i <= 20; i++) {
  1179. const option = document.createElement("option");
  1180. option.value = i;
  1181. option.textContent = i;
  1182. fontSizeDropdown.appendChild(option);
  1183. }
  1184. fontSizeDropdown.addEventListener("change", () => {
  1185. const selectedFontSize = fontSizeDropdown.value;
  1186. applyFontSize(selectedFontSize);
  1187. });
  1188. topButtonsDiv.appendChild(fontSizeDropdown);
  1189.  
  1190. // Append top buttons div to document body
  1191. document.body.appendChild(topButtonsDiv);
  1192. }
  1193.  
  1194. // Function to apply font size to WebSocket messages
  1195. function applyFontSize(fontSize) {
  1196. const webSocketMessagesDiv = document.getElementById("webSocketMessages");
  1197. if (webSocketMessagesDiv) {
  1198. webSocketMessagesDiv.style.fontSize = `${fontSize}px`;
  1199. }
  1200. }
  1201.  
  1202. // Call the function to create top buttons
  1203. createTopButtons();
  1204.  
  1205. // Function to open color picker popup
  1206. function openColorPickerPopup() {
  1207. const popup = document.createElement("div");
  1208. popup.id = "colorPickerPopup";
  1209. popup.style.position = "fixed";
  1210. popup.style.top = "50%";
  1211. popup.style.left = "50%";
  1212. popup.style.transform = "translate(-50%, -50%)";
  1213. popup.style.background = "#1f1f1f";
  1214. popup.style.padding = "20px";
  1215. popup.style.border = "2px solid #ffffff";
  1216. popup.style.zIndex = "99999";
  1217.  
  1218. const backgroundLabel = document.createElement("label");
  1219. backgroundLabel.textContent = "Background Color:";
  1220. backgroundLabel.style.color = "#ffffff";
  1221. popup.appendChild(backgroundLabel);
  1222.  
  1223. const backgroundColorInput = document.createElement("input");
  1224. backgroundColorInput.type = "color";
  1225. backgroundColorInput.id = "backgroundColorInput";
  1226. backgroundColorInput.style.marginRight = "10px";
  1227. backgroundColorInput.value = "#000000";
  1228. popup.appendChild(backgroundColorInput);
  1229.  
  1230. const fontColorLabel = document.createElement("label");
  1231. fontColorLabel.textContent = "Font Color:";
  1232. fontColorLabel.style.color = "#ffffff";
  1233. popup.appendChild(fontColorLabel);
  1234.  
  1235. const fontColorInput = document.createElement("input");
  1236. fontColorInput.type = "color";
  1237. fontColorInput.id = "fontColorInput";
  1238. fontColorInput.style.marginRight = "10px";
  1239. fontColorInput.value = "#ffffff";
  1240. popup.appendChild(fontColorInput);
  1241.  
  1242. const applyButton = document.createElement("button");
  1243. applyButton.textContent = "Apply";
  1244. applyButton.style.background = "black";
  1245. applyButton.style.color = "lime";
  1246. applyButton.style.marginTop = "10px";
  1247. applyButton.addEventListener("click", () => {
  1248. applyColors(backgroundColorInput.value, fontColorInput.value);
  1249. popup.remove();
  1250. });
  1251. popup.appendChild(applyButton);
  1252.  
  1253. const closeButton = document.createElement("button");
  1254. closeButton.textContent = "Close";
  1255. closeButton.style.background = "black";
  1256. closeButton.style.color = "lime";
  1257. closeButton.style.marginTop = "10px";
  1258. closeButton.style.marginLeft = "10px";
  1259. closeButton.addEventListener("click", () => {
  1260. popup.remove();
  1261. });
  1262. popup.appendChild(closeButton);
  1263.  
  1264. document.body.appendChild(popup);
  1265. }
  1266.  
  1267. // Function to apply selected colors to WebSocket log
  1268. function applyColors(backgroundColor, fontColor) {
  1269. const webSocketMessagesDiv = document.getElementById("webSocketMessages");
  1270. if (webSocketMessagesDiv) {
  1271. webSocketMessagesDiv.style.backgroundColor = backgroundColor;
  1272. webSocketMessagesDiv.style.color = fontColor;
  1273. }
  1274. }
  1275.  
  1276. /* Additional compacting styles */
  1277. /*@-moz-document url-prefix("https://stumblechat.com/room/") {*/
  1278. // Compact message styles
  1279. const compactStyles = `
  1280. .message .nickname ~ .content {
  1281. display: inline-block;
  1282. top: -7px;
  1283. position: relative;
  1284. margin-left: 2px;
  1285. margin-right: 1em;
  1286. }
  1287. .content + .content {
  1288. display: inline-block!important;
  1289. margin-right: 1em;
  1290. }
  1291. .message .nickname ~ .content span {
  1292. line-height: 1.5em;
  1293. }
  1294. `;
  1295.  
  1296. // Apply compact styles to the document
  1297. const style = document.createElement('style');
  1298. style.textContent = compactStyles;
  1299. document.head.appendChild(style);
  1300. /*}*/
  1301.  
  1302.  
  1303. // Function to handle click events for the new button
  1304. function handleLoadButtonClick() {
  1305. // Add functionality for the new button here
  1306. console.log('Load button clicked');
  1307. }
  1308.  
  1309. // Function to handle click events for the new button
  1310. function handleDisplayThingsButtonClick() {
  1311. // Add functionality for the new button here
  1312. console.log('Load button clicked');
  1313. }
  1314.  
  1315. // Create a new button configuration
  1316. const DisplayThingsButtonConfig = { name: 'd', text: 'display', clickHandler: handleDisplayThingsButtonClick };
  1317.  
  1318. // Create a new button configuration
  1319. const LoadButtonConfig = { name: 'n', text: 'Load', clickHandler: handleLoadButtonClick };
  1320.  
  1321. // Function to create generic buttons
  1322. function createGenericButtons() {
  1323. // Define button configurations
  1324. const buttonConfigurations = [
  1325. { name: 'c', text: 'Compact', clickHandler: toggleCompactView },
  1326. { name: 's', text: 'Save', clickHandler: () => {
  1327. // Functionality to save handle-username map to memory or file
  1328. console.log("Save button clicked");
  1329. saveUserListToFile();
  1330. }},
  1331. { name: 'L', text: 'Load Users', clickHandler: loadUsersFromFile }, // Button to load users from file
  1332. LoadButtonConfig, // Add the new button configuration here
  1333. { name: 'D', text: 'Display Things', clickHandler: handleDisplayThingsButtonClick } // Button to load users from file
  1334. ];
  1335.  
  1336. // Get the container for the buttons
  1337. const container = document.getElementById('topButtons');
  1338.  
  1339. // Loop through each button configuration and generate a button
  1340. buttonConfigurations.forEach(config => {
  1341. // Create a button element
  1342. const button = document.createElement('button');
  1343. button.textContent = config.text; // Use button text as text content
  1344. button.style.background = "black";
  1345. button.style.color = "lime";
  1346. button.style.width = "50px"; // Set button width
  1347. button.style.height = "20px"; // Set button height
  1348. button.style.margin = "0 5px"; // Set button margin
  1349.  
  1350. // Add event listener based on configuration
  1351. button.addEventListener('click', config.clickHandler);
  1352.  
  1353. // Append the button to the container in the DOM
  1354. container.appendChild(button);
  1355. });
  1356. }
  1357.  
  1358. // Call the function to create generic buttons
  1359. createGenericButtons();
  1360.  
  1361.  
  1362. // Function to create a new button and append it to the container
  1363. function createDisconnectButton() {
  1364. const container = document.getElementById('topButtons');
  1365.  
  1366. // Create the button element
  1367. const newButton = document.createElement('button');
  1368. newButton.textContent = 'DC'; // Change the text as needed
  1369. newButton.style.background = 'black';
  1370. newButton.style.color = 'lime';
  1371. newButton.style.width = '100px'; // Set the button width
  1372. newButton.style.height = '30px'; // Set the button height
  1373. newButton.style.margin = '0 5px'; // Set the button margin
  1374.  
  1375. // Add event listener to the new button
  1376. newButton.addEventListener('click', () => {
  1377. // Add functionality for the new button here
  1378. console.log('New button clicked');
  1379. });
  1380.  
  1381. // Append the new button to the container
  1382. container.appendChild(newButton);
  1383. }
  1384.  
  1385. // Call the function to create the new button
  1386. createDisconnectButton();
  1387.  
  1388. // Function to load users from the users.txt file
  1389. function displayThings() {
  1390. const users = [];
  1391. // Placeholder for file content, replace this with your file reading logic
  1392. // Example: You can use XMLHttpRequest, fetch API, or any other method to read the file
  1393. // For simplicity, I'll use fetch API assuming users.txt is in the same directory
  1394. fetch('users.txt')
  1395. .then(response => response.text())
  1396. .then(fileContent => {
  1397. // Split the file content into lines
  1398. const lines = fileContent.split('\n');
  1399.  
  1400. // Iterate over each line to parse user data
  1401. lines.forEach(line => {
  1402. const userData = line.trim().split(' '); // Splitting by space to separate username and handle
  1403. if (userData.length === 2) {
  1404. const username = userData[0].trim();
  1405. const handle = userData[1].trim();
  1406. users.push({ username, handle });
  1407. // Update user map
  1408. handleUserMap[handle] = username;
  1409. }
  1410. });
  1411.  
  1412. // Display loaded users
  1413. console.log("Loaded Users:");
  1414. users.forEach(user => {
  1415. console.log(`${user.username} (${user.handle})`);
  1416. });
  1417. })
  1418. .catch(error => {
  1419. console.error('Error loading users from file:', error);
  1420. });
  1421.  
  1422. return users;
  1423. }
  1424.  
  1425. // Find the CSP meta tag and modify its content attribute
  1426. const cspMeta = document.querySelector("meta[http-equiv='Content-Security-Policy']");
  1427. if (cspMeta) {
  1428. cspMeta.setAttribute("content", "your-updated-csp-directives");
  1429. }
  1430.  
  1431. const proxyUrl = "http://65.25.72.68:43435"; // Add http:// or https:// as needed
  1432.  
  1433. // Function to call the AI and send its response to the chat room
  1434. function DoAi(cmd_arg) {
  1435. // Define your OpenAI API key and other parameters
  1436. const api_key = 'your-api-key';
  1437. const endpoint = proxyUrl; // Use proxy server endpoint
  1438. const max_tokens = 200;
  1439. const max_parts = 10;
  1440. const delay_between_parts = 2;
  1441. const min_response_length = 10;
  1442.  
  1443. const headers = {
  1444. 'Content-Type': 'application/json',
  1445. 'Authorization': 'Bearer ' + api_key,
  1446. };
  1447.  
  1448. const data = {
  1449. model: 'gpt-3.5-turbo',
  1450. messages: [{role: 'system', content: 'You are a helpful assistant.'},
  1451. {role: 'user', content: cmd_arg}],
  1452. max_tokens: max_tokens,
  1453. };
  1454.  
  1455. // Send the POST request to the API via proxy server
  1456. fetch(endpoint, {
  1457. method: 'POST',
  1458. headers: headers,
  1459. body: JSON.stringify(data)
  1460. })
  1461. .then(response => {
  1462. if (!response.ok) {
  1463. throw new Error('Request failed with status code ' + response.status);
  1464. }
  1465. return response.json();
  1466. })
  1467. .then(result => {
  1468. if (result.choices && result.choices[0] && result.choices[0].message && result.choices[0].message.content) {
  1469. let response_text = result.choices[0].message.content;
  1470.  
  1471. // Check if the response_text is not empty and meets the minimum length
  1472. if (response_text.trim() && response_text.length >= min_response_length) {
  1473. // Use regular expression to replace various line break characters
  1474. response_text = response_text.replace(/[\r\n\t\f\v]+/g, ' ');
  1475.  
  1476. // Split the response into parts based on sentence-like breaks
  1477. const parts = response_text.match(/.{1,200}(?:\.\s|\.$|$)/g) || [];
  1478.  
  1479. const num_parts = Math.min(max_parts, parts.length);
  1480.  
  1481. // Calculate the time interval for rate limiting (15 seconds / 3 messages)
  1482. const rate_limit_interval = 15.0 / 3;
  1483.  
  1484. // Send each part with a delay
  1485. parts.slice(0, num_parts).forEach((part, index) => {
  1486. setTimeout(() => {
  1487. // Send the part to the chat room
  1488. sendMessage(part);
  1489. }, index * delay_between_parts * 1000);
  1490. });
  1491. } else {
  1492. sendMessage("AI response was blank or too short.");
  1493. }
  1494. } else {
  1495. sendMessage("AI response format unexpected: " + JSON.stringify(result));
  1496. }
  1497. })
  1498. .catch(error => {
  1499. sendMessage("AI request failed: " + error.message);
  1500. });
  1501. }
  1502.  
  1503.  
  1504. })();
  1505.  
  1506.  
  1507.  
  1508.  
  1509.  
  1510.  
  1511.