Chaturbate Chat, PM and User enter/leave Notifier for streamers

Blink/show a frame when having unread PM, unread Chats (main chat) or when user enter or leaves a streamers room. With setting window that can toggle them on or off

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Chaturbate Chat, PM and User enter/leave Notifier for streamers
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Blink/show a frame when having unread PM, unread Chats (main chat) or when user enter or leaves a streamers room. With setting window that can toggle them on or off
// @author       Brsrk
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=32&domain=chaturbate.com
// @icon64       https://www.google.com/s2/favicons?sz=64&domain=chaturbate.com
// @match        https://chaturbate.com/b/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function() {
  'use strict';

  // Define the specific text to monitor
  const monitorText = {
    before1: 'CHAT', // text to look for
    after1: 'CHAT \\(\\d+\\)', // regex pattern to match "CHAT (any number)"
    before2: 'PM', // text to look for
    after2: 'PM \\(\\d+\\)', // regex pattern to match "PM (any number)"
    before3: 'USERS', // text to look for
    after3: 'USERS \\(\\d+\\)', // regex pattern to match "USERS (any number)"
  };

  let previousTextContent = '';
  let previousUserCount = '';
  let blinkingBox = null;
  let blinkingFrame = null;
  let userBlinkingFrame = null;
  let titleBlinkInterval = null;
  let originalTitle = document.title;

  // Load settings from local storage
  let settings = {
    pmNotifications: GM_getValue('pmNotifications', true),
    userNotifications: GM_getValue('userNotifications', true),
    chatNotifications: GM_getValue('chatNotifications', true),
  };

  // Add CSS for blinking effect and settings menu
  const style = document.createElement('style');
  style.textContent = `
    #blinking-frame {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border: 10px solid red;
      animation: blink 1s infinite;
      z-index: 9999;
      pointer-events: none;
      box-sizing: border-box;
    }
    #user-blinking-frame-green {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border: 5px solid green;
      animation: blink-green 5s;
      z-index: 9997;
      pointer-events: none;
      box-sizing: border-box;
    }
    #user-blinking-frame-orange {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border: 2px solid orange;
      animation: blink-orange 5s;
      z-index: 9998;
      pointer-events: none;
      box-sizing: border-box;
    }
    @keyframes blink {
      0% {
        opacity: 1;
      }
      50% {
        opacity: 0;
      }
      100% {
        opacity: 1;
      }
    }
    @keyframes blink-green {
      0% {
        opacity: 1;
      }
      20% {
        opacity: 0;
      }
      40% {
        opacity: 1;
      }
      60% {
        opacity: 0;
      }
      80% {
        opacity: 1;
      }
      100% {
        opacity: 0;
      }
    }
    @keyframes blink-orange {
      0% {
        opacity: 1;
      }
      20% {
        opacity: 0;
      }
      40% {
        opacity: 1;
      }
      60% {
        opacity: 0;
      }
      80% {
        opacity: 1;
      }
      100% {
        opacity: 0;
      }
    }
    #settings-menu {
      position: fixed;
      top: 20px;
      right: 10px;
      background-color: #fff;
      padding: 10px;
      border: 1px solid #ddd;
      z-index: 10000;
      display: none;
    }
    #settings-menu-close {
      position: absolute;
      top: 0;
      right: 0;
      padding: 5px;
      cursor: pointer;
    }
  `;
  document.head.appendChild(style);

  // Create settings menu
  const settingsMenu = document.createElement('div');
  settingsMenu.id = 'settings-menu';
  settingsMenu.innerHTML = `
    <div id="settings-menu-close">X</div>
    <label><input type="checkbox" id="chat-notifications" ${settings.chatNotifications ? 'checked' : ''}> Main Chat Notifications</label><br>
    <label><input type="checkbox" id="pm-notifications" ${settings.pmNotifications ? 'checked' : ''}> PM Notifications</label><br>
    <label><input type="checkbox" id="user-notifications" ${settings.userNotifications ? 'checked' : ''}> User enter/leave Notification Frame</label>
  `;
  document.body.appendChild(settingsMenu);

  // Add event listeners to settings menu
  document.getElementById('pm-notifications').addEventListener('change', (e) => {
    settings.pmNotifications = e.target.checked;
    GM_setValue('pmNotifications', settings.pmNotifications);
  });
  document.getElementById('user-notifications').addEventListener('change', (e) => {
    settings.userNotifications = e.target.checked;
    GM_setValue('userNotifications', settings.userNotifications);
  });
  document.getElementById('chat-notifications').addEventListener('change', (e) => {
    settings.chatNotifications = e.target.checked;
    GM_setValue('chatNotifications', settings.chatNotifications);
  });
  document.getElementById('settings-menu-close').addEventListener('click', () => {
    settingsMenu.style.display = 'none';
  });

  // Register menu command
  GM_registerMenuCommand('Settings', () => {
    settingsMenu.style.display = 'block';
  });

  // Function to check for text changes
  function checkForChanges() {
    const textContent = document.body.textContent;

    if (textContent !== previousTextContent) {
      previousTextContent = textContent;

      // Check if the text content matches any of the after regex patterns
      const match1 = new RegExp(monitorText.after1).test(textContent);
      const match2 = new RegExp(monitorText.after2).test(textContent);
      const match3 = new RegExp(monitorText.after3).test(textContent);

      if ((match1 && settings.chatNotifications) || (match2 && settings.pmNotifications)) {
        // Show the blinking box and frame
        showBlinkingFrame();
      } else {
        // Hide the blinking box and frame
        hideBlinkingFrame();
      }

      // Blink page title (?)
      if (match2 && settings.pmNotifications) {
        blinkTitle('- ');
      } else {
        stopBlinkingTitle();
        document.title = originalTitle;
      }

      if (match3 && settings.userNotifications) {
        const userCountMatch = textContent.match(/USERS \((\d+)\)/);
        if (userCountMatch && userCountMatch[1] !== previousUserCount) {
          const currentUserCount = parseInt(userCountMatch[1]);
          if (previousUserCount !== '') {
            showUserBlinkingFrame(currentUserCount > parseInt(previousUserCount));
          }
          previousUserCount = userCountMatch[1];
        }
      }
    }
  }

  // Function to show the blinking frame
  function showBlinkingFrame() {
    if (!blinkingFrame) {
      blinkingFrame = document.createElement('div');
      blinkingFrame.id = 'blinking-frame';
      document.body.appendChild(blinkingFrame);
    }
  }

  // Function to hide the blinking frame
  function hideBlinkingFrame() {
    if (blinkingFrame) {
      blinkingFrame.remove();
      blinkingFrame = null;
    }
  }

  // Function to show the user blinking frame
  function showUserBlinkingFrame(increased) {
    if (userBlinkingFrame) {
      userBlinkingFrame.remove();
    }
    userBlinkingFrame = document.createElement('div');
    userBlinkingFrame.id = increased ? 'user-blinking-frame-green' : 'user-blinking-frame-orange';
    document.body.appendChild(userBlinkingFrame);
    setTimeout(() => {
      userBlinkingFrame.remove();
    }, 5000);
  }

  function blinkTitle(prefix) {
    stopBlinkingTitle();
    let visible = true;
    titleBlinkInterval = setInterval(() => {
      if (visible) {
        document.title = originalTitle;
        visible = false;
      } else {
        document.title = prefix + originalTitle;
        visible = true;
      }
    }, 1000);
  }

  function stopBlinkingTitle() {
    if (titleBlinkInterval) {
      clearInterval(titleBlinkInterval);
      titleBlinkInterval = null;
    }
  }

  // Continuously check for changes
  setInterval(checkForChanges, 1000); // Check every 1 second
})();