diff --git a/README.md b/README.md index 4949308f15..3b29a2278c 100644 --- a/README.md +++ b/README.md @@ -128,4 +128,4 @@ Yomitan uses several third-party libraries to function. ## Attribution -`button.mp3` is provided by [UNIVERSFIELD](https://pixabay.com/sound-effects/error-8-206492/) and licensed under the [Pixabay Content License](https://pixabay.com/service/license-summary/). +`fallback-bloop.mp3` is provided by [UNIVERSFIELD](https://pixabay.com/sound-effects/error-8-206492/) and licensed under the [Pixabay Content License](https://pixabay.com/service/license-summary/). diff --git a/ext/data/audio/button.mp3 b/ext/data/audio/fallback-bloop.mp3 similarity index 100% rename from ext/data/audio/button.mp3 rename to ext/data/audio/fallback-bloop.mp3 diff --git a/ext/data/audio/fallback-click.mp3 b/ext/data/audio/fallback-click.mp3 new file mode 100644 index 0000000000..7a9728d1c8 Binary files /dev/null and b/ext/data/audio/fallback-click.mp3 differ diff --git a/ext/data/schemas/options-schema.json b/ext/data/schemas/options-schema.json index c47f7063fd..227bc945ec 100644 --- a/ext/data/schemas/options-schema.json +++ b/ext/data/schemas/options-schema.json @@ -391,7 +391,7 @@ "enabled", "volume", "autoPlay", - "playFallbackSound", + "fallbackSoundType", "sources" ], "properties": { @@ -409,9 +409,10 @@ "type": "boolean", "default": false }, - "playFallbackSound": { - "type": "boolean", - "default": true + "fallbackSoundType": { + "type": "string", + "enum": ["none", "click", "bloop"], + "default": "click" }, "sources": { "type": "array", diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index 6c2bb816cf..b4d6129940 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -571,6 +571,7 @@ export class OptionsUtil { this._updateVersion57, this._updateVersion58, this._updateVersion59, + this._updateVersion60, ]; /* eslint-enable @typescript-eslint/unbound-method */ if (typeof targetVersion === 'number' && targetVersion < result.length) { @@ -1594,6 +1595,17 @@ export class OptionsUtil { } } + /** + * - Replaced audio.playFallbackSound with audio.fallbackSoundType + * @type {import('options-util').UpdateFunction} + */ + async _updateVersion60(options) { + for (const profile of options.profiles) { + profile.options.audio.fallbackSoundType = profile.options.audio.playFallbackSound ? 'click' : 'none'; + delete profile.options.audio.playFallbackSound; + } + } + /** * @param {string} url * @returns {Promise} diff --git a/ext/js/display/display-audio.js b/ext/js/display/display-audio.js index ef035857ce..87f5691370 100644 --- a/ext/js/display/display-audio.js +++ b/ext/js/display/display-audio.js @@ -36,8 +36,8 @@ export class DisplayAudio { this._playbackVolume = 1; /** @type {boolean} */ this._autoPlay = false; - /** @type {boolean} */ - this._playFallbackSound = true; + /** @type {import('settings').FallbackSoundType} */ + this._fallbackSoundType = 'none'; /** @type {?import('core').Timeout} */ this._autoPlayAudioTimer = null; /** @type {number} */ @@ -170,10 +170,10 @@ export class DisplayAudio { _onOptionsUpdated({options}) { const { general: {language}, - audio: {enabled, autoPlay, playFallbackSound, volume, sources}, + audio: {enabled, autoPlay, fallbackSoundType, volume, sources}, } = options; this._autoPlay = enabled && autoPlay; - this._playFallbackSound = playFallbackSound; + this._fallbackSoundType = fallbackSoundType; this._playbackVolume = Number.isFinite(volume) ? Math.max(0, Math.min(1, volume / 100)) : 1; /** @type {Set} */ @@ -454,7 +454,7 @@ export class DisplayAudio { const sourceIndex = sources.indexOf(source); title = `From source ${1 + sourceIndex}: ${source.name}`; } else { - audio = this._audioSystem.getFallbackAudio(this._playFallbackSound); + audio = this._audioSystem.getFallbackAudio(this._fallbackSoundType); title = 'Could not find audio'; } diff --git a/ext/js/media/audio-system.js b/ext/js/media/audio-system.js index 7a7e40bebd..0dfa2d20f9 100644 --- a/ext/js/media/audio-system.js +++ b/ext/js/media/audio-system.js @@ -27,8 +27,8 @@ export class AudioSystem extends EventDispatcher { super(); /** @type {?HTMLAudioElement} */ this._fallbackAudio = null; - /** @type {?boolean} */ - this._playFallbackSound = null; + /** @type {?import('settings').FallbackSoundType} */ + this._fallbackSoundType = null; } /** @@ -45,14 +45,24 @@ export class AudioSystem extends EventDispatcher { } /** - * @param {boolean} playFallbackSound + * @param {import('settings').FallbackSoundType} fallbackSoundType * @returns {HTMLAudioElement} */ - getFallbackAudio(playFallbackSound) { - if (this._fallbackAudio === null || this._playFallbackSound !== playFallbackSound) { - // audio handler expects audio url to always be present, empty string must be used instead of `new Audio()` - this._fallbackAudio = playFallbackSound ? new Audio('/data/audio/button.mp3') : new Audio(''); - this._playFallbackSound = playFallbackSound; + getFallbackAudio(fallbackSoundType) { + if (this._fallbackAudio === null || this._fallbackSoundType !== fallbackSoundType) { + this._fallbackSoundType = fallbackSoundType; + switch (fallbackSoundType) { + case 'click': + this._fallbackAudio = new Audio('/data/audio/fallback-click.mp3'); + break; + case 'bloop': + this._fallbackAudio = new Audio('/data/audio/fallback-bloop.mp3'); + break; + case 'none': + // audio handler expects audio url to always be present, empty string must be used instead of `new Audio()` + this._fallbackAudio = new Audio(''); + break; + } } return this._fallbackAudio; } diff --git a/ext/settings.html b/ext/settings.html index 924c230fe5..b6b3101545 100644 --- a/ext/settings.html +++ b/ext/settings.html @@ -1461,15 +1461,23 @@

