Greasy Fork is available in English.

KRINVM Multi-Tools

Chat-Filter, Auto-Reconnect, Anti-AFK, Auto-Announcer

// ==UserScript==
// @name         KRINVM Multi-Tools
// @namespace    https://github.com/krinvm
// @version      1.0
// @description  Chat-Filter, Auto-Reconnect, Anti-AFK, Auto-Announcer
// @name:en       KRINVM MULTI-TOOLS
// @name:ru       KRINVM МУЛЬТИ-ИНСТРУМЕНТЫ
// @name:zh-CN    KRINVM 多功能工具
// @name:id       KRINVM MULTI-TOOLS
// @name:vi       KRINVM CÔNG CỤ ĐA NĂNG
// @description:en Chat-Filter, Auto-Reconnect, Anti-AFK, Auto-Announcer
// @description:ru Чат-фильтр, Авто-переподключение, Анти-AFK, Авто-анонсер
// @description:zh-CN 聊天过滤器,自动重连,反AFK,自动公告
// @description:id Chat-Filter, Auto-Reconnect, Anti-AFK, Auto-Announcer
// @description:vi Lọc trò chuyện, Tự động kết nối lại, Chống AFK, Thông báo tự động
// @author       KRINVM
// @match        https://pony.town/
// @icon         https://i.ibb.co/Bnm5M9G/sshot-2024-08-07-1.png
// @license (https://github.com/krinvm/KRINVM-Multi-Tools/blob/main/LICENCIA.md)
// ==/UserScript==

/*# Licencia de uso CopyLeft

**Autora original:** KRINVM  
**Sitio web:** [https://github.com/krinvm](https://github.com/krinvm)  
**Fecha de entrada en vigencia:** 19 de septiembre de 2024

## Términos de la Licencia

### 1. Uso Permisible
Este código es de uso libre y se puede utilizar sin ninguna limitación, bajo las siguientes condiciones.

### 2. Restricciones
- **Uso Comercial:** No se permite el uso comercial del código, incluyendo pero no limitado a: alquiler, sublicencias, venta o cualquier tipo de explotación comercial.
  
### 3. Libertades Concedidas
- **Compartir y Distribuir:** Puedes compartir, distribuir y modificar el código siempre que se mantenga esta misma licencia.
- **Libertad de Estudio:** Tienes la libertad de estudiar cómo está hecho el trabajo y adaptarlo a tus necesidades. Se recomienda incluir documentación clara y accesible sobre el funcionamiento del código.
- **Modificar:** Puedes modificar el código de la manera que consideres conveniente.

### 4. (Re)Distribución
- Puedes (re)distribuir cuantas copias desees del código original y de las modificaciones realizadas, siempre que se mantenga la misma licencia y se incluya el aviso de autoría.

### 5. Condiciones de la Licencia
- Las condiciones de esta licencia no pueden ser revocadas. Todo trabajo derivado y el original deben estar siempre disponibles de tal manera que se facilite su modificación.
- El código fuente debe estar disponible para aquellos que reciban una copia del trabajo, y la compilación del código debería permitirse sin ninguna clase de impedimento.

### 6. Documentación Obligatoria
Para garantizar la transparencia y el entendimiento del código, se requiere que:

- **Manual de Usuario:** Se incluya un manual que explique cómo utilizar el código y sus funcionalidades.
- **Registro de Modificaciones:** Cada modificación realizada al código debe ir acompañada de una descripción clara de los cambios y su propósito, que debe ser documentada de la siguiente manera:
  - **Fecha de modificación.**
  - **Descripción detallada de los cambios.**
  - **Nombre del autor de los cambios.**
  
### 7. Responsabilidad
El uso de este código es bajo tu propio riesgo. La autora original no será responsable por ningún daño o perjuicio que surja del uso de este código.

### 8. Aceptación de Términos
Al utilizar, modificar o redistribuir este código, aceptas cumplir con los términos establecidos en esta licencia.
*/

