Скрипт SpeechSynthesisUtterance с кнопками воспроизведения, паузы, остановки и выбора языка и голоса - PullRequest
1 голос
/ 08 ноября 2019

Я хотел бы прочитать текст своих страниц с помощью SpeechSynthesisUtterance.

Я нашел этот скрипт: https://www.hongkiat.com/blog/text-to-speech/

Почти идеально, но кнопка паузы, кажется, не делает многои я хотел бы иметь возможность установить язык и, возможно, выбрать голос.

Я нашел ссылку здесь: https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance,, но я не очень хорошо разбираюсь в javascript и мне нужна помощь.

Для языка, насколько я понимаю, следует использовать набор параметров lang в теге html.

Для голоса я абсолютно не представляю, как реализовать его в коде.

Это было бы важно, потому что у меня есть тексты на английском, испанском, французском и итальянском, а результат без голосовых и языковых настроек иногда звучит очень странно ...


Обновление

В эти дни я немного поиграл, мне удалось (более или менее) объединить два разных сценария / примера.

Это: https://www.hongkiat.com/blog/text-to-speech/

и это: https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis#Examples

Код, который вышел, это:

HTML

<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

@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

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)

Javascript - это не мой мир, и мне действительно нужна чья-то помощь, чтобы правильно объединить эти вещи.


Обновление 2

Я сделал несколько других маленькихшаг вперед и упрощение.

Кажется, что это работает, не всегда кнопка паузы, у меня сейчас большие сомнения в том, что с хромом он не останавливается при обновлении или изменении страниц, и это действительноплохо, что при смене страницы он продолжает читать предыдущую страницу ...

HTML

<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

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 ().

//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;
                      }
                    }

Firefox устанавливает cookie без проблем, chrome no (даже еслифайл находится на онлайн-сервере).

Затем я попытался установить голос, сохраненный в cookie, как "выбранный" в функции populateVoiceList ():

//get cookie voice
    var cookievoice = getCookie('SpeechSynthesisVoice');

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

Это работает, я нахожу«выбранный» в коде, но, кажется, это не учитывается, он всегда начинает говорить с первым голосом в списке, или с голосом по умолчанию, я не уверен, и не с тем, у которого есть «выбранный»"...

Мне действительно нужна помощь с JavaScript ...

Используемые мной функции cookie:

//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);
}

1 Ответ

0 голосов
/ 14 ноября 2019

Как насчет этой строки после цикла "for"?

voiceSelect.selectedIndex = selectedIndex;

Если она все еще здесь, вы отменяете свой выбор. Попробуйте что-то вроде

if(cookievoice === voices[i].name) {
    option.setAttribute('selected', 'selected');
   selectedIndex = i;
}
...