网页划词朗读助手

划词自动朗读,支持中文/英文,多语音切换,可暂停与继续播放

// ==UserScript==
// @name         网页划词朗读助手
// @namespace    https://dqtx.cc/
// @version      1.0
// @description  划词自动朗读,支持中文/英文,多语音切换,可暂停与继续播放
// @author       Derek
// @license      MIT
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    let utterance = null;
    let isSpeaking = false;

    // 创建悬浮控制条
    const controlBar = document.createElement('div');
    controlBar.innerHTML = `
        <button id="speakPauseBtn">⏸ 暂停</button>
        <button id="speakResumeBtn">▶️ 继续</button>
        <button id="speakStopBtn">⏹ 停止</button>
    `;
    Object.assign(controlBar.style, {
        position: 'fixed',
        bottom: '50px',
        right: '50px',
        background: 'rgba(0,0,0,0.6)',
        color: '#fff',
        padding: '6px 10px',
        borderRadius: '8px',
        fontSize: '14px',
        zIndex: 99999,
        display: 'none',
        gap: '5px',
    });
    controlBar.querySelectorAll('button').forEach(btn => {
        Object.assign(btn.style, {
            background: 'rgba(255,255,255,0.1)',
            color: '#fff',
            border: 'none',
            cursor: 'pointer',
            margin: '0 3px',
            borderRadius: '4px',
            padding: '4px 8px',
        });
        btn.onmouseenter = () => btn.style.background = 'rgba(255,255,255,0.25)';
        btn.onmouseleave = () => btn.style.background = 'rgba(255,255,255,0.1)';
    });
    document.body.appendChild(controlBar);

    // 绑定事件
    const pauseBtn = controlBar.querySelector('#speakPauseBtn');
    const resumeBtn = controlBar.querySelector('#speakResumeBtn');
    const stopBtn = controlBar.querySelector('#speakStopBtn');

    pauseBtn.onclick = () => {
        window.speechSynthesis.pause();
    };
    resumeBtn.onclick = () => {
        window.speechSynthesis.resume();
    };
    stopBtn.onclick = () => {
        window.speechSynthesis.cancel();
        controlBar.style.display = 'none';
    };

    // 监听划词事件
    document.addEventListener('mouseup', () => {
        const selectedText = window.getSelection().toString().trim();
        if (selectedText.length > 0) {
            speakText(selectedText);
        }
    });

    // 自动检测语言(中英)
    function detectLang(text) {
        const zh = /[\u4e00-\u9fa5]/.test(text);
        return zh ? 'zh-CN' : 'en-US';
    }

    // 执行朗读
    function speakText(text) {
        // 停止当前朗读
        window.speechSynthesis.cancel();

        const lang = detectLang(text);
        utterance = new SpeechSynthesisUtterance(text);
        utterance.lang = lang;
        utterance.rate = 1.0;
        utterance.pitch = 1.0;

        const voices = speechSynthesis.getVoices();
        // 自动选择匹配语音
        const matched = voices.find(v => v.lang === lang);
        if (matched) utterance.voice = matched;

        utterance.onstart = () => {
            controlBar.style.display = 'flex';
            isSpeaking = true;
        };
        utterance.onend = () => {
            controlBar.style.display = 'none';
            isSpeaking = false;
        };

        window.speechSynthesis.speak(utterance);
    }

    // 初始化语音列表(部分浏览器需要延迟)
    if (speechSynthesis.onvoiceschanged !== undefined) {
        speechSynthesis.onvoiceschanged = () => {
            console.log('[划词朗读助手] 已加载语音包');
        };
    }
})();