Greasy Fork is available in English.

Lolz VoiceInput

Добавляет голосовой ввод на лолз

// ==UserScript==
// @name         Lolz VoiceInput
// @namespace    Android/lolzteam
// @version      0.1
// @description  Добавляет голосовой ввод на лолз
// @author       Android
// @match        *://zelenka.guru/*
// @match        *://lzt.market/*
// @match        *://lolz.guru/*
// @match        *://lolz.live/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=zelenka.guru
// @grant        none
// @license      MIT
// ==/UserScript==

const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || null;
if (!SpeechRecognition) {
    console.error("Ваш браузер не поддерживает голосовой ввод");
    return;
}

(() => {
    'use strict';

    const COLOR = {
        GRAY: '#8c8c8c',
        GREEN: '#2BAD72',
        LIGHT_GREEN: '#33cc87',
        LIGHT_GRAY: '#D6D6D6',
    };

    const ELEMENT_SELECTOR = {
        PARAGRAPH: '.fr-element p',
        WRAPPER: '.fr-wrapper',
        BOX: '.fr-box',
        BUTTON: '.lzt-fe-se-extraButton',
    };

    const BUTTON_SIZE = {
        WIDTH: '24px',
        HEIGHT: '24px',
    };

    const TIMEOUT_DURATION = 10 * 1000;

    const createButton = () => {
        const buttonStyle = document.createElement('button');
        buttonStyle.style.width = BUTTON_SIZE.WIDTH;
        buttonStyle.style.height = BUTTON_SIZE.HEIGHT;
        buttonStyle.style.color = COLOR.GRAY;
        buttonStyle.classList.add('main__block-color_taupe');
        buttonStyle.type = 'button';
        buttonStyle.style.cursor = 'pointer';
        buttonStyle.style.backgroundColor = 'transparent';
        buttonStyle.style.border = 'none';
        buttonStyle.style.display = 'flex';
        buttonStyle.style.alignItems = 'center';
        buttonStyle.style.justifyContent = 'center';
        return buttonStyle;
    };

    let isListening = false;
    let recognition;
    let timeoutId;

    const startListening = () => {
        recognition = new SpeechRecognition();
        recognition.lang = 'ru-RU';
        recognition.continuous = true;
    
        recognition.onstart = () => {
            console.log('onstart')
            clearTimeout(timeoutId);
        };
    
        recognition.onresult = (event) => {
            console.log('onresult')
            clearTimeout(timeoutId);
    
            const result = event.results[event.results.length - 1][0].transcript;
            const paragraphElement = document.querySelector(ELEMENT_SELECTOR.PARAGRAPH);
            const frWrapperElement = document.querySelector(ELEMENT_SELECTOR.WRAPPER);
            const frBoxElement = document.querySelector(ELEMENT_SELECTOR.BOX);
    
            paragraphElement.textContent = paragraphElement.textContent.replace(/\u200B/g, '').replace(/\u00A0/g, '');
            const shouldAppendSpace = paragraphElement.textContent.trim() !== '';
            paragraphElement.textContent += shouldAppendSpace ? ' ' + result : result;
            frWrapperElement.classList.remove('show-placeholder');
            frBoxElement.classList.add('is-focused');
    
            timeoutId = setTimeout(() => {
                stopListening();
            }, TIMEOUT_DURATION);
        };
    
        recognition.onend = () => {
            console.log('onend')
            if (isListening) {
                timeoutId = setTimeout(() => {
                    stopListening();
                }, TIMEOUT_DURATION);
            }
        };
    
        recognition.start();
    };


    const stopListening = () => {
        recognition.stop();
        isListening = false;
        microphoneButton.style.color = COLOR.GRAY;
    };

    const toggleListening = () => {
        if (isListening) {
            stopListening();
        } else {
            startListening();
            isListening = true;
            microphoneButton.style.color = COLOR.GREEN;
        }
    };

    const microphoneButton = createButton();

    const SVG_SIZE = {
        WIDTH: 20,
        HEIGHT: 20,
    };

    const microphoneSvg = `
    <svg xmlns="http://www.w3.org/2000/svg" width="${SVG_SIZE.WIDTH}" height="${SVG_SIZE.HEIGHT}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-mic">
        <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
        <path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
        <line x1="12" y1="19" x2="12" y2="23"></line>
        <line x1="8" y1="23" x2="16" y2="23"></line>
    </svg>
    `;

    microphoneButton.innerHTML = microphoneSvg;
    microphoneButton.addEventListener('click', toggleListening);

    microphoneButton.addEventListener('mouseenter', () => {
        microphoneButton.style.color = isListening ? COLOR.LIGHT_GREEN : COLOR.LIGHT_GRAY;
    });

    microphoneButton.addEventListener('mouseleave', () => {
        microphoneButton.style.color = isListening ? COLOR.GREEN : COLOR.GRAY;
    });

    const element = document.querySelector(ELEMENT_SELECTOR.BUTTON);
    element.parentNode.insertBefore(microphoneButton, element);
})();