首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带有播放、暂停、停止按钮以及选择语言和语音的SpeechSynthesisUtterance脚本

带有播放、暂停、停止按钮以及选择语言和语音的SpeechSynthesisUtterance脚本
EN

Stack Overflow用户
提问于 2019-11-08 08:35:04
回答 2查看 3.4K关注 0票数 4

我想用SpeechSynthesisUtterance阅读我的页面的文本。

我找到了这个脚本:https://www.hongkiat.com/blog/text-to-speech/

几乎完美,但暂停按钮似乎没有太多作用,我希望我有能力设置一种语言,也许选择一个声音。

我在这里找到了参考资料:https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance,但我对JavaScript了解不多。

对于语言,据我所知,应该使用html标记中的lang参数集。

对于声音,我完全不知道如何在代码中实现它。

这很重要,因为我有英语、西班牙语、法语和意大利语的文本,没有语音和语言设置的结果有时听起来真的很奇怪。

更新

这几天我做了一些小事,我设法(或多或少)组合了两个不同的脚本/示例。

这个:https://www.hongkiat.com/blog/text-to-speech/

这个是:https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis#Examples

出来的代码是:

HTML

代码语言:javascript
运行
复制
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="text-to-speech.js"></script>
</head>
<body>
<div class=buttons>
    <button id=play></button> &nbsp;
    <button id=pause></button> &nbsp;
    <button id=stop></button>
</div>
    <select id="voices">

    </select>
<div id="description">
The SpeechSynthesis interface of the Web Speech API is the controller interface for the speech service; this can be used to retrieve information about the synthesis voices available on the device, start and pause speech, and other commands besides. 
Questo è in italiano come viene?
</div>

</body>
</html>

CSS

代码语言:javascript
运行
复制
@import url('https://fonts.googleapis.com/css?family=Crimson+Text');

.buttons {
    margin-top: 25px;
}

button {
    background: none;
    border: none;
    cursor: pointer;
    height: 48px;
    outline: none;
    padding: 0;
    width: 48px;
}

#play {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/play.svg);
}

#play.played {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/play1.svg);
}

#pause {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/pause.svg);
}

#pause.paused {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/pause1.svg);
}

#stop {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/stop.svg);
}

#stop.stopped {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/stop1.svg);
}

JAVASCRIPT

代码语言:javascript
运行
复制
onload = function() {
    if ('speechSynthesis' in window) with(speechSynthesis) {

// select voices////
var synth = window.speechSynthesis;

var voiceSelect = document.querySelector('#voices');

var voices = [];

function populateVoiceList() {
  voices = synth.getVoices().sort(function (a, b) {
      const aname = a.name.toUpperCase(), bname = b.name.toUpperCase();
      if ( aname < bname ) return -1;
      else if ( aname == bname ) return 0;
      else return +1;
  });
  var selectedIndex = voiceSelect.selectedIndex < 0 ? 0 : voiceSelect.selectedIndex;
  voiceSelect.innerHTML = '';
  for(i = 0; i < voices.length ; i++) {
    var option = document.createElement('option');
    option.textContent = voices[i].name + ' (' + voices[i].lang + ')';

    if(voices[i].default) {
      option.textContent += ' -- DEFAULT';
    }

    option.setAttribute('data-lang', voices[i].lang);
    option.setAttribute('data-name', voices[i].name);
    voiceSelect.appendChild(option);
  }
  voiceSelect.selectedIndex = selectedIndex;
}

populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
  speechSynthesis.onvoiceschanged = populateVoiceList;
}
//end select voices

        var playEle = document.querySelector('#play');
        var pauseEle = document.querySelector('#pause');
        var stopEle = document.querySelector('#stop');
        var flag = false;

        playEle.addEventListener('click', onClickPlay);
        pauseEle.addEventListener('click', onClickPause);
        stopEle.addEventListener('click', onClickStop);

        function onClickPlay() {
            if (!flag) {
                flag = true;
                utterance = new SpeechSynthesisUtterance(document.querySelector('#description').textContent);
                //utterance.voice = getVoices()[0];

                //add voice//
                var selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
                    for(i = 0; i < voices.length ; i++) {
                      //if(voices[i].name === 'Google UK English Female') {
                      if(voices[i].name === selectedOption) {
                        utterance.voice = voices[i];
                        break;
                      }
                    }


                voiceSelect.onchange = function(){
                    onClickStop();
                    stopEle.className = '';
                    onClickPlay();
                    playEle.className = 'played';
                }
                //and add voice

                utterance.onend = function() {
                    flag = false;
                    playEle.className = pauseEle.className = '';
                    stopEle.className = 'stopped';
                };
                playEle.className = 'played';
                stopEle.className = '';
                speak(utterance);
            }
            if (paused) { /* unpause/resume narration */
                playEle.className = 'played';
                pauseEle.className = '';
                resume();
            }
        }

        function onClickPause() {
            if (speaking && !paused) { /* pause narration */
                pauseEle.className = 'paused';
                playEle.className = '';
                pause();
            }
        }

        function onClickStop() {
            if (speaking) { /* stop narration */
                /* for safari */
                stopEle.className = 'stopped';
                playEle.className = pauseEle.className = '';
                flag = false;
                cancel();

            }
        }

    }

    else { /* speech synthesis not supported */
        msg = document.createElement('h5');
        msg.textContent = "Detected no support for Speech Synthesis";
        msg.style.textAlign = 'center';
        msg.style.backgroundColor = 'red';
        msg.style.color = 'white';
        msg.style.marginTop = msg.style.marginBottom = 0;
        document.body.insertBefore(msg, document.querySelector('div'));
    }

}

