Auto Play Audio Sequentially

访问指定 URL 获取音频并自动播放,确保按顺序播放

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

// ==UserScript==
// @name         Auto Play Audio Sequentially
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  访问指定 URL 获取音频并自动播放,确保按顺序播放
// @author       Your Name
// @match        *://*/*
// @grant        none
// ==/UserScript==
(function() {
    'use strict';

    // 初始 URL
    const initialUrl = 'http://localhost: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';
                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);

    // 获取音频并添加到播放队列
    async function fetchAudioAndAddToQueue(url) {
        try {
            const response = await fetch(url);
            const blob = await response.blob();
            const audioUrl = window.URL.createObjectURL(blob);
            audioQueue.push(audioUrl);
            playNextAudio();
        } catch (error) {
            console.error('获取音频失败:', 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;
        const regex2 = /"(.*?)"/g;
        let text2=text;
        let match;
        while ((match = regex.exec(text)) !== null) {
            quotes.push(match[1]);
        }
        let match2;
        while ((match2 = regex2.exec(text2)) !== null) {
            quotes.push(match2[1]);
        }
        return quotes;
    }

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