(function() {
    'use strict';
 const panelContainer = document.createElement('div');
 panelContainer.id = 'scriptPanel';
 panelContainer.style.position = 'fixed';
 panelContainer.style.top = '790px';
 panelContainer.style.left = '1018px';
 panelContainer.style.zIndex = '9999';
 document.body.appendChild(panelContainer);


  let intervalId;

  const panelStyles = `
    #scriptPanel button {
      background-color: red;
      color: white;
      padding: 8px 12px;
      margin-right: 10px;
      border: none;
      cursor: pointer;
      outline: none;
      border-radius: 4px;
    }

    #scriptPanel button:hover {
      background-color: darkred;
    }

    #scriptPanel button.active {
      background-color: green;
    }
  `;

  const styleElement = document.createElement('style');
  styleElement.textContent = panelStyles;
  document.head.appendChild(styleElement);

  const madeByKrinvm = document.getElementById('madeByKrinvm');
  if (madeByKrinvm) {
    madeByKrinvm.style.top = 'calc(30px + 20px)';
  }

    const welcomeWindowHTML = `
    <div id="welcomeWindow" style="display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #333; padding: 20px; text-align: center; border: 2px solid rgba(0, 0, 0, 0.2); transition: opacity 0.5s, visibility 0.5s; z-index: 10000;">
      <h1 style="color: white; font-weight: bold;">KRINVM Multi-Tools</h1>
      <h3 style="color: white; font-weight: bold; font-size: 24px;">Version: <span style="font-size: 28px;">V1.0</span></h3>
      <!-- gif1 -->
      <h2 style="color: white;">
        ¡Hola! Soy krinvm y este es mi primer Script para pony.town. Si deseas más scripts útiles entra a: https://github.com/krinvm
      </h2>
      <img src="https://i.pinimg.com/originals/c7/9f/d0/c79fd0bec90cca55e7de3d0ec2ad514e.gif" alt="Your GIF" style="display: block; margin: 20px auto 0; width: 373px; height: 500px;">
      <h2 style="color: white;">
      </h2>
      <hr style="border-top: 1px solid white;">
      <button id="letsGoButton" style="background-color: #5cb85c; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; margin-top: 20px;">Aceptar!</button>
    </div>
    <div id="overlay" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); backdrop-filter: blur(5px); z-index: 9999;"></div>
    <div id="madeByKrinvm" style="position: fixed; top: 720px; right: 10px; font-size: 16px; z-index: 10001;">
<a href="https://www.youtube.com/@KRINVM2" target="_blank" style="text-decoration: none;">
    <span id="madeByText" style="cursor: pointer; color: #FFFFFF;">Hecho por KRINVM</span>
</a>

      <img id="krinvmImage" src="https://i.ibb.co/Bnm5M9G/sshot-2024-08-07-1.png" alt="photo" width="75" height="54" style="vertical-align: middle; margin-left: 5px; opacity: 0.7;">
    </div>
  `;



  panelContainer.innerHTML = welcomeWindowHTML;

  const welcomeWindow = document.getElementById('welcomeWindow');
  const letsGoButton = document.getElementById('letsGoButton');

  setTimeout(() => {
    welcomeWindow.style.opacity = '1';
    welcomeWindow.style.visibility = 'visible';
  }, 500);

  function closeWelcomeWindow() {
    welcomeWindow.style.opacity = '0';
    welcomeWindow.style.visibility = 'hidden';
    setTimeout(() => {
      overlay.style.display = 'none';
      overlay.style.pointerEvents = 'auto';
    }, 1000);
  }

  letsGoButton.addEventListener('click', closeWelcomeWindow);
  letsGoButton.addEventListener('mouseover', function() {
    letsGoButton.style.backgroundColor = '#4CAF50';
  });
  letsGoButton.addEventListener('mouseout', function() {
    letsGoButton.style.backgroundColor = '#5cb85c';
  });

  setTimeout(() => {
    welcomeWindow.style.display = 'block';
  }, 1000);

  letsGoButton.addEventListener('click', closeWelcomeWindow);

  const antiafkButton = document.createElement('button');
  antiafkButton.textContent = 'ANTI-AUS';
  antiafkButton.style.backgroundColor = 'red';
  antiafkButton.style.color = 'white';
  antiafkButton.style.padding = '8px 12px';
  antiafkButton.style.marginRight = '10px';
  antiafkButton.style.border = 'none';
  antiafkButton.style.cursor = 'pointer';
  antiafkButton.style.borderRadius = '4px';
  panelContainer.appendChild(antiafkButton);

  const autoWriterButton = document.createElement('button');
  autoWriterButton.textContent = 'AUTO-ANUNCIADOR';
  autoWriterButton.style.backgroundColor = 'red';
  autoWriterButton.style.color = 'white';
  autoWriterButton.style.padding = '8px 12px';
  autoWriterButton.style.marginRight = '10px';
  autoWriterButton.style.border = 'none';
  autoWriterButton.style.cursor = 'pointer';
  autoWriterButton.style.borderRadius = '4px';
  panelContainer.appendChild(autoWriterButton);

  let isAntiafkActive = false;
  let isAutoWriterActive = false;
  let intervalIdAutoWriter;

  antiafkButton.addEventListener('click', toggleAntiafk);
  autoWriterButton.addEventListener('click', toggleAutoWriter);

    const overlay = document.getElementById('overlay');
  if (overlay) {
    overlay.style.pointerEvents = 'none';
    overlay.style.display = 'block';

    const letsGoButton = document.getElementById('letsGoButton');
    if (letsGoButton) {
      letsGoButton.addEventListener('click', function() {
        overlay.style.display = 'none';
        overlay.style.pointerEvents = 'auto';
      });
    }
  }

  function click() {
    var event = new MouseEvent('click', {
      bubbles: true,
      cancelable: true,
      view: window
    });
    var element = document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2);
    element.dispatchEvent(event);

    console.log("click");
  }

  function startClicking() {
    intervalId = setInterval(click, 270000);
    console.log("script starting");
  }

  function stopClicking() {
    clearInterval(intervalId);
    console.log("script stop");
    setTimeout(function() {
      console.clear();
    }, 5000);
  }

  function toggleAntiafk() {
    isAntiafkActive = !isAntiafkActive;
    if (isAntiafkActive) {
      antiafkButton.classList.add('active');
      antiafkButton.style.backgroundColor = 'green';
      console.log('ANTI-AUS enable');
      startClicking();
    } else {
      antiafkButton.classList.remove('active');
      antiafkButton.style.backgroundColor = 'red';
      console.log('ANTI-AUS disable');
      stopClicking();
    }
  }
  antiafkButton.addEventListener('click', toggleAntiafk);

  function sendMessage(statsText) {
    let messageCount = 0;
    let isChatOpen = false;
    let isSendingMessage = false;

    function click() {
      var event = new MouseEvent('click', {
        bubbles: true,
        cancelable: true,
        view: window
      });
      var element = document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2);
      element.dispatchEvent(event);

      console.log("click");
    }

    function openChat() {
      const chatButton = document.querySelector(".chat-open-button button");

      if (chatButton) {
        chatButton.click();
        isChatOpen = true;
      }
    }


    function closeChat() {
      const closeButton = document.querySelector(".chat-close-button button");

      if (closeButton) {
        closeButton.click();
        isChatOpen = false;
      }
    }

function sendMessage(statsText) {
  if (isAutoWriterActive) {
    if (isChatOpen) {
      if (!isSendingMessage) {
        isSendingMessage = true;
        const textareaElement = document.querySelector("textarea[aria-label='Chat message']");

        if (textareaElement) {
          const statsTextWithoutFps = statsText.replace(/\d+\s?fps/, '');
          textareaElement.value = `${++messageCount} ${statsTextWithoutFps}`;

          const enterEvent = new KeyboardEvent("keydown", {
            key: "Enter",
            bubbles: true,
            cancelable: true,
          });

          textareaElement.dispatchEvent(enterEvent);
          const sendButton = document.querySelector("ui-button[title='Send message (hold Shift to send without closing input)'] button");
          if (sendButton) {
            sendButton.click();
          }

          if (messageCount === 200) {
            location.reload();
          }
        }
        isSendingMessage = false;
      } else {
        setTimeout(sendMessage, 1000, statsText);
      }
    } else {
      openChat();
    }
  }
}

    function updateAndSendMessage() {
      sendMessage(statsText);

      if (Math.random() < 0.39) {
        click();
      }
    }
    setInterval(updateAndSendMessage, 4000 + Math.random() * 2000);
  }
  function toggleAutoWriter() {
    isAutoWriterActive = !isAutoWriterActive;
    if (isAutoWriterActive) {
      autoWriterButton.classList.add('active');
      autoWriterButton.style.backgroundColor = 'green';
      console.log('AUTO-ANUNCIADOR enable');
      console.log('Escribe el texto que quieres repetir:');
      const adText = prompt('Escribe el texto que quieres repetir:');
      if (adText !== null) {
        const statsText = adText.trim() || 'Default text';
        sendMessage(statsText);
      } else {
        autoWriterButton.classList.remove('active');
        autoWriterButton.style.backgroundColor = 'red';
        isAutoWriterActive = false;
        console.log('AUTO-ANUNCIADOR disable');
      }
    } else {
      autoWriterButton.classList.remove('active');
      autoWriterButton.style.backgroundColor = 'red';
      console.log('AUTO-ANUNCIADOR disable');
      stopAutoWriterActions();
    }
  }
     function stopAutoWriterActions() {
    clearInterval(intervalIdAutoWriter);
    console.log("AUTO-ANUNCIADOR stopping");
  }

  autoWriterButton.addEventListener('click', toggleAutoWriter);
  antiafkButton.addEventListener('click', toggleAntiafk);
  autoWriterButton.addEventListener('click', toggleAutoWriter);