现在我有了播放、停止和暂停按钮(暂停仍然不起作用),我可以从设备中可用的声音中选择一种。

似乎在chrome上运行得很好,也许在Firefox上就没那么好用了(但我使用的是Linux LMDE,也许这是我的错)。过了一段时间,Chrome就不再说话了。我不知道为什么,但在我看来,我似乎已经看到有人可能理解为什么我这些天打开的数千个网页中的一些,我将不得不重新打开它们。

如果选择的声音保存在cookie中就好了,所以如果我打开另一个页面,脚本将从我选择的最后一个声音开始(我不知道如何在JavaScript中做到这一点)

更新2

我还做了其他一些小的改进和简化。

它似乎几乎是有效的,并不总是暂停按钮,我现在最大的疑问是,使用chrome时,当我更新或更改页面时,它似乎不会停止,这真的很糟糕,当你更改页面时,他一直在阅读前一页。

HTML

代码语言:javascript
运行
复制
<div id="SpeechSynthesis">
    <div>
        <button id=play>play</button>
        <button id=pause>pause</button>
        <button id=stop>stop</button>
    </div>
        <select id="voices">

        </select>
    </div>
<p id="texttospeech">
The SpeechSynthesis interface of the Web Speech API is the controller interface for the speech service; this can be used to retrieve information about the synthesis voices available on the device, start and pause speech, and other commands besides. 
Questo è in italiano come viene?
</p>

JAVASCRIPT

代码语言:javascript
运行
复制
onload = function() {
    if ('speechSynthesis' in window){
        var synth = speechSynthesis;
        var flag = false;

        //stop when change page ???(not sure)
            if(synth.speaking){ /* stop narration */
                /* for safari */
                flag = false;
                synth.cancel();
            }

        /* references to the buttons */
        var playEle = document.querySelector('#play');
        var pauseEle = document.querySelector('#pause');
        var stopEle = document.querySelector('#stop');

        /* click event handlers for the buttons */
        playEle.addEventListener('click', onClickPlay);
        pauseEle.addEventListener('click', onClickPause);
        stopEle.addEventListener('click', onClickStop);

// select voices////
//var synth = window.speechSynthesis;

var voiceSelect = document.querySelector('#voices');

var voices = [];

function populateVoiceList() {
  voices = synth.getVoices().sort(function (a, b) {
      const aname = a.name.toUpperCase(), bname = b.name.toUpperCase();
      if ( aname < bname ) return -1;
      else if ( aname == bname ) return 0;
      else return +1;
  });
  var selectedIndex = voiceSelect.selectedIndex < 0 ? 0 : voiceSelect.selectedIndex;
  voiceSelect.innerHTML = '';
  for(i = 0; i < voices.length ; i++) {
    var option = document.createElement('option');
    option.textContent = voices[i].name + ' (' + voices[i].lang + ')';

    if(voices[i].default) {
      option.textContent += ' -- DEFAULT';
    }

    option.setAttribute('data-lang', voices[i].lang);
    option.setAttribute('data-name', voices[i].name);
    voiceSelect.appendChild(option);
  }
  voiceSelect.selectedIndex = selectedIndex;
}

populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
  speechSynthesis.onvoiceschanged = populateVoiceList;
}
//end select voices

        function onClickPlay() {
            if(!flag){
                flag = true;
                utterance = new SpeechSynthesisUtterance(document.querySelector('#texttospeech').textContent);
                //utterance.voice = synth.getVoices()[0];

                //add voice//
                var selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
                    for(i = 0; i < voices.length ; i++) {
                      //if(voices[i].name === 'Google UK English Female') {
                      if(voices[i].name === selectedOption) {
                        utterance.voice = voices[i];
                        break;
                      }
                    }

                voiceSelect.onchange = function(){
                    onClickStop();
                    onClickPlay();
                }
                //and add voice

                utterance.onend = function(){
                    flag = false;
                };
                synth.speak(utterance);

                //fix stop after a while bug
                let r = setInterval(() => {
                  console.log(speechSynthesis.speaking);
                  if (!speechSynthesis.speaking) {
                    clearInterval(r);
                  } else {
                    speechSynthesis.resume();
                  }
                }, 14000);
                //end fix stop after a while bug
            }
            if(synth.paused) { /* unpause/resume narration */
                synth.resume();
            }
        }
        function onClickPause() {
            if(synth.speaking && !synth.paused){ /* pause narration */
                synth.pause();
            }
        }
        function onClickStop() {
           if(synth.speaking){ /* stop narration */
                /* for safari */
                flag = false;
                synth.cancel();
            }
        }
    }
  else {
        msg = document.createElement('h5');
        msg.textContent = "Detected no support for Speech Synthesis";
        msg.style.textAlign = 'center';
        msg.style.backgroundColor = 'red';
        msg.style.color = 'white';
        msg.style.marginTop = msg.style.marginBottom = 0;
        document.body.insertBefore(msg, document.querySelector('#SpeechSynthesis'));
  }
}

