Rumble Unique Chatters and Number of Messages for Live Streams

Displays the number of unique chatters and messages in Rumble live streams.

当前为 2024-10-01 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Rumble Unique Chatters and Number of Messages for Live Streams
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.6
  5. // @description Displays the number of unique chatters and messages in Rumble live streams.
  6. // @match https://rumble.com/*
  7. // @grant none
  8. // @run-at document-idle
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. /**
  15. * Utility function to wait for a specific element to appear in the DOM.
  16. * @param {string} selector - CSS selector of the target element.
  17. * @param {number} timeout - Maximum time to wait in milliseconds.
  18. * @returns {Promise<Element>} - Resolves with the found element or rejects on timeout.
  19. */
  20. function waitForElement(selector, timeout = 10000) {
  21. return new Promise((resolve, reject) => {
  22. const element = document.querySelector(selector);
  23. if (element) {
  24. return resolve(element);
  25. }
  26.  
  27. const observer = new MutationObserver(() => {
  28. const elem = document.querySelector(selector);
  29. if (elem) {
  30. observer.disconnect();
  31. resolve(elem);
  32. }
  33. });
  34.  
  35. observer.observe(document.body, { childList: true, subtree: true });
  36.  
  37. // Timeout after specified milliseconds
  38. setTimeout(() => {
  39. observer.disconnect();
  40. reject(new Error(`Element ${selector} not found within ${timeout}ms`));
  41. }, timeout);
  42. });
  43. }
  44.  
  45. async function init() {
  46. try {
  47. // Check if the live info element exists
  48. const liveInfoSelector = "div.video-header-live-info";
  49. try {
  50. const liveInfoElement = await waitForElement(liveInfoSelector, 5000);
  51. } catch (error) {
  52. console.warn("[Chat User Monitor] Live info element not found within 5 seconds. Exiting script.");
  53. return; // Exit the script if the live info element is not found
  54. }
  55.  
  56. // Wait for the chat box element to be available
  57. const chatBoxSelector = "#chat-history-list";
  58. const chatBox = await waitForElement(chatBoxSelector);
  59.  
  60. // Wait for the chat controls container to append the user count display
  61. const chatControlsSelector = "form#chat-message-form > div.chat-message-form-section.chat-message-form-section-justify-between > div.chat--rant-row:nth-of-type(1)";
  62. const chatControlsContainer = await waitForElement(chatControlsSelector);
  63.  
  64. // Initialize Sets to track unique users and messages
  65. const seenUsers = new Set();
  66. const seenMessages = new Set();
  67.  
  68. // Create a container for displaying the user count with SVG
  69. const userCountDisplay = document.createElement("div");
  70. userCountDisplay.id = "user-count-container";
  71. userCountDisplay.classList.add("video-category-tag");
  72. userCountDisplay.title = "Number of unique users in the chat";
  73.  
  74. // Insert the user SVG icon
  75. const userIconContainer = document.createElement("div");
  76. userIconContainer.innerHTML = `
  77. <svg width="20px" height="20px" viewBox="0 0 16 16" fill="currentColor">
  78. <path d="M8 7C9.65685 7 11 5.65685 11 4C11 2.34315 9.65685 1 8 1C6.34315 1 5 2.34315 5 4C5 5.65685 6.34315 7 8 7Z"/>
  79. <path d="M14 12C14 10.3431 12.6569 9 11 9H5C3.34315 9 2 10.3431 2 12V15H14V12Z"/>
  80. </svg>
  81. `;
  82. userIconContainer.style.marginRight = "8px";
  83.  
  84. // Create the user count element
  85. const userCountElement = document.createElement("span");
  86. userCountElement.id = "seen-users-count";
  87. userCountElement.textContent = "0";
  88. userCountElement.style.fontSize = "12px";
  89.  
  90. // Append SVG and user count to the container
  91. userCountDisplay.appendChild(userIconContainer);
  92. userCountDisplay.appendChild(userCountElement);
  93.  
  94. // Append the container to the chat controls container
  95. chatControlsContainer.appendChild(userCountDisplay);
  96.  
  97. // Create a container for displaying the message count with SVG
  98. const messageCountDisplay = document.createElement("div");
  99. messageCountDisplay.id = "message-count-container";
  100. messageCountDisplay.style.display = "flex";
  101. messageCountDisplay.style.alignItems = "center";
  102. messageCountDisplay.style.marginLeft = "16px";
  103. messageCountDisplay.title = "Number of messages in the chat";
  104.  
  105. // Insert the message SVG icon
  106. const messageIconContainer = document.createElement("div");
  107. messageIconContainer.innerHTML = `
  108. <svg width="20px" height="20px" viewBox="0 0 24 24" fill="currentColor">
  109. <path d="M21.0039 12C21.0039 16.9706 16.9745 21 12.0039 21C9.9675 21 3.00463 21 3.00463 21C3.00463 21 4.56382 17.2561 3.93982 16.0008C3.34076 14.7956 3.00391 13.4372 3.00391 12C3.00391 7.02944 7.03334 3 12.0039 3C16.9745 3 21.0039 7.02944 21.0039 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  110. </svg>
  111. `;
  112. messageIconContainer.style.marginRight = "8px";
  113.  
  114. // Create the message count element
  115. const messageCountElement = document.createElement("span");
  116. messageCountElement.id = "seen-messages-count";
  117. messageCountElement.textContent = "0";
  118. messageCountElement.style.fontSize = "12px";
  119.  
  120. // Append SVG and message count to the message container
  121. messageCountDisplay.appendChild(messageIconContainer);
  122. messageCountDisplay.appendChild(messageCountElement);
  123.  
  124. // Append the message count container to the user count container
  125. userCountDisplay.appendChild(messageCountDisplay);
  126.  
  127. /**
  128. * Updates the displayed counts of users and messages.
  129. */
  130. const updateCounts = () => {
  131. userCountElement.textContent = seenUsers.size;
  132. messageCountElement.textContent = seenMessages.size;
  133. };
  134.  
  135. /**
  136. * Observes the chat box for new messages and users.
  137. */
  138. const observeChat = () => {
  139. const observer = new MutationObserver(mutations => {
  140. mutations.forEach(mutation => {
  141. mutation.addedNodes.forEach(node => {
  142. if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains('chat-history--row')) {
  143. try {
  144. const messageId = node.getAttribute("data-message-id");
  145. const userId = node.getAttribute("data-message-user-id");
  146.  
  147. // Track unique messages
  148. if (messageId && !seenMessages.has(messageId)) {
  149. seenMessages.add(messageId);
  150. }
  151.  
  152. // Track unique users
  153. if (userId && !seenUsers.has(userId)) {
  154. seenUsers.add(userId);
  155. }
  156.  
  157. // Update the displayed counts
  158. updateCounts();
  159. } catch (error) {
  160. console.error("[Chat User Monitor] Error processing message:", error);
  161. }
  162. }
  163. });
  164. });
  165. });
  166.  
  167. observer.observe(chatBox, { childList: true });
  168. };
  169.  
  170. // Start observing the chat
  171. observeChat();
  172.  
  173. } catch (error) {
  174. console.error("[Chat User Monitor] Initialization failed:", error);
  175. }
  176. }
  177.  
  178. // Start the initialization process
  179. init();
  180.  
  181. })();