const style = document.createElement('style');
style.appendChild(
  document.createTextNode(`
    .chat-line.highlight { background-color: rgba(239, 4, 239, 0.56); }
    .chat-line.hidden { display: none; }
    .filter-line {
      background: rgba(0,0,0,0.1);
      border-radius: 3px;
      border: 1px solid rgba(0,0,0,0.3);
      margin-left: 2px;
      margin-bottom: 2px;
      color: white;
    }
  `)
);
document.getElementsByTagName('head')[0].appendChild(style);

var namesFilter = [];
var chatListener = null;
var playingListener = null;
var filterInput = null;
var filterinjected = false;

const uninjectFilter = () => {
  if (!filterinjected) {
    return;
  }
  filterinjected = false;

  console.log('removing chat filter');
  if(chatListener != null) {
    chatListener.disconnect();
  }

  if(filterInput != null) {
    filterInput.remove();
  }
};

const injectFilter = () => {
  if (filterinjected) {
    return;
  }
  filterinjected = true;
  console.log('injecting chat filter');
  const chatContents = document.querySelector('.chat-log-scroll-inner');

  const refreshLineHighlight = (line) => {
    const name = line.querySelector('.chat-line-name-content').innerText;
    if (namesFilter.length == 0 || !namesFilter[0]) {
      // line.classList.remove('highlight');
      line.classList.remove('hidden');
      return;
    }
    for (let n of namesFilter) {
      if (name.toLowerCase().includes(n.toLowerCase())) {
        // line.classList.add('highlight');
        line.classList.remove('hidden');
        break;
      } else {
        // line.classList.remove('highlight');
        line.classList.add('hidden');
      }
    }
  };

  const refreshAllHighlight = () => {
    chatContents.querySelectorAll('.chat-line').forEach((line) => refreshLineHighlight(line));
  };

  filterInput = document.createElement('input');
  filterInput.type = 'text';
  filterInput.classList.add('filter-line');
  filterInput.style.minWidth = '300px';
  filterInput.placeholder = 'Filtrar Nombres (separado por comas)';
  filterInput.onkeydown = (e) => {
    if (e.code == 'Escape' || e.code == 'Enter') {
      e.target.blur();
    }
  };
  filterInput.oninput = (e) => {
    namesFilter = e.target.value
      .split(',')
      .map((s) => s.trim())
      .filter((s) => s);
    refreshAllHighlight();
  };
  document.querySelector('.chat-log-tabs').appendChild(filterInput);

  chatListener = new MutationObserver((mutations, obs) => {
    mutations.forEach((mutation) => {
      mutation.addedNodes.forEach((line) => {
        refreshLineHighlight(line);
      });
    });
  });
  chatListener.observe(chatContents, { childList: true });
};

