您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Auto message, auto disconnect/reconnect, and blacklist for Yiffspot with enhanced UI and debugging
// ==UserScript== // @name Yiffspot Chat Helper // @namespace http://tampermonkey.net/ // @version 3.1 // @license MIT // @description Auto message, auto disconnect/reconnect, and blacklist for Yiffspot with enhanced UI and debugging // @match https://www.Yiffspot.com* // @icon https://www.google.com/s2/favicons?sz=64&domain=https://www.Yiffspot.com/ // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; // Debug mode (set to true to enable debug window) const DEBUG_MODE = false; // Change to true to enable debugging // Variables for the bot settings let settings = { autoMessage: GM_getValue('autoMessage', ''), disconnectTimer: GM_getValue('disconnectTimer', 0), autoReconnect: GM_getValue('autoReconnect', 0), blacklist: GM_getValue('blacklist', []) }; let isChatConnected = false; // Tracks if a chat is currently active let messageSent = false; // Tracks if the bot has sent its auto-message let disconnectTimeout = null; // Timer for auto-disconnect let reconnectTimeout = null; // Timer for auto-reconnect let isPaused = false; // Pauses all timers/actions let blacklistTriggered = false; // Tracks if a blacklist term was triggered let blacklistTerm = ''; // Stores the triggered blacklist term let disconnectTimeRemaining = 0; let reconnectTimeRemaining = 0; let blacklistTimeout = null; // Timer for blacklist-triggered disconnect let blacklistTimeRemaining = 0; // Variable to track the active timer controlling the UI let currentActiveTimer = null; // Store the previous number of child elements in #messages let previousChildCount = 0; // Function to save settings using GM_setValue function saveSettings() { GM_setValue('autoMessage', settings.autoMessage); GM_setValue('disconnectTimer', settings.disconnectTimer); GM_setValue('autoReconnect', settings.autoReconnect); GM_setValue('blacklist', settings.blacklist); } // Function to process a node and its children function processNodeAndChildren(node) { if (node.nodeType === Node.ELEMENT_NODE) { checkBlacklistOnElement(node); // Recursively process child nodes node.querySelectorAll('*').forEach(childNode => { if (childNode.nodeType === Node.ELEMENT_NODE) { checkBlacklistOnElement(childNode); } }); } else if (node.nodeType === Node.TEXT_NODE) { checkBlacklistOnText(node.textContent); } } // Function to check for blacklist terms in an element's text content function checkBlacklistOnElement(element) { const textContent = element.textContent || ''; checkBlacklistOnText(textContent); } // Function to check for blacklist terms in text function checkBlacklistOnText(text) { if (settings.blacklist.length === 0 || blacklistTriggered) return; const lowerCaseText = text.toLowerCase(); let termFound = null; for (let term of settings.blacklist) { if (lowerCaseText.includes(term.toLowerCase())) { // Blacklist term found termFound = term; break; } } if (termFound) { if (DEBUG_MODE) console.log(`Blacklist term "${termFound}" found in text: "${text.trim()}"`); // Start the blacklist disconnect timer blacklistTriggered = true; blacklistTerm = termFound; startBlacklistDisconnectTimer(); if (DEBUG_MODE) updateDebugInfo(); } else { if (DEBUG_MODE) console.log(`No blacklist terms found in text: "${text.trim()}"`); } } // Function to start the blacklist disconnect timer function startBlacklistDisconnectTimer() { clearInterval(blacklistTimeout); if (!isPaused) { blacklistTimeRemaining = 5; // Hardcoded 5-second timer currentActiveTimer = 'blacklist'; // Set blacklist as the active timer updateCountdownDisplay(blacklistTimeRemaining, 'Disconnecting in', '#dc3545'); // Red color blacklistTimeout = setInterval(() => { if (!isPaused) { blacklistTimeRemaining--; if (currentActiveTimer === 'blacklist') { updateCountdownDisplay(blacklistTimeRemaining, 'Disconnecting in', '#dc3545'); } if (blacklistTimeRemaining <= 0) { clearInterval(blacklistTimeout); handleDisconnect(); } } }, 1000); } } // Function to cancel the blacklist disconnect function cancelBlacklistDisconnect() { if (blacklistTriggered) { clearInterval(blacklistTimeout); blacklistTriggered = false; blacklistTerm = ''; blacklistTimeRemaining = 0; hideCountdownDisplay(); currentActiveTimer = null; // Clear active timer if (isChatConnected) { startDisconnectTimer(); // Resume normal disconnect timer } if (DEBUG_MODE) updateDebugInfo(); } } // Function to manually monitor changes in the #messages element function monitorMessagesManually() { const messagesElement = document.querySelector('#messages'); // Assuming the chat messages container ID is '#messages' if (!messagesElement) { // Retry after a short delay if the element is not found setTimeout(monitorMessagesManually, 1000); return; } // Check if the child count has changed const currentChildCount = messagesElement.childElementCount; // Subtract 1 for the "partner is typing..." element if it's present const adjustedChildCount = currentChildCount > 0 ? currentChildCount - 1 : 0; if (adjustedChildCount > previousChildCount) { // Process only the new elements (up to the second to last element, excluding the "partner is typing...") for (let i = previousChildCount; i < adjustedChildCount; i++) { const newChild = messagesElement.children[i]; processNodeAndChildren(newChild); } // Reset the disconnect timer on new message if (isChatConnected) { startDisconnectTimer(); // Reset the disconnect timer } } // Update the previous child count previousChildCount = adjustedChildCount; // Re-check periodically (you can adjust the interval as needed) setTimeout(monitorMessagesManually, 1000); // Check every second } // Function to handle disconnect function handleDisconnect() { clearInterval(disconnectTimeout); clearInterval(blacklistTimeout); hideCountdownDisplay(); const disconnectButton = document.querySelector('#disconnect'); if (disconnectButton) { disconnectButton.click(); isChatConnected = false; messageSent = false; currentActiveTimer = null; // Clear active timer if (DEBUG_MODE) console.log('Disconnected from chat'); startAutoReconnectTimer(); } } // Function to start the disconnect timer function startDisconnectTimer() { clearInterval(disconnectTimeout); if (currentActiveTimer !== 'blacklist') { // Only start if blacklist is not active clearInterval(reconnectTimeout); // Pause reconnect timer clearInterval(blacklistTimeout); // Pause blacklist timer if (settings.disconnectTimer > 0 && !isPaused && isChatConnected && !blacklistTriggered) { disconnectTimeRemaining = settings.disconnectTimer; currentActiveTimer = 'disconnect'; // Set disconnect as the active timer updateCountdownDisplay(disconnectTimeRemaining, 'Disconnect in', '#28a745'); disconnectTimeout = setInterval(() => { if (!isPaused && currentActiveTimer === 'disconnect') { disconnectTimeRemaining--; updateCountdownDisplay(disconnectTimeRemaining, 'Disconnect in', '#28a745'); if (disconnectTimeRemaining <= 0) { clearInterval(disconnectTimeout); handleDisconnect(); } } }, 1000); } } } // Function to start auto reconnect timer function startAutoReconnectTimer() { clearInterval(reconnectTimeout); if (currentActiveTimer !== 'blacklist') { // Only start if blacklist is not active if (settings.autoReconnect > 0 && !isPaused) { reconnectTimeRemaining = settings.autoReconnect; currentActiveTimer = 'reconnect'; // Set reconnect as the active timer updateCountdownDisplay(reconnectTimeRemaining, 'Reconnecting in', '#28a745'); reconnectTimeout = setInterval(() => { if (!isPaused && currentActiveTimer === 'reconnect') { reconnectTimeRemaining--; updateCountdownDisplay(reconnectTimeRemaining, 'Reconnecting in', '#28a745'); if (reconnectTimeRemaining <= 0) { clearInterval(reconnectTimeout); attemptReconnect(); } } }, 1000); } } } // Function to attempt reconnect function attemptReconnect() { clearInterval(reconnectTimeout); hideCountdownDisplay(); currentActiveTimer = null; // Clear active timer const findPartnerButton = document.querySelector('#find-partner'); if (findPartnerButton) { findPartnerButton.click(); if (DEBUG_MODE) console.log('Attempting to reconnect...'); } } // Function to observe chat status function observeChatStatus() { function setupObserver() { const disconnectRow = document.querySelector('#disconnect-row'); if (disconnectRow) { // Set up a MutationObserver on the 'class' attribute const observer = new MutationObserver((mutationsList) => { mutationsList.forEach((mutation) => { if (mutation.type === 'attributes' && mutation.attributeName === 'class') { const isHidden = disconnectRow.classList.contains('hide-ele'); if (!isHidden && !isChatConnected) { // Chat connected isChatConnected = true; messageSent = false; blacklistTriggered = false; blacklistTerm = ''; if (DEBUG_MODE) console.log('Chat connected'); sendAutoMessage(); startDisconnectTimer(); if (DEBUG_MODE) updateDebugInfo(); } else if (isHidden && isChatConnected) { // Chat disconnected isChatConnected = false; messageSent = false; clearInterval(disconnectTimeout); clearInterval(reconnectTimeout); hideCountdownDisplay(); if (DEBUG_MODE) console.log('Chat disconnected'); startAutoReconnectTimer(); if (DEBUG_MODE) updateDebugInfo(); } } }); }); // Start observing 'disconnectRow' observer.observe(disconnectRow, { attributes: true, attributeFilter: ['class'] }); // Check the initial state const isHidden = disconnectRow.classList.contains('hide-ele'); if (!isHidden && !isChatConnected) { isChatConnected = true; messageSent = false; blacklistTriggered = false; blacklistTerm = ''; if (DEBUG_MODE) console.log('Chat connected (initial)'); sendAutoMessage(); startDisconnectTimer(); if (DEBUG_MODE) updateDebugInfo(); } } else { // Wait until 'disconnectRow' becomes available setTimeout(setupObserver, 1000); } } setupObserver(); } // Function to send the auto message function sendAutoMessage() { if (settings.autoMessage.trim() === '' || messageSent || !isChatConnected) return; const messageBox = document.querySelector('#message'); if (messageBox) { messageBox.value = settings.autoMessage; messageSent = true; simulateEnterKey(messageBox); if (DEBUG_MODE) console.log('Auto message sent:', settings.autoMessage); } } // Helper function to fully simulate the Enter keypress function simulateEnterKey(inputElement) { const keydownEvent = new KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13, which: 13 }); const keypressEvent = new KeyboardEvent('keypress', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13, which: 13 }); const keyupEvent = new KeyboardEvent('keyup', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13, which: 13 }); inputElement.dispatchEvent(keydownEvent); inputElement.dispatchEvent(keypressEvent); inputElement.dispatchEvent(keyupEvent); } // Function to create the control menu, countdown display, and debug window function createUI() { // Add custom styles GM_addStyle(` #chatHelperMenu { position: fixed; top: 60px; left: 10px; z-index: 10000; background-color: rgba(30, 30, 30, 0.95); border: 1px solid #555; border-radius: 8px; padding: 15px; box-shadow: 0 5px 15px rgba(0,0,0,0.5); display: none; max-width: 300px; font-family: Arial, sans-serif; font-size: 14px; color: #ddd; } #chatHelperMenu h2 { margin-top: 0; font-size: 18px; color: #fff; } #chatHelperMenu label { display: block; margin-top: 10px; color: #ccc; } #chatHelperMenu input, #chatHelperMenu textarea { width: 100%; margin-top: 5px; padding: 5px; box-sizing: border-box; font-size: 14px; background-color: #444; color: #eee; border: 1px solid #666; } #chatHelperMenu button { padding: 8px 12px; margin-top: 15px; font-size: 14px; cursor: pointer; background-color: #007BFF; color: white; border: none; border-radius: 5px; } #chatHelperMenuClose { position: absolute; top: 5px; right: 5px; cursor: pointer; font-size: 16px; color: #fff; } #chatHelperButton { position: fixed; top: 10px; left: 10px; z-index: 10000; padding: 10px; font-size: 20px; background-color: #007BFF; color: white; border: none; border-radius: 5px; cursor: pointer; } #chatHelperCountdown { position: fixed; top: 15px; left: 70px; z-index: 10000; padding: 8px 12px; font-size: 14px; background-color: #28a745; color: white; border-radius: 5px; cursor: pointer; display: none; } #chatHelperDebug { position: fixed; bottom: 10px; left: 10px; z-index: 10000; background-color: rgba(0, 0, 0, 0.8); color: #fff; padding: 10px; border-radius: 5px; font-family: monospace; font-size: 12px; display: none; max-width: 300px; word-wrap: break-word; white-space: pre-line; } `); // Create menu container const menuContainer = document.createElement('div'); menuContainer.id = 'chatHelperMenu'; // Create menu content menuContainer.innerHTML = ` <span id="chatHelperMenuClose">×</span> <h2>Chat Helper Settings</h2> <label for="autoMessage">Auto Message:</label> <textarea id="autoMessage" rows="3"></textarea> <label for="disconnectTimer">Disconnect Timer (sec):</label> <input type="number" id="disconnectTimer" min="0"> <label for="autoReconnect">Auto Reconnect Timer (sec):</label> <input type="number" id="autoReconnect" min="0"> <label for="blacklist">Blacklist (comma-separated, quote-wrapped):</label> <textarea id="blacklist" rows="3" placeholder='"term1", "term2", "term3"'></textarea> <button id="saveSettings">Save</button> `; document.body.appendChild(menuContainer); // Create menu toggle button const menuButton = document.createElement('button'); menuButton.id = 'chatHelperButton'; menuButton.textContent = '⚙️'; document.body.appendChild(menuButton); // Create countdown display const countdownDisplay = document.createElement('div'); countdownDisplay.id = 'chatHelperCountdown'; countdownDisplay.textContent = ''; document.body.appendChild(countdownDisplay); // Create debug window if DEBUG_MODE is true if (DEBUG_MODE) { const debugWindow = document.createElement('div'); debugWindow.id = 'chatHelperDebug'; document.body.appendChild(debugWindow); } // Load settings into UI document.getElementById('autoMessage').value = settings.autoMessage; document.getElementById('disconnectTimer').value = settings.disconnectTimer; document.getElementById('autoReconnect').value = settings.autoReconnect; document.getElementById('blacklist').value = settings.blacklist.map(term => `"${term}"`).join(', '); // Menu button click event (toggle) menuButton.addEventListener('click', () => { if (menuContainer.style.display === 'none' || menuContainer.style.display === '') { menuContainer.style.display = 'block'; } else { menuContainer.style.display = 'none'; } }); // Close menu button click event document.getElementById('chatHelperMenuClose').addEventListener('click', () => { menuContainer.style.display = 'none'; }); // Save settings button click event document.getElementById('saveSettings').addEventListener('click', () => { settings.autoMessage = document.getElementById('autoMessage').value.trim(); settings.disconnectTimer = parseInt(document.getElementById('disconnectTimer').value, 10) || 0; settings.autoReconnect = parseInt(document.getElementById('autoReconnect').value, 10) || 0; const blacklistInput = document.getElementById('blacklist').value.trim(); settings.blacklist = parseBlacklistInput(blacklistInput); saveSettings(); menuContainer.style.display = 'none'; // Apply settings immediately if (isChatConnected) { startDisconnectTimer(); // Other settings will naturally take effect } if (DEBUG_MODE) updateDebugInfo(); }); // Countdown display click event (toggle pause or cancel blacklist disconnect) countdownDisplay.addEventListener('click', () => { if (currentActiveTimer === 'blacklist') { cancelBlacklistDisconnect(); } else { // Toggle pause isPaused = !isPaused; if (isPaused) { clearInterval(disconnectTimeout); clearInterval(reconnectTimeout); clearInterval(blacklistTimeout); countdownDisplay.style.backgroundColor = '#ffc107'; // Yellow for paused countdownDisplay.textContent = 'Paused'; // Show "Paused" text } else { countdownDisplay.style.backgroundColor = '#28a745'; // Green for active if (blacklistTriggered) { startBlacklistDisconnectTimer(); } else if (isChatConnected) { startDisconnectTimer(); } else { startAutoReconnectTimer(); } } if (DEBUG_MODE) updateDebugInfo(); } }); // Store references for later use uiElements = { menuContainer, menuButton, countdownDisplay, debugWindow: DEBUG_MODE ? document.getElementById('chatHelperDebug') : null }; } // Function to parse the blacklist input function parseBlacklistInput(input) { const regex = /"([^"]+)"/g; let terms = []; let match; while ((match = regex.exec(input)) !== null) { terms.push(match[1]); } return terms; } // UI elements reference let uiElements = {}; // Function to update countdown display function updateCountdownDisplay(timeRemaining, text, color) { const display = uiElements.countdownDisplay; if (display) { display.textContent = `${text} ${timeRemaining}s`; display.style.display = 'block'; display.style.backgroundColor = color; } if (DEBUG_MODE) updateDebugInfo(); } // Function to hide countdown display function hideCountdownDisplay() { const display = uiElements.countdownDisplay; if (display) { display.style.display = 'none'; } } // Function to update debug information function updateDebugInfo() { if (DEBUG_MODE && uiElements.debugWindow) { let debugText = `Chat Helper Debug Info:\n`; debugText += `Chat Connected: ${isChatConnected}\n`; debugText += `Paused: ${isPaused}\n`; debugText += `Blacklist Triggered: ${blacklistTriggered}\n`; if (blacklistTriggered) { debugText += `Blacklist Term: "${blacklistTerm}"\n`; debugText += `Blacklist Timer: ${blacklistTimeRemaining}s\n`; } if (!blacklistTriggered && isChatConnected) { debugText += `Disconnect Timer: ${disconnectTimeRemaining}s\n`; } if (!isChatConnected) { debugText += `Reconnect Timer: ${reconnectTimeRemaining}s\n`; } uiElements.debugWindow.textContent = debugText; uiElements.debugWindow.style.display = 'block'; } } // Initialize the script function init() { createUI(); // Start manually monitoring messages monitorMessagesManually(); // Start observing chat status observeChatStatus(); } // Run the initialization function init(); })();