Я хотел бы прочитать текст своих страниц с помощью 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>
<button id=pause></button>
<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);
}