Advertisement
MeKLiN2

Untitled

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