mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-29 07:53:27 -04:00
96 lines
2.9 KiB
Vue
96 lines
2.9 KiB
Vue
<template>
|
||
<Tooltip :text="$t('pronunciation.play')">
|
||
<a
|
||
:class="['btn', 'btn-sm', 'btn-link', 'px-1', 'py-0', !pronunciation ? 'disabled' : '']"
|
||
dir="ltr"
|
||
:href="pronunciationLink"
|
||
target="_blank"
|
||
@click.prevent="pronounce"
|
||
>
|
||
<Icon :v="icon" /><sub v-if="name">{{ name }}</sub>
|
||
</a>
|
||
</Tooltip>
|
||
</template>
|
||
|
||
|
||
<script lang="ts">
|
||
import { Base64 } from 'js-base64';
|
||
import Vue from 'vue';
|
||
import type { PropType } from 'vue';
|
||
|
||
const STATE_IDLE = 'idle';
|
||
const STATE_LOADING = 'loading';
|
||
const STATE_PLAYING = 'playing';
|
||
|
||
export default Vue.extend({
|
||
props: {
|
||
pronunciation: { default: null, type: String as PropType<string | null> },
|
||
voice: { required: true, type: String },
|
||
},
|
||
data(): { state: 'idle' | 'loading' | 'playing', sound: HTMLAudioElement | null } {
|
||
return {
|
||
state: STATE_IDLE,
|
||
sound: null,
|
||
};
|
||
},
|
||
computed: {
|
||
pronunciationLink(): string | undefined {
|
||
if (!this.pronunciation) {
|
||
return undefined;
|
||
}
|
||
|
||
return `/api/pronounce/${this.voice}/${Base64.encodeURI(this.pronunciation)}`;
|
||
},
|
||
name(): string | null {
|
||
if (!this.$config.pronunciation?.enabled) {
|
||
return this.voice;
|
||
}
|
||
|
||
const voices = Object.keys(this.$config.pronunciation.voices);
|
||
if (voices.length === 1 && this.voice === voices[0]) {
|
||
// don’t show voice name if it is considered the main voice for this locale
|
||
return null;
|
||
}
|
||
|
||
return this.voice;
|
||
},
|
||
icon(): string {
|
||
switch (this.state) {
|
||
case STATE_LOADING:
|
||
return 'spinner fa-spin';
|
||
case STATE_PLAYING:
|
||
return 'volume-up';
|
||
case STATE_IDLE:
|
||
default:
|
||
return 'volume';
|
||
}
|
||
},
|
||
},
|
||
methods: {
|
||
pronounce() {
|
||
if (!this.pronunciationLink) {
|
||
return;
|
||
}
|
||
if (this.sound && this.sound.src.endsWith(this.pronunciationLink) && !this.sound.error) {
|
||
// reuse the sound object if it has the same source and has been loaded without an error
|
||
this.sound.pause();
|
||
this.sound.currentTime = 0;
|
||
this.sound.play();
|
||
|
||
return;
|
||
}
|
||
|
||
this.sound = new Audio(this.pronunciationLink);
|
||
|
||
this.sound.addEventListener('canplay', () => this.sound!.play());
|
||
this.sound.addEventListener('play', () => this.state = STATE_PLAYING);
|
||
this.sound.addEventListener('ended', () => this.state = STATE_IDLE);
|
||
this.sound.addEventListener('error', () => this.state = STATE_IDLE);
|
||
|
||
this.state = STATE_LOADING;
|
||
this.sound.load();
|
||
},
|
||
},
|
||
});
|
||
</script>
|