aboutsummaryrefslogtreecommitdiff
path: root/ext/bg/js/audio.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/bg/js/audio.js')
-rw-r--r--ext/bg/js/audio.js152
1 files changed, 75 insertions, 77 deletions
diff --git a/ext/bg/js/audio.js b/ext/bg/js/audio.js
index 2e5db7cc..9e0ae67c 100644
--- a/ext/bg/js/audio.js
+++ b/ext/bg/js/audio.js
@@ -17,8 +17,8 @@
*/
-async function audioBuildUrl(definition, mode, cache={}) {
- if (mode === 'jpod101') {
+const audioUrlBuilders = {
+ 'jpod101': async (definition) => {
let kana = definition.reading;
let kanji = definition.expression;
@@ -35,84 +35,80 @@ async function audioBuildUrl(definition, mode, cache={}) {
params.push(`kana=${encodeURIComponent(kana)}`);
}
- const url = `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?${params.join('&')}`;
- return Promise.resolve(url);
- } else if (mode === 'jpod101-alternate') {
- return new Promise((resolve, reject) => {
- const response = cache[definition.expression];
- if (response) {
- resolve(response);
- } else {
- const data = {
- post: 'dictionary_reference',
- match_type: 'exact',
- search_query: definition.expression
- };
-
- const params = [];
- for (const key in data) {
- params.push(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`);
- }
-
- const xhr = new XMLHttpRequest();
- xhr.open('POST', 'https://www.japanesepod101.com/learningcenter/reference/dictionary_post');
- xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
- xhr.addEventListener('error', () => reject('Failed to scrape audio data'));
- xhr.addEventListener('load', () => {
- cache[definition.expression] = xhr.responseText;
- resolve(xhr.responseText);
- });
-
- xhr.send(params.join('&'));
- }
- }).then(response => {
- const dom = new DOMParser().parseFromString(response, 'text/html');
- for (const row of dom.getElementsByClassName('dc-result-row')) {
- try {
- const url = row.querySelector('audio>source[src]').getAttribute('src');
- const reading = row.getElementsByClassName('dc-vocab_kana').item(0).innerText;
- if (url && reading && (!definition.reading || definition.reading === reading)) {
- return audioUrlNormalize(url, 'https://www.japanesepod101.com', '/learningcenter/reference/');
- }
- } catch (e) {
- // NOP
- }
- }
+ return `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?${params.join('&')}`;
+ },
+ 'jpod101-alternate': async (definition) => {
+ const response = await new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('POST', 'https://www.japanesepod101.com/learningcenter/reference/dictionary_post');
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ xhr.addEventListener('error', () => reject(new Error('Failed to scrape audio data')));
+ xhr.addEventListener('load', () => resolve(xhr.responseText));
+ xhr.send(`post=dictionary_reference&match_type=exact&search_query=${encodeURIComponent(definition.expression)}`);
});
- } else if (mode === 'jisho') {
- return new Promise((resolve, reject) => {
- const response = cache[definition.expression];
- if (response) {
- resolve(response);
- } else {
- const xhr = new XMLHttpRequest();
- xhr.open('GET', `https://jisho.org/search/${definition.expression}`);
- xhr.addEventListener('error', () => reject('Failed to scrape audio data'));
- xhr.addEventListener('load', () => {
- cache[definition.expression] = xhr.responseText;
- resolve(xhr.responseText);
- });
-
- xhr.send();
- }
- }).then(response => {
+
+ const dom = new DOMParser().parseFromString(response, 'text/html');
+ for (const row of dom.getElementsByClassName('dc-result-row')) {
try {
- const dom = new DOMParser().parseFromString(response, 'text/html');
- const audio = dom.getElementById(`audio_${definition.expression}:${definition.reading}`);
- if (audio) {
- const url = audio.getElementsByTagName('source').item(0).getAttribute('src');
- if (url) {
- return audioUrlNormalize(url, 'https://jisho.org', '/search/');
- }
+ const url = row.querySelector('audio>source[src]').getAttribute('src');
+ const reading = row.getElementsByClassName('dc-vocab_kana').item(0).innerText;
+ if (url && reading && (!definition.reading || definition.reading === reading)) {
+ return audioUrlNormalize(url, 'https://www.japanesepod101.com', '/learningcenter/reference/');
}
} catch (e) {
// NOP
}
+ }
+
+ throw new Error('Failed to find audio URL');
+ },
+ 'jisho': async (definition) => {
+ const response = await new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', `https://jisho.org/search/${definition.expression}`);
+ xhr.addEventListener('error', () => reject(new Error('Failed to scrape audio data')));
+ xhr.addEventListener('load', () => resolve(xhr.responseText));
+ xhr.send();
});
+
+ const dom = new DOMParser().parseFromString(response, 'text/html');
+ try {
+ const audio = dom.getElementById(`audio_${definition.expression}:${definition.reading}`);
+ if (audio !== null) {
+ const url = audio.getElementsByTagName('source').item(0).getAttribute('src');
+ if (url) {
+ return audioUrlNormalize(url, 'https://jisho.org', '/search/');
+ }
+ }
+ } catch (e) {
+ // NOP
+ }
+
+ throw new Error('Failed to find audio URL');
+ },
+ 'custom': async (definition, optionsContext) => {
+ const options = await apiOptionsGet(optionsContext);
+ const customSourceUrl = options.audio.customSourceUrl;
+ return customSourceUrl.replace(/\{([^\}]*)\}/g, (m0, m1) => (definition.hasOwnProperty(m1) ? `${definition[m1]}` : m0));
}
- else {
- return Promise.resolve();
+};
+
+async function audioBuildUrl(definition, mode, optionsContext, cache={}) {
+ const cacheKey = `${mode}:${definition.expression}`;
+ if (cache.hasOwnProperty(cacheKey)) {
+ return Promise.resolve(cache[cacheKey]);
+ }
+
+ if (audioUrlBuilders.hasOwnProperty(mode)) {
+ const handler = audioUrlBuilders[mode];
+ return handler(definition, optionsContext).then(
+ (url) => {
+ cache[cacheKey] = url;
+ return url;
+ },
+ () => null);
}
+ return null;
}
function audioUrlNormalize(url, baseUrl, basePath) {
@@ -145,9 +141,10 @@ function audioBuildFilename(definition) {
return filename += '.mp3';
}
+ return null;
}
-async function audioInject(definition, fields, mode) {
+async function audioInject(definition, fields, sources, optionsContext) {
let usesAudio = false;
for (const name in fields) {
if (fields[name].includes('{audio}')) {
@@ -166,11 +163,12 @@ async function audioInject(definition, fields, mode) {
audioSourceDefinition = definition.expressions[0];
}
- const url = await audioBuildUrl(audioSourceDefinition, mode);
- const filename = audioBuildFilename(audioSourceDefinition);
-
- if (url && filename) {
- definition.audio = {url, filename};
+ const {url} = await audioGetFromSources(audioSourceDefinition, sources, optionsContext, false);
+ if (url !== null) {
+ const filename = audioBuildFilename(audioSourceDefinition);
+ if (filename !== null) {
+ definition.audio = {url, filename};
+ }
}
return true;