您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
(我已经安装了用户样式管理器,让我安装!)
// ==UserScript==
// @name Character.AI Auto-Requester
// @namespace http://tampermonkey.net/
// @version 2.95555556
// @license GNU GPLv3
// @description Автоматическая отправка сообщений с настройкой интервалов
// @match https://character.ai/chat*
// @author xPress
// @grant GM_addStyle
// ==/UserScript==
//TODO: Слайдер для .control-overlay scale
(function() {
'use strict';
// Начальные значения
let delayVoice = 10000;
let interval = 30000;
let timer;
// Стили для оверлея
GM_addStyle(`
.control-overlay {
user-select: none;
position: absolute;
top: 50%; /* или любое другое фиксированное значение */
left: 50%;
background: rgba(255,255,255,0.8);
padding: 15px;
border-radius: 8px;
color: black;
z-index: 9999;
min-width: 250px;
width: 350px;
max-height: 800px; /* Максимальная высота */
transition: max-height 0.4s ease-in-out;
transform: translate(-50%, -100px) scale(0.9);
transform-origin: top left; /* или center, в зависимости от нужного эффекта */
}
.slider-container {
margin: 10px 0;
}
input[type="range"] {
width: 100%;
margin: 5px 0;
-webkit-appearance: none;
background: transparent;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: lime;
cursor: pointer;
margin-top: -6px;
}
input[type="range"]::-moz-range-thumb {
height: 16px;
width: 16px;
border-radius: 50%;
background: lime;
cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
cursor: pointer;
background: #c9c9c9;
border-radius: 2px;
}
input[type="range"]::-moz-range-track {
width: 100%;
height: 4px;
cursor: pointer;
background: #c9c9c9;
border-radius: 2px;
}
.value-display {
font-size: 14px;
margin-top: 5px;
}
.header {
cursor: move;
padding: 0 10px;
background: rgba(255,255,255,0.5);
border-bottom: 1px solid #333;
}
.minimized {
max-height: 53px;
overflow: hidden;
}
.control-overlay:not(.minimized) .content {
opacity: 1;
transition: opacity 0.4s ease-in-out;
}
.control-overlay.minimized .content {
opacity: 0;
transition: opacity 0.4s ease-in-out;
}
.switch-container {
margin: 10px 0;
}
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.switch-container label {
margin: 15px 35px;
font-size: 24px;
margin-top: 23px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: lime;
}
input:focus + .slider {
box-shadow: 0 0 1px lime;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
.description {
font-size: 12px;
text-indent: 25px;
line-height: 11px;
color: gray;
}
.description p {
margin-top: 5px; /* Отступ сверху */
margin-bottom: 5px; /* Отступ снизу */
color: gray
}
`);
const textFieldXPath = '//*[@id="chat-body"]/div[2]/div/div/div/div[1]/textarea';
const sendButtonXPath = '//*[@id="chat-body"]/div[2]/div/div/div/div[2]/button';
const voiceButtonXPath = '//*[@id="chat-messages"]/div[1]/div[1]/div/div/div[1]/div/div[1]/div[1]/div[2]/div[1]/div[2]/div[2]/div/button';
// Создаем элементы управления
const overlay = document.createElement('div');
overlay.className = 'control-overlay';
overlay.innerHTML = `
<div class="header">
<h3 style="margin:0; display:inline-block;">Character.AI Auto-Requester</h3>
<button class="minimize" style="float:right;">▼</button>
</div>
<div class="content">
<div class="slider-container">
<label>Задержка голоса:</label>
<input type="range" min="1" max="60" value="${delayVoice/1000}" class="voice-delay">
<div class="value-display">${delayVoice/1000} сек</div>
</div>
<div class="slider-container">
<label>Интервал сообщений:</label>
<input type="range" min="3" max="120" value="${interval/1000}" class="send-interval">
<div class="value-display">${interval/1000} сек</div>
</div>
<div class="switch-container">
<label>Вкл/Выкл</label>
<label class="switch">
<input type="checkbox" class="toggle-auto-send">
<span class="slider round"></span>
</label>
</div>
<div class="description">
Пользуйтесь аккуратно; не совсем понятно, за какие скорости могут забанить аккаунт. В любом случае даже простое использование стороннего софта типа этого, скорее всего, не приветствуется.
<p>
Осторожно, смартфон, например, может не отключать экран и не блокироваться из-за работающего скрипта. Даже в состоянии "Выкл".
<p>
Если нужна тёмная тема - включайте DarkReader; если хочется какую-то другую - Stylus. Спасибо за понимание.
</div>
</div>
`;
document.body.appendChild(overlay);
// Обработчики ползунков
overlay.querySelector('.voice-delay').addEventListener('input', function(e) {
delayVoice = e.target.value * 1000;
e.target.nextElementSibling.textContent = `${e.target.value} сек`;
// Останавливаем таймер
clearInterval(timer);
overlay.querySelector('.toggle-auto-send').checked = false;
});
let currentUrl = window.location.href;
overlay.querySelector('.send-interval').addEventListener('input', function(e) {
interval = e.target.value * 1000;
e.target.nextElementSibling.textContent = `${e.target.value} сек`;
// Останавливаем таймер
clearInterval(timer);
overlay.querySelector('.toggle-auto-send').checked = false;
});
function clickVoiceButton() {
const voiceButton = document.evaluate(
voiceButtonXPath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
voiceButton?.click();
}
function simulateSend() {
if (window.location.href !== currentUrl) {
// Останавливаем таймер
clearInterval(timer);
overlay.querySelector('.toggle-auto-send').checked = false;
currentUrl = window.location.href;
return
}
const textField = document.evaluate(
textFieldXPath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
const sendButton = document.evaluate(
sendButtonXPath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
if (textField && sendButton && !sendButton.disabled) {
const inputText = textField.value.trim();
if (inputText === '') {
sendButton.click();
textField.value = '';
setTimeout(clickVoiceButton, delayVoice);
}
}
}
// Вкл/Выкл
overlay.querySelector('.toggle-auto-send').addEventListener('change', function(e) {
if (e.target.checked) {
// Включаем автоматическую отправку
clearInterval(timer);
timer = setInterval(simulateSend, interval);
// Запоминаем страницу, на которой запустили автоотправку
let currentUrl = window.location.href;
} else {
// Выключаем автоматическую отправку
clearInterval(timer);
}
});
// Перемещение оверлея
let isDown = false;
let offset = [0, 0];
// Функция для обработки начала касания
function handleTouchStart(event) {
if (event.touches.length === 1) { // Только одно касание
isDown = true;
const touch = event.touches[0];
offset = [
overlay.offsetLeft - touch.clientX,
overlay.offsetTop - touch.clientY
];
event.preventDefault(); // Предотвратить выделение текста
}
}
// Функция для обработки движения касания
function handleTouchMove(event) {
if (isDown) {
const touch = event.touches[0];
overlay.style.top = `${touch.clientY + offset[1]}px`;
overlay.style.right = 'auto'; // Чтобы не было привязки к правому краю
overlay.style.left = `${touch.clientX + offset[0]}px`;
event.preventDefault(); // Предотвратить прокрутку страницы
}
}
// Функция для обработки окончания касания
function handleTouchEnd() {
isDown = false;
}
// Добавление обработчиков событий для касаний
overlay.querySelector('.header h3').addEventListener('touchstart', handleTouchStart);
document.addEventListener('touchmove', handleTouchMove);
document.addEventListener('touchend', handleTouchEnd);
// Добавление обработчиков событий для мыши (чтобы не потерять функциональность на компьютере)
overlay.querySelector('.header h3').addEventListener('mousedown', function(event) {
if (event.button === 0) { // Левая кнопка мыши
isDown = true;
offset = [
overlay.offsetLeft - event.clientX,
overlay.offsetTop - event.clientY
];
event.preventDefault(); // Предотвратить выделение текста
}
});
document.addEventListener('mouseup', function() {
isDown = false;
});
document.addEventListener('mousemove', function(event) {
if (isDown) {
overlay.style.top = `${event.clientY + offset[1]}px`;
overlay.style.right = 'auto'; // Чтобы не было привязки к правому краю
overlay.style.left = `${event.clientX + offset[0]}px`;
}
});
// Минимизация/сворачивание
overlay.querySelector('.minimize').addEventListener('click', function() {
if (overlay.classList.contains('minimized')) {
overlay.classList.remove('minimized');
this.textContent = '▼'; // Используем Unicode для символа
} else {
overlay.classList.add('minimized');
this.textContent = '▲'; // Используем Unicode для символа
}
});
})();