@internetarchive/bookreader 5.0.0-97 → 5.0.0-98
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BookReader/BookReader.css +8 -9
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/bergamot-translator-worker.js +1 -1
- package/BookReader/plugins/plugin.text_selection.js +1 -1
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.translate.js +1 -1
- package/BookReader/plugins/plugin.translate.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/silence.mp3 +0 -0
- package/package.json +2 -2
- package/src/BookReader/options.js +12 -8
- package/src/BookReader.js +45 -1
- package/src/assets/silence.mp3 +0 -0
- package/src/css/_BRsearch.scss +1 -0
- package/src/css/_TextSelection.scss +7 -9
- package/src/plugins/plugin.text_selection.js +9 -0
- package/src/plugins/translate/TranslationManager.js +6 -3
- package/src/plugins/translate/plugin.translate.js +133 -58
- package/src/plugins/tts/AbstractTTSEngine.js +3 -4
- package/src/plugins/tts/PageChunk.js +28 -9
- package/src/plugins/tts/WebTTSEngine.js +5 -7
- package/src/plugins/tts/plugin.tts.js +40 -4
- package/src/plugins/tts/utils.js +15 -5
|
@@ -30,7 +30,11 @@ export default class WebTTSEngine extends AbstractTTSEngine {
|
|
|
30
30
|
start(leafIndex, numLeafs) {
|
|
31
31
|
// Need to run in this function to capture user intent to start playing audio
|
|
32
32
|
if ('mediaSession' in navigator) {
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* According to https://developers.google.com/web/updates/2017/02/media-session#implementation_notes , it needs to be at least 5 seconds
|
|
35
|
+
* long to allow usage of the media sessions api
|
|
36
|
+
*/
|
|
37
|
+
const audio = new Audio(br.options.imagesBaseURL + '../silence.mp3');
|
|
34
38
|
audio.loop = true;
|
|
35
39
|
|
|
36
40
|
this.events.on('pause', () => audio.pause());
|
|
@@ -386,9 +390,3 @@ export class WebTTSSound {
|
|
|
386
390
|
}
|
|
387
391
|
}
|
|
388
392
|
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* According to https://developers.google.com/web/updates/2017/02/media-session#implementation_notes , it needs to be at least 5 seconds
|
|
392
|
-
* long to allow usage of the media sessions api
|
|
393
|
-
*/
|
|
394
|
-
const SILENCE_6S_MP3 = 'data:audio/mp3;base64,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';
|
|
@@ -165,13 +165,26 @@ export class TtsPlugin extends BookReaderPlugin {
|
|
|
165
165
|
|
|
166
166
|
const renderVoicesMenu = (voicesMenu) => {
|
|
167
167
|
voicesMenu.empty();
|
|
168
|
-
|
|
168
|
+
let bookLanguage = this.ttsEngine.opts.bookLanguage;
|
|
169
|
+
if (this.br.plugins.translate?.translationManager?.active) {
|
|
170
|
+
bookLanguage = this.br.plugins.translate.langFromCode;
|
|
171
|
+
}
|
|
172
|
+
|
|
169
173
|
const bookLanguages = this.ttsEngine.getVoices().filter(v => v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);
|
|
170
174
|
const otherLanguages = this.ttsEngine.getVoices().filter(v => !v.lang.startsWith(bookLanguage)).sort(voiceSortOrder);
|
|
171
175
|
|
|
172
176
|
if (this.ttsEngine.getVoices().length > 1) {
|
|
173
|
-
|
|
174
|
-
|
|
177
|
+
if (this.br.plugins.translate?.translationManager?.active) {
|
|
178
|
+
// Separate out Other Languages when translation active, not sure if too much / unwieldy
|
|
179
|
+
const toLang = this.br.plugins.translate.langToCode;
|
|
180
|
+
const translatedLanguages = this.ttsEngine.getVoices().filter(v => v.lang.startsWith(toLang)).sort(voiceSortOrder);
|
|
181
|
+
voicesMenu.append($(`<optgroup label="Book Language, Translated From (${bookLanguage})"> ${renderVoiceOption(bookLanguages)} </optgroup>`));
|
|
182
|
+
voicesMenu.append($(`<optgroup label="Book Language, Translated To (${toLang})"> ${renderVoiceOption(translatedLanguages)} </optgroup>`));
|
|
183
|
+
voicesMenu.append($(`<optgroup label="Other Languages"> ${renderVoiceOption(otherLanguages.filter(v => !v.lang.startsWith(toLang)).sort(voiceSortOrder))}`));
|
|
184
|
+
} else {
|
|
185
|
+
voicesMenu.append($(`<optgroup label="Book Language (${bookLanguage})"> ${renderVoiceOption(bookLanguages)} </optgroup>`));
|
|
186
|
+
voicesMenu.append($(`<optgroup label="Other Languages"> ${renderVoiceOption(otherLanguages)} </optgroup>`));
|
|
187
|
+
}
|
|
175
188
|
|
|
176
189
|
voicesMenu.val(this.ttsEngine.voice.voiceURI);
|
|
177
190
|
voicesMenu.show();
|
|
@@ -185,6 +198,8 @@ export class TtsPlugin extends BookReaderPlugin {
|
|
|
185
198
|
voicesMenu.on("change", ev => this.ttsEngine.setVoice(voicesMenu.val()));
|
|
186
199
|
this.ttsEngine.events.on('pause resume start', () => this.updateState());
|
|
187
200
|
this.ttsEngine.events.on('voiceschanged', () => renderVoicesMenu(voicesMenu));
|
|
201
|
+
this.br.on('translationEnabled', () => renderVoicesMenu(voicesMenu));
|
|
202
|
+
this.br.on('translationDisabled', () => renderVoicesMenu(voicesMenu));
|
|
188
203
|
this.br.refs.$BRReadAloudToolbar.find('[name=play]').on("click", this.playPause.bind(this));
|
|
189
204
|
this.br.refs.$BRReadAloudToolbar.find('[name=advance]').on("click", this.jumpForward.bind(this));
|
|
190
205
|
this.br.refs.$BRReadAloudToolbar.find('[name=review]').on("click", this.jumpBackward.bind(this));
|
|
@@ -208,6 +223,12 @@ export class TtsPlugin extends BookReaderPlugin {
|
|
|
208
223
|
}
|
|
209
224
|
|
|
210
225
|
start(startTTSEngine = true) {
|
|
226
|
+
const checkVoice = this.br.plugins.translate?.translationManager?.active ? toISO6391(this.br.plugins.translate.langToCode) : "";
|
|
227
|
+
const bookVoice = this.ttsEngine.getBestVoice(checkVoice);
|
|
228
|
+
|
|
229
|
+
const voicesMenu = this.br.refs.$BRReadAloudToolbar.find('[name=playback-voice');
|
|
230
|
+
this.ttsEngine.setVoice(bookVoice.voiceURI);
|
|
231
|
+
voicesMenu.val(bookVoice.voiceURI);
|
|
211
232
|
if (this.br.constModeThumb == this.br.mode)
|
|
212
233
|
this.br.switchMode(this.br.constMode1up);
|
|
213
234
|
|
|
@@ -291,7 +312,22 @@ export class TtsPlugin extends BookReaderPlugin {
|
|
|
291
312
|
const pageIndex = chunk.leafIndex;
|
|
292
313
|
|
|
293
314
|
this.removeHilites();
|
|
294
|
-
|
|
315
|
+
if (this.br.plugins.translate?.translationManager.active) {
|
|
316
|
+
const pageContainers = this.br.getActivePageContainerElementsForIndex(pageIndex);
|
|
317
|
+
const paragraphIndex = chunk.chunkIndex;
|
|
318
|
+
pageContainers.forEach(container => {
|
|
319
|
+
const translateElement = container.querySelector('.BRtranslateLayer');
|
|
320
|
+
const containerChildren = Array.from(translateElement.childNodes);
|
|
321
|
+
const paragraphEle = containerChildren[paragraphIndex];
|
|
322
|
+
if (!paragraphEle) { return; }
|
|
323
|
+
const [pOffHeight, pOffTop, pOffWidth, pOffLeft] = [paragraphEle.offsetHeight, paragraphEle.offsetTop, paragraphEle.offsetWidth, paragraphEle.offsetLeft];
|
|
324
|
+
const boxes = {pageIndex: [
|
|
325
|
+
{l: pOffLeft, r: pOffLeft + pOffWidth, b: pOffTop + pOffHeight, t: pOffTop},
|
|
326
|
+
]};
|
|
327
|
+
renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes.pageIndex, this.br.book.getPage(pageIndex), translateElement);
|
|
328
|
+
});
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
295
331
|
// group by index; currently only possible to have chunks on one page :/
|
|
296
332
|
this._ttsBoxesByIndex = {
|
|
297
333
|
[pageIndex]: chunk.lineRects.map(([l, b, r, t]) => ({l, r, b, t})),
|
package/src/plugins/tts/utils.js
CHANGED
|
@@ -19,38 +19,48 @@ export function isAndroid(userAgent = navigator.userAgent) {
|
|
|
19
19
|
return /android/i.test(userAgent);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/** @type {{[lang: string]: string}} */
|
|
23
|
+
// Handle odd one-off language pairs that might show up over time
|
|
24
|
+
const specialLangs = {
|
|
25
|
+
"zh-hans": "中文 (Zhōngwén)",
|
|
26
|
+
};
|
|
22
27
|
/**
|
|
23
28
|
* @typedef {string} ISO6391
|
|
24
29
|
* Language code in ISO 639-1 format. e.g. en, fr, zh
|
|
30
|
+
* Can also retrieve language native name + ISO 639-1 code
|
|
25
31
|
**/
|
|
26
32
|
|
|
27
33
|
/**
|
|
28
34
|
* @param {string} language in some format
|
|
35
|
+
* @param {boolean?} getName gets Native Name + language code if true
|
|
29
36
|
* @return {ISO6391?}
|
|
30
37
|
*/
|
|
31
|
-
export function toISO6391(language) {
|
|
38
|
+
export function toISO6391(language, getName = false) {
|
|
32
39
|
if (!language) return null;
|
|
33
40
|
language = language.toLowerCase();
|
|
34
41
|
|
|
35
|
-
return searchForISO6391(language, ['iso639_1']) ||
|
|
36
|
-
searchForISO6391(language, ['iso639_2T']) ||
|
|
37
|
-
searchForISO6391(language, ['iso639_2B', 'nativeName', 'name']);
|
|
42
|
+
return searchForISO6391(language, ['iso639_1'], getName) ||
|
|
43
|
+
searchForISO6391(language, ['iso639_2T'], getName) ||
|
|
44
|
+
searchForISO6391(language, ['iso639_2B', 'nativeName', 'name'], getName);
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
/**
|
|
41
48
|
* Searches for the given long in the given columns.
|
|
42
49
|
* @param {string} language
|
|
43
50
|
* @param {Array<keyof import('iso-language-codes').Code>} columnsToSearch
|
|
51
|
+
* @param {boolean?} getName
|
|
44
52
|
* @return {ISO6391?}
|
|
45
53
|
*/
|
|
46
|
-
function searchForISO6391(language, columnsToSearch) {
|
|
54
|
+
function searchForISO6391(language, columnsToSearch, getName) {
|
|
47
55
|
for (const lang of langs) {
|
|
48
56
|
for (const colName of columnsToSearch) {
|
|
49
57
|
if (lang[colName].split(', ').map(x => x.toLowerCase()).indexOf(language) != -1) {
|
|
58
|
+
if (getName) return `${lang.nativeName.split(", ")[0]} (${lang.iso639_1})`;
|
|
50
59
|
return lang.iso639_1;
|
|
51
60
|
}
|
|
52
61
|
}
|
|
53
62
|
}
|
|
63
|
+
if (specialLangs[language]) return `${specialLangs[language]} (${language})`;
|
|
54
64
|
return null;
|
|
55
65
|
}
|
|
56
66
|
|