CollabVM Autotype Pro

Автоматический ввод текста в CollabVM

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

// ==UserScript==
// @name         CollabVM Autotype Pro
// @namespace    https://greasyfork.org/users/yourprofile
// @version      2.1
// @description  Автоматический ввод текста в CollabVM
// @author       YourName
// @match        https://computernewb.com/collab-vm/*
// @match        http://computernewb.com/collab-vm/*
// @match        https://collabvm.com/*
// @match        http://collabvm.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    let active = false;
    let stopFlag = false;
    let ws = null;
    let panelVisible = true;

    function findWebSocket() {
        if (window.collabVM?.socket) { ws = window.collabVM.socket; return true; }
        if (window.ws) { ws = window.ws; return true; }
        if (window.socket) { ws = window.socket; return true; }
        return false;
    }

    function sendChar(char) {
        if (!ws || ws.readyState !== WebSocket.OPEN) {
            findWebSocket();
            if (!ws || ws.readyState !== WebSocket.OPEN) return false;
        }
        ws.send(JSON.stringify([3, char]));
        return true;
    }

    function playSound() {
        try {
            let audio = new Audio('data:audio/wav;base64,UklGRnoAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoAAACBhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqFhYqF');
            audio.volume = 0.3;
            audio.play();
        } catch(e) {}
    }

    async function typeText(text, delay, repeat, statusDiv) {
        if (!findWebSocket()) {
            statusDiv.innerText = "❌ WebSocket не найден";
            return false;
        }
        
        let total = text.length * repeat;
        let current = 0;
        
        for (let r = 0; r < repeat; r++) {
            for (let i = 0; i < text.length; i++) {
                if (stopFlag) {
                    statusDiv.innerText = "⏹ Остановлено";
                    return false;
                }
                sendChar(text[i]);
                current++;
                statusDiv.innerText = `⌨ ${current}/${total}`;
                await new Promise(r => setTimeout(r, delay));
            }
        }
        return true;
    }

    function createPanel() {
        if (document.getElementById('cvm-autotype-panel')) return;
        
        let panel = document.createElement('div');
        panel.id = 'cvm-autotype-panel';
        panel.style.cssText = `position:fixed; bottom:10px; right:10px; background:#1a1a2e; color:#eee; padding:12px; z-index:9999; border-radius:8px; width:280px; font-family:'Segoe UI',Arial,sans-serif; font-size:13px; box-shadow:0 4px 12px rgba(0,0,0,0.3); border:1px solid #16213e;`;
        
        panel.innerHTML = `
            <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:8px;">
                <div style="font-weight:bold; color:#e94560;">🤖 CollabVM Autotype</div>
                <button id="cvm-autotype-hide" style="background:none; border:none; color:#666; cursor:pointer; font-size:16px;">✕</button>
            </div>
            
            <textarea id="cvm-autotype-text" style="width:100%; margin:5px 0; padding:6px; background:#0f3460; color:#fff; border:none; border-radius:4px; box-sizing:border-box; font-family:monospace;" rows="2" placeholder="Введите текст..."></textarea>
            
            <div style="margin:5px 0;">
                <button class="cvm-preset" data-text="Hello World!" style="background:#16213e; border:1px solid #0f3460; color:#fff; padding:2px 8px; border-radius:3px; cursor:pointer; font-size:11px;">Hello</button>
                <button class="cvm-preset" data-text="Test 123" style="background:#16213e; border:1px solid #0f3460; color:#fff; padding:2px 8px; border-radius:3px; cursor:pointer; font-size:11px;">Test</button>
                <button class="cvm-preset" data-text="Lorem ipsum" style="background:#16213e; border:1px solid #0f3460; color:#fff; padding:2px 8px; border-radius:3px; cursor:pointer; font-size:11px;">Lorem</button>
                <button class="cvm-preset" data-text="1234567890" style="background:#16213e; border:1px solid #0f3460; color:#fff; padding:2px 8px; border-radius:3px; cursor:pointer; font-size:11px;">123</button>
            </div>
            
            <div style="display:flex; gap:8px; margin:5px 0;">
                <div style="flex:1;">
                    <label style="font-size:12px;">⏱ Задержка:</label>
                    <input type="number" id="cvm-autotype-delay" style="width:100%; margin-top:2px; padding:3px; background:#0f3460; color:#fff; border:none; border-radius:4px;">
                </div>
                <div style="flex:1;">
                    <label style="font-size:12px;">🔄 Повторы:</label>
                    <input type="number" id="cvm-autotype-repeat" value="1" min="1" max="99" style="width:100%; margin-top:2px; padding:3px; background:#0f3460; color:#fff; border:none; border-radius:4px;">
                </div>
            </div>
            
            <div style="display:flex; gap:8px; margin:8px 0;">
                <button id="cvm-autotype-start" style="flex:1; background:#2ecc71; color:#fff; border:none; padding:6px; border-radius:4px; cursor:pointer;">▶ Старт</button>
                <button id="cvm-autotype-stop" style="flex:1; background:#e74c3c; color:#fff; border:none; padding:6px; border-radius:4px; cursor:pointer;">⏹ Стоп</button>
            </div>
            
            <div id="cvm-autotype-status" style="font-size:11px; color:#aaa; text-align:center;">🟡 Ожидание</div>
            <div style="font-size:10px; color:#555; text-align:center; margin-top:5px;">
                💾 Сохраняется | 🎵 Звук по окончании
            </div>
        `;
        document.body.appendChild(panel);
        
        let textarea = document.getElementById('cvm-autotype-text');
        let delayInput = document.getElementById('cvm-autotype-delay');
        let repeatInput = document.getElementById('cvm-autotype-repeat');
        let statusDiv = document.getElementById('cvm-autotype-status');
        
        textarea.value = localStorage.getItem('cvm_autotype_text') || '';
        delayInput.value = localStorage.getItem('cvm_autotype_delay') || '30';
        repeatInput.value = localStorage.getItem('cvm_autotype_repeat') || '1';
        
        textarea.onchange = () => localStorage.setItem('cvm_autotype_text', textarea.value);
        delayInput.onchange = () => localStorage.setItem('cvm_autotype_delay', delayInput.value);
        repeatInput.onchange = () => localStorage.setItem('cvm_autotype_repeat', repeatInput.value);
        
        document.querySelectorAll('.cvm-preset').forEach(btn => {
            btn.onclick = () => {
                textarea.value = btn.dataset.text;
                localStorage.setItem('cvm_autotype_text', btn.dataset.text);
                statusDiv.innerText = `📋 Выбран: ${btn.dataset.text.substring(0, 20)}${btn.dataset.text.length > 20 ? '...' : ''}`;
            };
        });
        
        document.getElementById('cvm-autotype-hide').onclick = () => {
            panelVisible = !panelVisible;
            panel.style.display = panelVisible ? '' : 'none';
        };
        
        document.getElementById('cvm-autotype-start').onclick = async () => {
            if (active) { statusDiv.innerText = "⚠ Уже работает"; return; }
            let text = textarea.value;
            let delay = parseInt(delayInput.value) || 30;
            let repeat = parseInt(repeatInput.value) || 1;
            
            if (!text.trim()) { statusDiv.innerText = "❌ Введите текст"; return; }
            if (repeat < 1) { statusDiv.innerText = "❌ Повторов должно быть >= 1"; return; }
            
            active = true;
            stopFlag = false;
            let success = await typeText(text, delay, repeat, statusDiv);
            active = false;
            
            if (!stopFlag && success) {
                statusDiv.innerText = "✅ Готово!";
                playSound();
            }
        };
        
        document.getElementById('cvm-autotype-stop').onclick = () => {
            if (active) { 
                stopFlag = true; 
                active = false; 
                statusDiv.innerText = "⏹ Остановлено"; 
            } else { 
                statusDiv.innerText = "⏸ Нет активного ввода"; 
            }
        };
        
        document.addEventListener('keydown', (e) => {
            if (e.altKey && e.code === 'KeyT') { 
                e.preventDefault(); 
                document.getElementById('cvm-autotype-start').click(); 
            }
            if (e.altKey && e.code === 'KeyS') { 
                e.preventDefault(); 
                document.getElementById('cvm-autotype-stop').click(); 
            }
            if (e.altKey && e.code === 'KeyH') { 
                e.preventDefault(); 
                panelVisible = !panelVisible;
                panel.style.display = panelVisible ? '' : 'none';
                statusDiv.innerText = panelVisible ? "🟡 Панель показана" : "🟡 Панель скрыта";
            }
        });
        
        setInterval(() => {
            if (findWebSocket() && ws.readyState === WebSocket.OPEN) {
                if (!statusDiv.innerText.includes("✅") && !active && !statusDiv.innerText.includes("📋")) {
                    statusDiv.innerText = "🟢 Подключено";
                }
            } else {
                if (!active && !statusDiv.innerText.includes("📋")) {
                    statusDiv.innerText = "🔴 Нет соединения";
                }
            }
        }, 3000);
    }
    
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', createPanel);
    } else {
        createPanel();
    }
})();