A comment on A review on Janitor AI - Automatic Message Formatting Corrector (Settings Menu) by caret was reported 13.11.2025 for Спам
caret said:
My homemade fix:
// ==UserScript== // @name Janitor AI - Automatic Message Formatting Corrector (Drag & Drop button) // @namespace http://tampermonkey.net/ // @version 7.1 // @description Draggable button with visual feedback! Remembers its position, adapts to screen size, and can't be dragged off-screen. Formats narration/dialogues. // @author accforfaciet // @match *://janitorai.com/chats/* // @grant GM_addStyle // @run-at document-idle // @license MIT // @downloadURL https://update.greasyfork.org/scripts/551458/Janitor%20AI%20-%20Automatic%20Message%20Formatting%20Corrector%20%28Drag%20%20Drop%20button%29.user.js // @updateURL https://update.greasyfork.org/scripts/551458/Janitor%20AI%20-%20Automatic%20Message%20Formatting%20Corrector%20%28Drag%20%20Drop%20button%29.meta.js // ==/UserScript== (function() { 'use strict'; // --- SCRIPT SETTINGS --- const DEBUG_MODE = true; const BUTTON_POSITION_KEY = 'formatterButtonPosition'; // --- UNIVERSAL SELECTORS --- const EDIT_BUTTON_SELECTOR = 'button[title="Edit Message"], button[aria-label="Edit"]'; const TEXT_AREA_SELECTOR = 'textarea[style*="font-size:16px"], textarea[style*="font-size: 16px"], textarea[class*="_autoResizeTextarea"]'; const CONFIRM_BUTTON_SELECTOR = 'button[aria-label="Confirm"], button[aria-label="Save"], button[aria-label*="Confirm"], button[aria-label*="Save"]'; // --- DEBUGGING TOOLS --- function debugLog(...args) { if (DEBUG_MODE) console.log('[DEBUG]', ...args); } function waitForElement(selector, timeoutMs = 10000) { return new Promise(resolve => { let el = document.querySelector(selector); if (el) { debugLog(`Element found immediately: ${selector}`); return resolve(el); } debugLog(`Waiting for element: ${selector}`); const startTime = Date.now(); const observer = new MutationObserver(() => { const elapsed = Date.now() - startTime; if (elapsed > timeoutMs) { observer.disconnect(); debugLog(`Timeout (${timeoutMs}ms) waiting for: ${selector}`); return resolve(null); } el = document.querySelector(selector); if (el) { observer.disconnect(); debugLog(`Element found after ${elapsed}ms: ${selector}`); return resolve(el); } }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); }); } // --- CORE TEXT PROCESSING FUNCTIONS --- function removeThinkTags(text) { text = text.replace(/\n?\s*<(thought|thoughts)>[\s\S]*?<\/(thought|thoughts)>\s*\n?/g, ''); text = text.replace(/<(system|response)>|<\/response>/g, ''); text = text.replace(/\n?\s*<think>[\s\S]*?<\/think>\s*\n?/g, ''); text = text.replace('</think>', ''); return removeSystemPrompt(text); } function formatNarrationAndDialogue(text) { text = removeThinkTags(text); const normalizedText = text.replace(/[«“”„‟⹂❞❝]/g, '"'); const lines = normalizedText.split('\n'); return lines.map(line => { const trimmedLine = line.trim(); if (trimmedLine === '') return ''; const cleanLine = trimmedLine.replace(/\*/g, ''); if (cleanLine.includes('"') || cleanLine.includes('`')) { return cleanLine.split(/("[\s\S]*?"|`[\s\S]*?`)/) .map(frag => { if ((frag.startsWith('"') && frag.endsWith('"')) || (frag.startsWith('`') && frag.endsWith('`'))) return frag; return frag.trim() !== '' ? `*${frag.trim()}*` : ''; }).filter(Boolean).join(' '); } return `*${cleanLine}*`; }).join('\n'); } function removeSystemPrompt(text) { if (!text.trim().toLowerCase().includes('theuser')) return text; const splitPointIndex = text.search(/[^\s\*]\*[^\s\*]/); if (splitPointIndex !== -1) { debugLog(`System prompt found. Text trimmed.`); return text.substring(splitPointIndex + 1); } return text; } // --- MAIN ACTION SEQUENCE --- async function processLastMessage(textProcessor) { debugLog('--- STARTING EDIT PROCESS ---'); try { const allEditButtons = document.querySelectorAll(EDIT_BUTTON_SELECTOR); debugLog(`Found ${allEditButtons.length} edit buttons`); if (allEditButtons.length === 0) { debugLog('STOP: No edit buttons found.'); return; } const lastEditButton = allEditButtons[allEditButtons.length - 1]; debugLog('Clicking last edit button'); lastEditButton.click(); debugLog('Edit button clicked, waiting 800ms for modal'); await new Promise(resolve => setTimeout(resolve, 800)); const textField = await waitForElement(TEXT_AREA_SELECTOR); if (!textField) { debugLog('STOP: Text field not found'); return; } debugLog('Text field found'); const originalText = textField.value; debugLog(`Original text length: ${originalText.length}`); const newText = textProcessor(originalText); debugLog(`New text length: ${newText.length}`); textField.value = newText; textField.dispatchEvent(new Event('input', { bubbles: true })); textField.dispatchEvent(new Event('change', { bubbles: true })); debugLog('Text updated, events dispatched'); const confirmButton = await waitForElement(CONFIRM_BUTTON_SELECTOR, 5000); if (!confirmButton) { debugLog('STOP: Confirm button not found'); return; } debugLog('Confirm button found, clicking'); confirmButton.click(); debugLog('--- PROCESS COMPLETED SUCCESSFULLY ---'); } catch (error) { debugLog('ERROR in process:', error.message); console.error('CRITICAL ERROR during edit process:', error); } } // --- DRAGGABLE BUTTON --- function makeButtonDraggable(button) { let isDragging = false; let wasDragged = false; let offsetX, offsetY; const savedPosition = localStorage.getItem(BUTTON_POSITION_KEY); if (savedPosition) { const { top, left } = JSON.parse(savedPosition); button.style.top = top; button.style.left = left; button.style.right = 'auto'; button.style.bottom = 'auto'; } function dragStart(e) { e.preventDefault(); isDragging = true; wasDragged = false; button.classList.add('is-dragging'); const clientX = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX; const clientY = e.type === 'touchstart' ? e.touches[0].clientY : e.clientY; offsetX = clientX - button.getBoundingClientRect().left; offsetY = clientY - button.getBoundingClientRect().top; document.addEventListener('mousemove', dragMove); document.addEventListener('touchmove', dragMove, { passive: false }); document.addEventListener('mouseup', dragEnd); document.addEventListener('touchend', dragEnd); } function dragMove(e) { if (!isDragging) return; e.preventDefault(); wasDragged = true; const clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX; const clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY; let newLeft = clientX - offsetX; let newTop = clientY - offsetY; const buttonRect = button.getBoundingClientRect(); newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - buttonRect.width)); newTop = Math.max(0, Math.min(newTop, window.innerHeight - buttonRect.height)); button.style.right = 'auto'; button.style.bottom = 'auto'; button.style.left = `${newLeft}px`; button.style.top = `${newTop}px`; } function dragEnd() { if (!isDragging) return; isDragging = false; button.classList.remove('is-dragging'); document.removeEventListener('mousemove', dragMove); document.removeEventListener('touchmove', dragMove); document.removeEventListener('mouseup', dragEnd); document.removeEventListener('touchend', dragEnd); if (wasDragged) { const pos = { top: button.style.top, left: button.style.left }; localStorage.setItem(BUTTON_POSITION_KEY, JSON.stringify(pos)); } else { processLastMessage(formatNarrationAndDialogue); } } button.addEventListener('mousedown', dragStart); button.addEventListener('touchstart', dragStart, { passive: false }); } function createTriggerButton() { const buttonContainer = document.createElement('div'); buttonContainer.id = 'janitor-editor-buttons'; document.body.appendChild(buttonContainer); const formatButton = document.createElement('button'); formatButton.innerHTML = '✏️'; formatButton.id = 'formatterTrigger'; formatButton.title = 'Format asterisks (Click) or Move Button (Drag)'; buttonContainer.appendChild(formatButton); makeButtonDraggable(formatButton); } // --- MOBILE KEYBOARD FIX --- async function initKeyboardBugFix() { try { const mainInput = await waitForElement('textarea[placeholder^="Type a message"]', 10000); const buttonContainer = document.getElementById('janitor-editor-buttons'); if (!mainInput || !buttonContainer) return; mainInput.addEventListener('focus', () => { buttonContainer.style.display = 'none'; }); mainInput.addEventListener('blur', () => { setTimeout(() => { buttonContainer.style.display = 'block'; }, 200); }); } catch (e) {} } // --- ADAPTIVE STYLES --- GM_addStyle(` #janitor-editor-buttons button { position: fixed; z-index: 9999; color: white; border: none; border-radius: 50%; box-shadow: 0 4px 8px rgba(0,0,0,0.3); cursor: pointer; transition: transform 0.2s, opacity 0.2s, box-shadow 0.2s; user-select: none; } #janitor-editor-buttons button:active { transform: scale(0.95); } #formatterTrigger { background-color: #c9226e; } #janitor-editor-buttons button.is-dragging { transform: scale(1.1); opacity: 0.8; box-shadow: 0 8px 16px rgba(0,0,0,0.4); transition: none; } @media (min-width: 769px) { #formatterTrigger { width: 50px; height: 50px; font-size: 24px; right: 27%; bottom: 12%; } } @media (max-width: 768px) { #formatterTrigger { width: 40px; height: 40px; font-size: 16px; right: 28%; bottom: 20%; } } `); // --- LAUNCH --- createTriggerButton(); initKeyboardBugFix(); console.log('Script "Janitor AI - Automatic Message Formatting Corrector" (v7.1) launched.'); })();
caret (the reported user) has made:
This report has been dismissed by a moderator.
