diff --git a/ext/bg/background.html b/ext/bg/background.html index 3b37db87..194d4a45 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -27,6 +27,7 @@ + diff --git a/ext/bg/js/audio.js b/ext/bg/js/audio.js index 26896027..0bf836df 100644 --- a/ext/bg/js/audio.js +++ b/ext/bg/js/audio.js @@ -136,6 +136,7 @@ function audioBuildFilename(definition) { return filename += '.mp3'; } + return null; } async function audioInject(definition, fields, sources, optionsContext) { @@ -157,11 +158,12 @@ async function audioInject(definition, fields, sources, optionsContext) { audioSourceDefinition = definition.expressions[0]; } - const url = await audioBuildUrl(audioSourceDefinition, sources[0], optionsContext); - 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; diff --git a/ext/bg/search.html b/ext/bg/search.html index e71824d3..3284ed43 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -36,7 +36,6 @@ - @@ -44,6 +43,7 @@ + diff --git a/ext/fg/float.html b/ext/fg/float.html index 52c7faa3..fe1aee8f 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -39,6 +39,7 @@ + diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js new file mode 100644 index 00000000..b905140c --- /dev/null +++ b/ext/mixed/js/audio.js @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 Alex Yatskov + * Author: Alex Yatskov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +function audioGetFromUrl(url) { + return new Promise((resolve, reject) => { + const audio = new Audio(url); + audio.addEventListener('loadeddata', () => { + if (audio.duration === 5.694694 || audio.duration === 5.720718) { + // Hardcoded values for invalid audio + reject(new Error('Could not retrieve audio')); + } else { + resolve(audio); + } + }); + audio.addEventListener('error', () => reject(audio.error)); + }); +} + +async function audioGetFromSources(expression, sources, optionsContext, createAudioObject, cache=null) { + const key = `${expression.expression}:${expression.reading}`; + if (cache !== null && cache.hasOwnProperty(expression)) { + return cache[key]; + } + + for (let i = 0, ii = sources.length; i < ii; ++i) { + const source = sources[i]; + const url = await apiAudioGetUrl(expression, source, optionsContext); + if (url === null) { + continue; + } + + try { + const audio = createAudioObject ? await audioGetFromUrl(url) : null; + const result = {audio, url, source}; + if (cache !== null) { + cache[key] = result; + } + return result; + } catch (e) { + // NOP + } + } + return {audio: null, source: null}; +} diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index c1224084..8d4e1e68 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -26,6 +26,8 @@ class Display { this.context = null; this.sequence = 0; this.index = 0; + this.audioPlaying = null; + this.audioFallback = null; this.audioCache = {}; this.optionsContext = {}; this.eventListeners = []; @@ -404,33 +406,24 @@ class Display { this.setSpinnerVisible(true); const expression = expressionIndex === -1 ? definition : definition.expressions[expressionIndex]; - let url = await apiAudioGetUrl(expression, this.options.audio.sources[0], this.optionsContext); - if (!url) { - url = '/mixed/mp3/button.mp3'; + + if (this.audioPlaying !== null) { + this.audioPlaying.pause(); + this.audioPlaying = null; } - for (const key in this.audioCache) { - this.audioCache[key].pause(); + let {audio} = await audioGetFromSources(expression, this.options.audio.sources, this.optionsContext, true, this.audioCache); + if (audio === null) { + if (this.audioFallback === null) { + this.audioFallback = new Audio('/mixed/mp3/button.mp3'); + } + audio = this.audioFallback; } - const volume = this.options.audio.volume / 100.0; - let audio = this.audioCache[url]; - if (audio) { - audio.currentTime = 0; - audio.volume = volume; - audio.play(); - } else { - audio = new Audio(url); - audio.onloadeddata = () => { - if (audio.duration === 5.694694 || audio.duration === 5.720718) { - audio = new Audio('/mixed/mp3/button.mp3'); - } - - this.audioCache[url] = audio; - audio.volume = volume; - audio.play(); - }; - } + this.audioPlaying = audio; + audio.currentTime = 0; + audio.volume = this.options.audio.volume / 100.0; + audio.play(); } catch (e) { this.onError(e); } finally {