aboutsummaryrefslogtreecommitdiff
path: root/ext/bg
diff options
context:
space:
mode:
Diffstat (limited to 'ext/bg')
-rw-r--r--ext/bg/js/audio.js104
-rw-r--r--ext/bg/js/backend.js8
2 files changed, 64 insertions, 48 deletions
diff --git a/ext/bg/js/audio.js b/ext/bg/js/audio.js
index 361a19cc..80e9cb9a 100644
--- a/ext/bg/js/audio.js
+++ b/ext/bg/js/audio.js
@@ -18,8 +18,49 @@
/*global jpIsStringEntirelyKana*/
-const audioUrlBuilders = new Map([
- ['jpod101', async (definition) => {
+class AudioUriBuilder {
+ constructor() {
+ this._getUrlHandlers = new Map([
+ ['jpod101', this._getUriJpod101.bind(this)],
+ ['jpod101-alternate', this._getUriJpod101Alternate.bind(this)],
+ ['jisho', this._getUriJisho.bind(this)],
+ ['text-to-speech', this._getUriTextToSpeech.bind(this)],
+ ['text-to-speech-reading', this._getUriTextToSpeechReading.bind(this)],
+ ['custom', this._getUriCustom.bind(this)]
+ ]);
+ }
+
+ normalizeUrl(url, baseUrl, basePath) {
+ if (url) {
+ if (url[0] === '/') {
+ if (url.length >= 2 && url[1] === '/') {
+ // Begins with "//"
+ url = baseUrl.substring(0, baseUrl.indexOf(':') + 1) + url;
+ } else {
+ // Begins with "/"
+ url = baseUrl + url;
+ }
+ } else if (!/^[a-z][a-z0-9\-+.]*:/i.test(url)) {
+ // No URI scheme => relative path
+ url = baseUrl + basePath + url;
+ }
+ }
+ return url;
+ }
+
+ async getUri(mode, definition, options) {
+ const handler = this._getUrlHandlers.get(mode);
+ if (typeof handler === 'function') {
+ try {
+ return await handler(definition, options);
+ } catch (e) {
+ // NOP
+ }
+ }
+ return null;
+ }
+
+ async _getUriJpod101(definition) {
let kana = definition.reading;
let kanji = definition.expression;
@@ -37,8 +78,9 @@ const audioUrlBuilders = new Map([
}
return `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?${params.join('&')}`;
- }],
- ['jpod101-alternate', async (definition) => {
+ }
+
+ async _getUriJpod101Alternate(definition) {
const response = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://www.japanesepod101.com/learningcenter/reference/dictionary_post');
@@ -54,7 +96,7 @@ const audioUrlBuilders = new Map([
const url = row.querySelector('audio>source[src]').getAttribute('src');
const reading = row.getElementsByClassName('dc-vocab_kana').item(0).textContent;
if (url && reading && (!definition.reading || definition.reading === reading)) {
- return audioUrlNormalize(url, 'https://www.japanesepod101.com', '/learningcenter/reference/');
+ return this.normalizeUrl(url, 'https://www.japanesepod101.com', '/learningcenter/reference/');
}
} catch (e) {
// NOP
@@ -62,8 +104,9 @@ const audioUrlBuilders = new Map([
}
throw new Error('Failed to find audio URL');
- }],
- ['jisho', async (definition) => {
+ }
+
+ async _getUriJisho(definition) {
const response = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', `https://jisho.org/search/${definition.expression}`);
@@ -78,7 +121,7 @@ const audioUrlBuilders = new Map([
if (audio !== null) {
const url = audio.getElementsByTagName('source').item(0).getAttribute('src');
if (url) {
- return audioUrlNormalize(url, 'https://jisho.org', '/search/');
+ return this.normalizeUrl(url, 'https://jisho.org', '/search/');
}
}
} catch (e) {
@@ -86,55 +129,28 @@ const audioUrlBuilders = new Map([
}
throw new Error('Failed to find audio URL');
- }],
- ['text-to-speech', async (definition, options) => {
+ }
+
+ async _getUriTextToSpeech(definition, options) {
const voiceURI = options.audio.textToSpeechVoice;
if (!voiceURI) {
throw new Error('No voice');
}
return `tts:?text=${encodeURIComponent(definition.expression)}&voice=${encodeURIComponent(voiceURI)}`;
- }],
- ['text-to-speech-reading', async (definition, options) => {
+ }
+
+ async _getUriTextToSpeechReading(definition, options) {
const voiceURI = options.audio.textToSpeechVoice;
if (!voiceURI) {
throw new Error('No voice');
}
return `tts:?text=${encodeURIComponent(definition.reading || definition.expression)}&voice=${encodeURIComponent(voiceURI)}`;
- }],
- ['custom', async (definition, options) => {
- const customSourceUrl = options.audio.customSourceUrl;
- return customSourceUrl.replace(/\{([^}]*)\}/g, (m0, m1) => (hasOwn(definition, m1) ? `${definition[m1]}` : m0));
- }]
-]);
-
-async function audioGetUrl(definition, mode, options, download) {
- const handler = audioUrlBuilders.get(mode);
- if (typeof handler === 'function') {
- try {
- return await handler(definition, options, download);
- } catch (e) {
- // NOP
- }
}
- return null;
-}
-function audioUrlNormalize(url, baseUrl, basePath) {
- if (url) {
- if (url[0] === '/') {
- if (url.length >= 2 && url[1] === '/') {
- // Begins with "//"
- url = baseUrl.substring(0, baseUrl.indexOf(':') + 1) + url;
- } else {
- // Begins with "/"
- url = baseUrl + url;
- }
- } else if (!/^[a-z][a-z0-9\-+.]*:/i.test(url)) {
- // No URI scheme => relative path
- url = baseUrl + basePath + url;
- }
+ async _getUriCustom(definition, options) {
+ const customSourceUrl = options.audio.customSourceUrl;
+ return customSourceUrl.replace(/\{([^}]*)\}/g, (m0, m1) => (hasOwn(definition, m1) ? `${definition[m1]}` : m0));
}
- return url;
}
diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js
index 1fdc4c70..66378b0c 100644
--- a/ext/bg/js/backend.js
+++ b/ext/bg/js/backend.js
@@ -21,9 +21,8 @@ conditionsTestValue, profileConditionsDescriptor
handlebarsRenderDynamic
requestText, requestJson, optionsLoad
dictConfigured, dictTermsSort, dictEnabledSet
-audioGetUrl
jpConvertReading, jpDistributeFuriganaInflected, jpKatakanaToHiragana
-AnkiNoteBuilder, AudioSystem, Translator, AnkiConnect, AnkiNull, Mecab, BackendApiForwarder, JsonSchema, ClipboardMonitor*/
+AnkiNoteBuilder, AudioSystem, AudioUriBuilder, Translator, AnkiConnect, AnkiNull, Mecab, BackendApiForwarder, JsonSchema, ClipboardMonitor*/
class Backend {
constructor() {
@@ -36,6 +35,7 @@ class Backend {
this.optionsSchema = null;
this.defaultAnkiFieldTemplates = null;
this.audioSystem = new AudioSystem({getAudioUri: this._getAudioUri.bind(this)});
+ this.audioUriBuilder = new AudioUriBuilder();
this.optionsContext = {
depth: 0,
url: window.location.href
@@ -515,7 +515,7 @@ class Backend {
async _onApiAudioGetUrl({definition, source, optionsContext}) {
const options = this.getOptions(optionsContext);
- return await audioGetUrl(definition, source, options);
+ return await this.audioUriBuilder.getUri(source, definition, options);
}
_onApiScreenshotGet({options}, sender) {
@@ -771,7 +771,7 @@ class Backend {
}
const options = this.getOptions(optionsContext);
- return await audioGetUrl(definition, source, options);
+ return await this.audioUriBuilder.getUri(source, definition, options);
}
async _audioInject(definition, fields, sources, optionsContext) {