fily / red text red text red text red text red text re

// ==UserScript==
// @name        red text red text red text red text red text re
// @namespace   Violentmonkey Scripts
// @version     1.2.0
// @match       https://tetr.io/*
// @grant       none
// @run-at      document-idle
// @license MIT
// @author      fily
// ==/UserScript==

(() => {
  'use strict';

  const PING_CLASSES = ['ping-1', 'ping-2', 'ping-3', 'ping-more'];

  const style = document.createElement('style');
  style.textContent = `
    .chat_message.pingchat p.ping-1 {
      color: #ff5151;
      text-shadow: 0 0 12px #ff5151;
    }
    .chat_message.pingchat p.ping-2 {
      color: #ff2e2e;
      text-shadow: 0 0 20px #ff2e2e, 0 0 8px #ff2e2e;
      font-weight: 600;
    }
    .chat_message.pingchat p.ping-3,
    .chat_message.pingchat p.ping-more {
      color: #ff0000;
      text-shadow: 0 0 32px #ff0000, 0 0 12px #ff0000;
      font-weight: 700;
    }
    .chat_message.pingchat p.ping-more {
      animation: ping-pulse 0.4s ease-in-out infinite alternate;
    }
    @keyframes ping-pulse {
      from { text-shadow: 0 0 16px  #ff0000; }
      to   { text-shadow: 0 0 44px #ff0000, 0 0 16px #ff0000; }
    }
  `;
  document.head.append(style);

  function currentName() {
    const el = document.getElementById('me_username');
    // if for some reason there is no name, move on
    if (!el) return '';
    const raw = 'value' in el && el.value != null ? el.value : el.textContent;
    return (raw || '').trim();
  }

  let nameRe = null;
  let nameKey = '';

  function refreshName() {
    const name = currentName();
    if (name === nameKey) return false;
    nameKey = name;
    nameRe = name
      // bullshit
      ?
      new RegExp(`(?<![\\p{L}\\p{N}_])${name}(?![\\p{L}\\p{N}_])`, 'giu') :
      null;
    return true;
  }

  function paint(chat, force = false) {
    for (const msg of chat.querySelectorAll('.chat_message.pingchat')) {
      if (!force && msg.dataset.pingFor === nameKey) continue;
      msg.dataset.pingFor = nameKey;

      for (const p of msg.querySelectorAll('p')) {
        // no duplicates
        p.classList.remove(...PING_CLASSES);
        if (!nameRe) continue;
        nameRe.lastIndex = 0;
        const hits = (p.textContent.match(nameRe) || []).length;
        if (hits) p.classList.add(PING_CLASSES[Math.min(hits, PING_CLASSES.length) - 1]);
      }
    }
  }

  function start(chat) {
    console.log(chat)
    refreshName();
    paint(chat, true);

    new MutationObserver(() => {
      const changed = refreshName();
      paint(chat, changed);
    }).observe(chat, {
      childList: true,
      subtree: true,
      characterData: true
    });

    // catch the username appearing or changing outside the chat scroller
    new MutationObserver(() => {
      if (refreshName()) paint(chat, true);
    }).observe(document.body, {
      childList: true,
      subtree: true,
      characterData: true
    });
  }

  const chat = document.getElementById('room_chat');
  if (chat) {
    start(chat);
  }
  else {
    const obs = new MutationObserver(() => {
      const el = document.getElementById('room_chat');
      if (el) {
        obs.disconnect();
        start(el);
      }
    });
    obs.observe(document.documentElement, {
      childList: true,
      subtree: true
    });
  }
})();