// ==UserScript== // @name Auto Scroll Chat Enhancer // @namespace http://tampermonkey.net/ // @version 2024-04-03 // @description Streamline your character.ai chat experience with the Auto Scroll Chat Enhancer! This script features a control panel with "Start" and "Stop" for key press simulations and an "Auto Scroll" toggle. Activate "Auto Scroll" to automatically view the latest messages, keeping you in the conversation flow seamlessly. Perfect for users seeking an efficient chatting experience. // @author anonymous // @match https://character.ai/chat/* // @icon https://www.google.com/s2/favicons?sz=64&domain=character.ai // @grant none // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 自动滚动状态变量 let autoScrollEnabled = true; // 控制面板设置 const controlPanel = document.createElement('div'); controlPanel.style.position = 'fixed'; controlPanel.style.top = '0'; controlPanel.style.left = '0'; controlPanel.style.zIndex = '10000'; controlPanel.style.display = 'flex'; controlPanel.style.gap = '10px'; // 按钮间距 document.body.appendChild(controlPanel); const startButton = document.createElement('button'); startButton.textContent = '开始'; controlPanel.appendChild(startButton); const stopButton = document.createElement('button'); stopButton.textContent = '停止'; controlPanel.appendChild(stopButton); // 创建自动滚动控制按钮 const autoScrollButton = document.createElement('button'); autoScrollButton.textContent = `自动滚动: ${autoScrollEnabled ? 'on' : 'off'}`; controlPanel.appendChild(autoScrollButton); // 为自动滚动按钮添加点击事件监听器 autoScrollButton.addEventListener('click', () => { autoScrollEnabled = !autoScrollEnabled; // 切换自动滚动状态 autoScrollButton.textContent = `自动滚动: ${autoScrollEnabled ? 'on' : 'off'}`; // 更新按钮文本 // 如果自动滚动被启用,立即执行一次滚动 if (autoScrollEnabled) { Array.from(box.children).pop()?.scrollIntoView(false); } }); // 添加样式 const style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = ` .swiper-no-swiping.box-item { background-color: var(--surface-elevation-2); margin: 0 5px 15px 8px; border-radius: 15px; padding: 5px 10px; cursor: pointer; /* 添加手形光标表示可点击 */ } `; document.head.appendChild(style); // 模拟按键操作 function simulateKeyPress(keyCode) { let event = document.createEvent('Event'); event.initEvent('keydown', true, false); event = Object.assign(event, { ctrlKey: false, metaKey: false, altKey: false, which: keyCode, keyCode: keyCode, key: keyCode === 37 ? 'ArrowLeft' : 'ArrowRight', code: keyCode === 37 ? 'ArrowLeft' : 'ArrowRight' }); document.dispatchEvent(event); } let intervalId; // 点击开始按钮 startButton.addEventListener('click', () => { console.log('开始模拟按键'); start(); }); function start(){ if(intervalId) clearInterval(intervalId); document.querySelector('textarea').focus(); intervalId = setInterval(() => simulateKeyPress(39), 40); } // 点击停止按钮 stopButton.addEventListener('click', () => { console.log('停止模拟按键'); stop(); }); function stop(){ clearInterval(intervalId); } // 显示内容的box const box = document.createElement('div'); box.style.position = 'fixed'; box.style.top = '50px'; box.style.left = '0'; box.style.width = '50%'; box.style.height = '94vh'; box.style.overflow = 'scroll'; document.body.appendChild(box); let cache = ''; // 更新box中的内容以匹配swiper-wrapper的当前状态 function updateBoxContent() { const swiperWrapper = document.querySelector('.swiper-wrapper'); if (swiperWrapper) { if(swiperWrapper.innerText===cache) return; cache = swiperWrapper.innerText; if(swiperWrapper.children.length<3){ start(); } box.innerHTML = ''; // 清空现有内容 const elements = swiperWrapper.querySelectorAll('.swiper-no-swiping'); elements.forEach((element, index) => { const clone = element.cloneNode(true); clone.classList.add('box-item'); clone.addEventListener('dblclick', () => { stop(); const a = Array.from(box.children).indexOf(clone); const b = Array.from(swiperWrapper.children).indexOf(document.querySelector('.swiper-wrapper > .swiper-slide-active')); const difference = a - b; console.error(a,b) if (difference < 0) { for (let i = 0; i < Math.abs(difference); i++) { simulateKeyPress(37); // 按下左箭头 } } else { for (let i = 0; i < difference; i++) { simulateKeyPress(39); // 按下右箭头 } } }); box.appendChild(clone); }); // 当自动滚动开启时,自动滚动到最新内容 if (autoScrollEnabled) { Array.from(box.children).pop()?.scrollIntoView(false); } } } function setupObserver() { // 选择更高级别的元素作为观察目标,例如 body 或特定容器 const container = document.body; let check = Date.now(); const observer = new MutationObserver((mutations, obs) => { if(document.querySelector('div[role=dialog')){ stop(); return; } if(Date.now()-check<1000) return; // 每次变动时检查.swiper-wrapper是否存在 const swiperWrapper = document.querySelector('.swiper-wrapper'); if (swiperWrapper) { check = Date.now() updateBoxContent(); } }); // 监视元素的子元素变化 observer.observe(container, { childList: true, subtree: true }); } setupObserver(); })();