// ==UserScript== // @name Chat-Mods // @namespace http://tampermonkey.net/ // @version 2026-03-27 // @description Change Comchat functionality // @author Anonymous // @match https://chat.guro.cx/ // @icon https://www.google.com/s2/favicons?sz=64&domain=guro.cx // @grant none // ==/UserScript== (function () { 'use strict'; console.log('Chat-Mods loaded'); const frames = document.querySelector('frameset'); const formFrame = document.querySelector('frame[name="form"]'); const logFrame = document.querySelector('frame[name="log"]'); let formDoc; let form; if (!frames || !formFrame || !logFrame) return; frames.setAttribute('rows', '0,*'); frames.setAttribute('frameborder', '0'); frames.setAttribute('border', '0'); frames.setAttribute('framespacing', '0'); logFrame.src = 'http://localhost:4200?framed=true'; const iframe = document.createElement('iframe'); iframe.name = 'hidden_frame'; iframe.style.display = 'none'; document.body.appendChild(iframe); function extractError(body) { if (!body) return 'Page not loaded'; const html = body.innerHTML; if (!html.includes('([3-5]\d\d\b.+)<\/h2>/.exec(html) || [])[1] || 'Unknown error'; return null; } function enterChatRoom(name, email, color) { const nameField = formDoc.querySelector('input[name="name"]'); const emailField = formDoc.querySelector('input[name="email"]'); if (!nameField || !emailField) return; // Already in chat let tripCode; [name, tripCode] = name.split('#'); if (tripCode) localStorage.setItem('password', tripCode); const colorButton = formDoc.querySelector(`input[type="radio"][value="${color}"]`); const submitButton = formDoc.querySelector('input[type="submit"]'); formDoc.querySelector('form').setAttribute('target', '_self'); nameField.value = name; emailField.value = email || ''; colorButton?.click(); submitButton.click(); let tries = 0; // Wait for the form to load const formCheck = () => { formDoc = formFrame.contentDocument; form = formDoc.querySelector('form'); const formError = extractError(formDoc.body); if (formError) logFrame.postMessage(['enterChatRoom', formError], '*'); else if (formDoc.querySelector('input[name="comment"]')) logFrame.contentWindow.postMessage(['enterChatRoom', null], '*'); else if (++tries < 30) setTimeout(formCheck, 100); else logFrame.postMessage(['enterChatRoom', 'Timed out'], '*'); }; formCheck(); } const messageSubmitter = evt => { evt.preventDefault(); const formData = new FormData(form); fetch(form.action, { method: form.method, body: formData, }) .then(response => { if (response.ok) { formDoc.querySelector('input[name="comment"]').value = ''; logFrame.postMessage(['sendChatMessage', null], '*'); } else logFrame.postMessage(['sendChatMessage', `Sending message failed with status ${response.status}`], '*'); }) .catch(error => { logFrame.postMessage(['sendChatMessage', `Sending message failed with error: ${error.message || error.toString()}`], '*'); }); }; function sendChatMessage(comment, color, tripCode) { let face = ''; const $ = /^(.*)(\u2000(.+)\u2000)\s*$/.exec(comment); if ($) { comment = $[1]; face = $[3]; } formDoc.querySelector('select[name="color"]').value = color; formDoc.querySelector('#face').value = face; formDoc.querySelector('input[name="comment"]').value = comment; formDoc.querySelector('input[name="password"]').value = tripCode; formDoc.querySelector('form').setAttribute('target', 'hidden_frame'); form.removeEventListener('submit', messageSubmitter); // Make sure we don't double-submit form.addEventListener('submit', messageSubmitter); formDoc.querySelector('form').submit(); } window.addEventListener('message', evt => { formDoc = formFrame.contentDocument; form = formDoc.querySelector('form'); switch (evt.data[0]) { case 'enterChatRoom': enterChatRoom(evt.data[1], evt.data[2], evt.data[3]); break; case 'sendChatMessage': sendChatMessage(evt.data[1], evt.data[2], evt.data[3]); break; } }); })();