aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/bg/js/settings/audio-controller.js103
-rw-r--r--ext/bg/settings.html9
2 files changed, 54 insertions, 58 deletions
diff --git a/ext/bg/js/settings/audio-controller.js b/ext/bg/js/settings/audio-controller.js
index 6ea11e15..ae0e234a 100644
--- a/ext/bg/js/settings/audio-controller.js
+++ b/ext/bg/js/settings/audio-controller.js
@@ -28,18 +28,25 @@ class AudioController {
this._audioSourceContainer = null;
this._audioSourceAddButton = null;
this._audioSourceEntries = [];
+ this._ttsVoiceTestTextInput = null;
}
async prepare() {
this._audioSystem.prepare();
- this._audioSourceContainer = document.querySelector('.audio-source-list');
- this._audioSourceAddButton = document.querySelector('.audio-source-add');
+ this._ttsVoiceTestTextInput = document.querySelector('#text-to-speech-voice-test-text');
+ this._audioSourceContainer = document.querySelector('#audio-source-list');
+ this._audioSourceAddButton = document.querySelector('#audio-source-add');
this._audioSourceContainer.textContent = '';
this._audioSourceAddButton.addEventListener('click', this._onAddAudioSource.bind(this), false);
- this._prepareTextToSpeech();
+ if (typeof speechSynthesis !== 'undefined') {
+ speechSynthesis.addEventListener('voiceschanged', this._updateTextToSpeechVoices.bind(this), false);
+ }
+ this._updateTextToSpeechVoices();
+
+ document.querySelector('#text-to-speech-voice-test').addEventListener('click', this._onTestTextToSpeech.bind(this), false);
this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this));
@@ -59,57 +66,62 @@ class AudioController {
}
}
- _prepareTextToSpeech() {
- if (typeof speechSynthesis === 'undefined') { return; }
-
- speechSynthesis.addEventListener('voiceschanged', this._updateTextToSpeechVoices.bind(this), false);
- this._updateTextToSpeechVoices();
+ _onTestTextToSpeech() {
+ try {
+ const text = this._ttsVoiceTestTextInput.value || '';
+ const voiceUri = document.querySelector('[data-setting="audio.textToSpeechVoice"]').value;
- document.querySelector('#text-to-speech-voice').addEventListener('change', this._onTextToSpeechVoiceChange.bind(this), false);
- document.querySelector('#text-to-speech-voice-test').addEventListener('click', this._testTextToSpeech.bind(this), false);
+ const audio = this._audioSystem.createTextToSpeechAudio(text, voiceUri);
+ audio.volume = 1.0;
+ audio.play();
+ } catch (e) {
+ // NOP
+ }
}
_updateTextToSpeechVoices() {
- const voices = Array.prototype.map.call(speechSynthesis.getVoices(), (voice, index) => ({voice, index}));
+ const voices = (
+ typeof speechSynthesis !== 'undefined' ?
+ [...speechSynthesis.getVoices()].map((voice, index) => ({
+ voice,
+ isJapanese: this._languageTagIsJapanese(voice.lang),
+ index
+ })) :
+ []
+ );
voices.sort(this._textToSpeechVoiceCompare.bind(this));
- document.querySelector('#text-to-speech-voice-container').hidden = (voices.length === 0);
+ for (const select of document.querySelectorAll('[data-setting="audio.textToSpeechVoice"]')) {
+ const fragment = document.createDocumentFragment();
- const fragment = document.createDocumentFragment();
+ let option = document.createElement('option');
+ option.value = '';
+ option.textContent = 'None';
+ fragment.appendChild(option);
- let option = document.createElement('option');
- option.value = '';
- option.textContent = 'None';
- fragment.appendChild(option);
+ for (const {voice} of voices) {
+ option = document.createElement('option');
+ option.value = voice.voiceURI;
+ option.textContent = `${voice.name} (${voice.lang})`;
+ fragment.appendChild(option);
+ }
- for (const {voice} of voices) {
- option = document.createElement('option');
- option.value = voice.voiceURI;
- option.textContent = `${voice.name} (${voice.lang})`;
- fragment.appendChild(option);
+ select.textContent = '';
+ select.appendChild(fragment);
}
-
- const select = document.querySelector('#text-to-speech-voice');
- select.textContent = '';
- select.appendChild(fragment);
- select.value = select.dataset.value;
}
_textToSpeechVoiceCompare(a, b) {
- const aIsJapanese = this._languageTagIsJapanese(a.voice.lang);
- const bIsJapanese = this._languageTagIsJapanese(b.voice.lang);
- if (aIsJapanese) {
- if (!bIsJapanese) { return -1; }
+ if (a.isJapanese) {
+ if (!b.isJapanese) { return -1; }
} else {
- if (bIsJapanese) { return 1; }
+ if (b.isJapanese) { return 1; }
}
- const aIsDefault = a.voice.default;
- const bIsDefault = b.voice.default;
- if (aIsDefault) {
- if (!bIsDefault) { return -1; }
+ if (a.voice.default) {
+ if (!b.voice.default) { return -1; }
} else {
- if (bIsDefault) { return 1; }
+ if (b.voice.default) { return 1; }
}
return a.index - b.index;
@@ -123,19 +135,6 @@ class AudioController {
);
}
- _testTextToSpeech() {
- try {
- const text = document.querySelector('#text-to-speech-voice-test').dataset.speechText || '';
- const voiceUri = document.querySelector('#text-to-speech-voice').value;
-
- const audio = this._audioSystem.createTextToSpeechAudio(text, voiceUri);
- audio.volume = 1.0;
- audio.play();
- } catch (e) {
- // NOP
- }
- }
-
_getUnusedAudioSource() {
const audioSourcesAvailable = [
'jpod101',
@@ -195,10 +194,6 @@ class AudioController {
this._audioSourceEntries.splice(index, 1);
}
- _onTextToSpeechVoiceChange(e) {
- e.currentTarget.dataset.value = e.currentTarget.value;
- }
-
async _onAddAudioSource() {
const audioSource = this._getUnusedAudioSource();
const index = this._audioSourceEntries.length;
diff --git a/ext/bg/settings.html b/ext/bg/settings.html
index c318401f..795cdd54 100644
--- a/ext/bg/settings.html
+++ b/ext/bg/settings.html
@@ -346,14 +346,15 @@
<input type="number" min="0" max="100" id="audio-playback-volume" class="form-control" data-setting="audio.volume">
</div>
- <div class="form-group" id="text-to-speech-voice-container" hidden>
+ <div class="form-group" id="text-to-speech-voice-container">
<label for="text-to-speech-voice">Text-to-speech voice</label>
<div class="input-group">
<select class="form-control" id="text-to-speech-voice" data-setting="audio.textToSpeechVoice"></select>
<div class="input-group-btn">
- <button class="btn btn-default" id="text-to-speech-voice-test" title="Test voice" data-speech-text="よみちゃん"><span class="glyphicon glyphicon-volume-up"></span></button>
+ <button class="btn btn-default" id="text-to-speech-voice-test" title="Test voice"><span class="glyphicon glyphicon-volume-up"></span></button>
</div>
</div>
+ <input type="text" value="よみちゃん" id="text-to-speech-voice-test-text" hidden>
</div>
<div class="form-group options-advanced">
@@ -363,9 +364,9 @@
<div class="form-group ignore-form-changes">
<label>Audio playback sources</label>
- <div class="audio-source-list generic-input-list"></div>
+ <div class="audio-source-list generic-input-list" id="audio-source-list"></div>
<div class="input-group audio-source-options">
- <button class="btn btn-default audio-source-add" title="Add audio playback source"><span class="glyphicon glyphicon-plus"></span></button>
+ <button class="btn btn-default audio-source-add" title="Add audio playback source" id="audio-source-add"><span class="glyphicon glyphicon-plus"></span></button>
</div>
<template id="audio-source-template"><div class="input-group audio-source">