Greasy Fork

Auto Play Audio Sequentially

顺序播放

当前为 2024-03-12 提交的版本,查看 最新版本

// ==UserScript==
// @name         Auto Play Audio Sequentially
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  顺序播放
// @author       Your Name
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @connet       192.168.10.2
// ==/UserScript==
(function() {
    'use strict';

    // 初始 URL
    const initialUrl = 'http://192.168.10.2:9880?text=你好,我是七七,是个小僵尸&text_lang=中文&ref_audio_path=./qiqi3.mp3&prompt_text=刮大风了…_拉手…拉手!要、要被吹跑了!…&prompt_lang=中文&sweight=SoVITS_weights/qiqi_e8_s136.pth&gweight=GPT_weights/qiqi-e15.ckpt';

    // 当前 URL
    let currentUrl = initialUrl;

    // 存储待播放的音频URL队列
    const audioQueue = [];

    // 是否有音频正在播放
    let isPlaying = false;

    // 存储已经绑定过按钮的 div 元素
    const boundDivs = new Set();

    // 检测并插入播放按钮的函数
    function checkAndInsertPlayButton() {
        const divElements = document.querySelectorAll('div');

        divElements.forEach(div => {
            if (div.getAttribute('dir') === 'auto' && !boundDivs.has(div)) {
                const playButton = document.createElement('button');
                playButton.textContent = 'Play Audio';
                playButton.style.backgroundColor = '#4CAF50'; // 设置按钮背景颜色
                playButton.style.color = 'white'; // 设置按钮文字颜色
                playButton.style.padding = '8px 16px'; // 设置按钮内边距
                playButton.style.border = 'none'; // 移除按钮边框
                playButton.style.borderRadius = '4px'; // 设置按钮圆角
                playButton.style.cursor = 'pointer'; // 设置鼠标指针样式
                div.parentNode.insertBefore(playButton, div.nextSibling);

                playButton.addEventListener('click', async function() {
                    const text = div.textContent.trim();
                    const quotes = extractQuotes(text);
                    for (const quote of quotes) {
                        await fetchAudioAndAddToQueue(updateUrlWithText(currentUrl, quote));
                    }
                });

                boundDivs.add(div); // 将已经绑定过按钮的 div 元素添加到集合中
            }
        });
    }

    // 每隔 5 秒检测一次 div 元素
    setInterval(checkAndInsertPlayButton, 5000);

    // 使用 GM_xmlhttpRequest 获取音频并添加到播放队列
    function fetchAudioAndAddToQueue(url) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: url,
                responseType: 'blob',
                onload: function(response) {
                    if (response.status >= 200 && response.status < 300) {
                        const audioUrl = window.URL.createObjectURL(response.response);
                        audioQueue.push(audioUrl);
                        playNextAudio();
                        resolve();
                    } else {
                        reject(new Error('Failed to load audio'));
                    }
                },
                onerror: function() {
                    reject(new Error('Network error'));
                }
            });
        });
    }

    // 播放队列中的下一个音频
    function playNextAudio() {
        if (isPlaying || audioQueue.length === 0) {
            return;
        }
        isPlaying = true;
        const audioUrl = audioQueue.shift(); // 获取并移除队列中的第一个音频URL
        const audio = new Audio(audioUrl);
        audio.play();
        audio.onended = function() {
            isPlaying = false;
            playNextAudio(); // 播放完毕后继续播放下一个
        };
    }

    // 提取文本中的双引号内容
    function extractQuotes(text) {
        const quotes = [];
        const regex = /"(.*?)"/g;
        let match;
        while ((match = regex.exec(text)) !== null) {
            quotes.push(match[1]);
        }
        return quotes;
    }

    // 更新 URL 中的 text 参数
    function updateUrlWithText(url, text) {
        const urlObj = new URL(url);
        urlObj.searchParams.set('text', text);
        return urlObj.toString();
    }
})();