Yomitan Settings

-
-
-
Enable audio fallback sound
-
Play sound when Yomitan fails to fetch audio.
-
-
- +
+
+
+
Audio fallback sound
+
+ The sound to play when Yomitan fails to fetch audio. +
+
+
+ +
-
+
Audio volume
diff --git a/test/options-util.test.js b/test/options-util.test.js index bc41089571..8505a27204 100644 --- a/test/options-util.test.js +++ b/test/options-util.test.js @@ -76,7 +76,7 @@ function createProfileOptionsTestData1() { sources: ['jpod101', 'text-to-speech', 'custom', 'jpod101-alternate'], volume: 100, autoPlay: false, - playFallbackSound: true, + fallbackSoundType: 'click', customSourceUrl: 'http://localhost/audio.mp3?term={expression}&reading={reading}', textToSpeechVoice: 'example-voice', }, @@ -337,7 +337,7 @@ function createProfileOptionsUpdatedTestData1() { ], volume: 100, autoPlay: false, - playFallbackSound: true, + fallbackSoundType: 'click', }, scanning: { selectText: true, @@ -680,7 +680,7 @@ function createOptionsUpdatedTestData1() { }, ], profileCurrent: 0, - version: 59, + version: 60, global: { database: { prefixWildcardsSupported: false, diff --git a/types/ext/settings.d.ts b/types/ext/settings.d.ts index 5ca7e62c39..f5111e629b 100644 --- a/types/ext/settings.d.ts +++ b/types/ext/settings.d.ts @@ -167,10 +167,12 @@ export type AudioOptions = { enabled: boolean; volume: number; autoPlay: boolean; - playFallbackSound: boolean; + fallbackSoundType: FallbackSoundType; sources: AudioSourceOptions[]; }; +export type FallbackSoundType = 'none' | 'click' | 'bloop'; + export type AudioSourceOptions = { type: AudioSourceType; url: string;