playingListener = new MutationObserver((mutations, obs) => {
  mutations.forEach((mutation) => {
    if (mutation.attributeName === 'class') {
      if(mutation.target.classList.contains('playing')){
        setTimeout(injectFilter, 1000);
      } else {
        uninjectFilter();
      }
    }
  });
})
playingListener.observe(document.querySelector('body'), { attributes: true });

    //COMIENZA AUTO RECONECTAR

    // Función para verificar el estado de conexión
    function checkConnection() {
        if (document.body.innerText.includes("Disconnected") || document.body.innerText.includes("Error")) {
            console.log("Desconectado. Intentando reconectar...");
            reconnect();
        } else {
            console.log("Conectado.");
        }
    }

    // Función para reconectar
    function reconnect() {
        // Aquí puedes agregar cualquier lógica adicional que necesites para reconectar
        setTimeout(() => {
            window.location.reload();
        }, 3000); // Espera 3 segundos antes de recargar
    }

    // Función para hacer clic en el botón "Play"
    function clickPlayButton() {
        const playButton = [...document.querySelectorAll('div strong')]
            .find(el => el.innerText.includes("Play"));

        if (playButton) {
            console.log("Esperando 10 segundos antes de hacer clic en el botón 'Play'...");
            setTimeout(() => {
                console.log("Haciendo clic en el botón 'Play'...");
                playButton.click();
            }, 5000); // Espera 5 segundos antes de hacer clic
        }
    }

    // Intervalo para verificar la conexión cada 3 segundos
    setInterval(checkConnection, 3000);

    // Observador de mutaciones para detectar cambios en el DOM
    const observer = new MutationObserver(() => {
        if (document.location.href === "https://pony.town/") {
            clickPlayButton();
        }
    });

    // Comenzar a observar el body
    observer.observe(document.body, { childList: true, subtree: true });
})();