更新3

我尝试添加带有上一次选择的声音的cookie。我添加了几个函数来管理cookie,并在onClickPlay()函数中设置了cookie。

代码语言:javascript
运行
复制
//add voice//
                var selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
                    for(i = 0; i < voices.length ; i++) {
                      //if(voices[i].name === 'Google UK English Female') {
                      if(voices[i].name === selectedOption) {
                        utterance.voice = voices[i];
                        setCookie('SpeechSynthesisVoice',voices[i].name,30);
                        break;
                      }
                    }

火狐设置cookie没有问题,chrome no (即使文件在在线服务器上)。

然后,我尝试在populateVoiceList()函数中将保存在cookie中的声音设置为"selected“:

代码语言:javascript
运行
复制
//get cookie voice
    var cookievoice = getCookie('SpeechSynthesisVoice');

//add selcted to option if if cookievoice
    if (cookievoice === voices[i].name) {
        option.setAttribute('selected', 'selected');
    }

它起作用了,我在代码中找到了“选定的”,但它似乎没有被考虑,它总是从列表中的第一个声音开始对话,或者是默认的声音,我不确定,而不是与具有“选定”的声音。

我使用的cookie函数:

代码语言:javascript
运行
复制
//cookie functions
function setCookie(name, value, days) {
    var expires = '',
        date = new Date();
    if (days) {
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = '; expires=' + date.toGMTString();
    }
    document.cookie = name + '=' + value + expires + '; path=/';
}

function getCookie(name) {
    var cookies = document.cookie.split(';'),
        length = cookies.length,
        i,
        cookie,
        nameEQ = name + '=';
    for (i = 0; i < length; i += 1) {
        cookie = cookies[i];
        while (cookie.charAt(0) === ' ') {
            cookie = cookie.substring(1, cookie.length);
        }
        if (cookie.indexOf(nameEQ) === 0) {
            return cookie.substring(nameEQ.length, cookie.length);
        }
    }
    return null;
}

function eraseCookie(name) {
    createCookie(name, '', -1);
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-11-20 07:48:00

我没有得到太多的帮助,但不知何故,我设法设置了一个小播放器来阅读网页文本。

我用一个演示程序做了一个小教程,解释了我做了什么以及它是如何工作的。

https://www.alebalweb-blog.com/85-text-to-speech-player-with-buttons-play-pause-stop-and-voice-choice.html

票数 2
EN

Stack Overflow用户

发布于 2019-11-14 14:21:19

"for“循环后的这一行如何?

代码语言:javascript
运行
复制
voiceSelect.selectedIndex = selectedIndex;

如果它还在这里,你就覆盖了你的选择。试试像这样的东西

代码语言:javascript
运行
复制
if(cookievoice === voices[i].name) {
    option.setAttribute('selected', 'selected');
   selectedIndex = i;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58758819

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档