@huluvu424242/honey-speech
Version:
Text to Speech component wich is reading texts from DOM elements.
366 lines (358 loc) • 12.6 kB
JavaScript
import { attachShadow, createEvent, h, Host, proxyCustomElement } from '@stencil/core/internal/client';
export { setAssetPath } from '@stencil/core/internal/client';
class Logger {
constructor(enableLogging) {
Logger.isLoggingActive = enableLogging;
}
static disableLogging() {
this.isLoggingActive = false;
}
static enableLogging() {
this.isLoggingActive = true;
}
static toggleLogging(enableLogging) {
if (enableLogging) {
Logger.enableLogging();
}
else {
Logger.disableLogging();
}
}
static logMessage(message) {
if (console && this.isLoggingActive) {
console.log(message);
}
}
static debugMessage(message) {
if (console && this.isLoggingActive) {
console.debug(message);
}
}
static errorMessage(message) {
if (console && this.isLoggingActive) {
console.error(message);
}
}
static infoMessage(message) {
if (console && this.isLoggingActive) {
console.info(message);
}
}
}
Logger.isLoggingActive = true;
class Synthese {
constructor() {
this.sprachSynthese = window.speechSynthesis;
this.sprachSynthese.onvoiceschanged = () => {
if (!this.voices || this.voices.length < 1) {
this.voices = this.sprachSynthese.getVoices();
Logger.debugMessage("voices changed to: " + this.voices.join(","));
}
else {
Logger.debugMessage("voices alraedy initialized");
}
};
Logger.debugMessage("call getVoices()");
this.sprachSynthese.getVoices();
}
getVoices() {
return this.voices;
}
cancel() {
this.sprachSynthese.cancel();
}
}
class Sprachausgabe {
constructor(onSpeakerStarted, onSpeakerFinished, onSpeakerPaused, onSpeakerResume, onSpeakerFailed, audioLang, audioPitch, audioRate, audioVolume, voiceName) {
this.onSpeakerStarted = (ev) => onSpeakerStarted(ev);
this.onSpeakerFinished = (ev) => onSpeakerFinished(ev);
this.onSpeakerPaused = (ev) => onSpeakerPaused(ev);
this.onSpeakerResume = (ev) => onSpeakerResume(ev);
this.onSpeakerFailed = (ev) => onSpeakerFailed(ev);
this.audioLang = audioLang;
this.audioPitch = audioPitch;
this.audioRate = audioRate;
this.audioVolume = audioVolume;
this.voiceName = voiceName;
this.stimme = undefined;
Logger.infoMessage("####constructor finished");
}
getDefaultStimme() {
var namedMatch;
var langMatches = [];
var langDefaultMatch;
var defaultMatch;
const voices = Sprachausgabe.synthese.getVoices();
Logger.infoMessage("Found voices:" + JSON.stringify(voices));
if (!voices)
return null;
for (var i = 0; i < voices.length; i++) {
if (voices[i].name === this.voiceName ||
voices[i].lang === this.audioLang ||
voices[i].default) {
Logger.debugMessage("voice matched:" + voices[i].name + voices[i].lang);
if (voices[i].name === this.voiceName) {
namedMatch = voices[i];
}
if (voices[i].lang === this.audioLang &&
voices[i].default) {
langDefaultMatch = voices[i];
}
if (voices[i].lang === this.audioLang) {
langMatches.push(voices[i]);
}
if (voices[i].default) {
defaultMatch = voices[i];
}
}
}
// Auswertung
if (namedMatch) {
return namedMatch;
}
if (langDefaultMatch) {
return langDefaultMatch;
}
if (langMatches && langMatches.length > 0) {
return langMatches[0];
}
if (defaultMatch) {
return defaultMatch;
}
return voices[0];
}
erzeugeVorleser(text) {
Logger.infoMessage("erzeugeVorleser started");
const vorleser = new SpeechSynthesisUtterance(text);
vorleser.onend = this.onSpeakerFinished;
vorleser.onstart = this.onSpeakerStarted;
vorleser.onpause = this.onSpeakerPaused;
vorleser.onresume = this.onSpeakerResume;
vorleser.onerror = this.onSpeakerFailed;
vorleser.pitch = this.audioPitch;
vorleser.rate = this.audioRate;
vorleser.volume = this.audioVolume;
vorleser.voice = this.stimme;
vorleser.lang = this.audioLang;
return vorleser;
}
textVorlesen(zuLesenderText) {
if (!this.stimme) {
this.stimme = this.getDefaultStimme();
Logger.infoMessage("set default voice to " + this.stimme);
}
if (zuLesenderText) {
const texte = zuLesenderText.match(/(\S+\s){1,20}/g);
texte.forEach(text => {
const vorleser = this.erzeugeVorleser(text);
Logger.infoMessage("speaker lang used:" + vorleser.lang);
if (vorleser.voice) {
Logger.infoMessage("speaker voice used:" + vorleser.voice.name);
Logger.infoMessage("speaker voice lang:" + vorleser.voice.lang);
}
else {
Logger.infoMessage("no voice matched for text: " + zuLesenderText);
}
Sprachausgabe.synthese.sprachSynthese.speak(vorleser);
});
}
}
cancel() {
Sprachausgabe.synthese.sprachSynthese.cancel();
}
}
Sprachausgabe.synthese = new Synthese();
const honeySpeechCss = ".speakerimage{background:var(--honey-speaker-background, transparent);stroke:var(--honey-speaker-color, blue);fill:var(--honey-speaker-color, blue);padding:var(--honey-speaker-padding, 5px);font-size:var(--honey-speaker-font-size, medium);border:var(--honey-speaker-border, 0);width:var(--honey-speaker-width, 36px);height:var(--honey-speaker-height, 36px)}";
const HoneySpeech = class extends HTMLElement {
constructor() {
super();
this.__registerHost();
attachShadow(this);
this.honeySpeakerStarted = createEvent(this, "honeySpeakerStarted", 7);
this.honeySpeakerFinished = createEvent(this, "honeySpeakerFinished", 7);
this.honeySpeakerPaused = createEvent(this, "honeySpeakerPaused", 7);
this.honeySpeakerResume = createEvent(this, "honeySpeakerResume", 7);
this.honeySpeakerFailed = createEvent(this, "honeySpeakerFailed", 7);
/**
* true wenn das Tag ohne alt Attribute deklariert wurde
*/
this.createAltText = false;
/**
* true wenn das Tag ohne title Attribut deklariert wurde
*/
this.createTitleText = false;
/**
* taborder
*/
this.taborder = "0";
/**
* if the toggle button is pressed
*/
this.isPressed = false;
/**
* use pure speaker symbol for silence state
*/
this.pure = false;
/**
* enable console logging
*/
this.verbose = false;
/**
* icon width
*/
this.iconwidth = "36";
/**
* icon height
*/
this.iconheight = "36";
/**
* i18n language ident for Web Speech API: de-DE or en or de ...
*/
this.audiolang = "de-DE";
/**
* pitch for Web Speech API
*/
this.audiopitch = 1;
/**
* rate for Web Speech API
*/
this.audiorate = 1;
/**
* volume for Web Speech API
*/
this.audiovolume = 1;
/**
* voice name used of Web Speech API
*/
this.voicename = undefined;
}
connectedCallback() {
// States initialisieren
this.ident = this.hostElement.id ? this.hostElement.id : Math.random().toString(36).substring(7);
this.createTitleText = !this.hostElement.title;
this.createAltText = !this.hostElement["alt"];
this.taborder = this.hostElement.getAttribute("tabindex") ? (this.hostElement.tabIndex + "") : "0";
// Properties auswerten
Logger.toggleLogging(this.verbose);
}
componentWillLoad() {
this.sprachAusgabe = new Sprachausgabe(() => {
this.honeySpeakerStarted.emit(this.ident);
this.isPressed = true;
Logger.debugMessage("Vorlesen gestartet");
}, () => {
this.honeySpeakerFinished.emit(this.ident);
this.isPressed = false;
Logger.debugMessage("Vorlesen beendet");
}, () => {
this.honeySpeakerPaused.emit(this.ident);
this.isPressed = false;
Logger.debugMessage("Pause mit Vorlesen");
}, () => {
this.honeySpeakerResume.emit(this.ident);
this.isPressed = true;
Logger.debugMessage("Fortsetzen mit Vorlesen");
}, (ev) => {
this.honeySpeakerFailed.emit(this.ident);
this.isPressed = false;
Logger.errorMessage("Fehler beim Vorlesen" + JSON.stringify(ev));
}, this.audiolang, this.audiopitch, this.audiorate, this.audiovolume, this.voicename);
}
createNewTitleText() {
if (this.isPressed) {
return "Liest gerade vor";
}
else {
return "Vorlesen";
}
}
getTitleText() {
if (this.createTitleText) {
return this.createNewTitleText();
}
else {
return this.hostElement.title;
}
}
createNewAltText() {
if (this.isPressed) {
return "Symbol eines stummen Lautsprechers";
}
else {
return "Symbol eines tönenden Lautsprechers";
}
}
getAltText() {
if (this.createAltText) {
return this.createNewAltText();
}
else {
return this.hostElement.getAttribute("alt");
}
}
getTexte() {
if (this.textids) {
const refIds = this.textids.split(",");
const texte = [];
refIds.forEach(elementId => {
const element = document.getElementById(elementId);
if (element) {
texte.push(element.innerText);
}
else {
Logger.errorMessage("text to speak not found of DOM element with id " + elementId);
}
});
return texte;
}
else {
return ["Kein Text vorhanden, daher keine Ausgabe möglich."];
}
}
async textVorlesen(text) {
this.isPressed = true;
await this.sprachAusgabe.textVorlesen(text + " ");
}
toggleAction() {
Logger.debugMessage("###TOGGLE TO" + this.isPressed);
this.isPressed = !this.isPressed;
if (this.isPressed) {
const texte = this.getTexte();
texte.forEach(async (text) => {
this.textVorlesen(text);
});
}
else {
this.sprachAusgabe.cancel();
}
}
onClick() {
this.toggleAction();
}
onKeyDown(ev) {
if (ev.key === 'Enter' || ev.key === ' ') {
ev.preventDefault();
this.toggleAction();
}
}
render() {
Logger.debugMessage('##RENDER##');
return (h(Host, { title: this.getTitleText(), alt: this.getAltText(), role: "button", tabindex: this.taborder, "aria-pressed": this.isPressed ? "true" : "false" }, this.isPressed ? (h("svg", { id: this.ident + "-svg", xmlns: "http://www.w3.org/2000/svg", width: this.iconwidth, height: this.iconheight, role: "img", "aria-label": this.getAltText(), class: "speakerimage", viewBox: "0 0 75 75" }, h("path", { "stroke-width": "5", "stroke-linejoin": "round", d: "M39.389,13.769 L22.235,28.606 L6,28.606 L6,47.699 L21.989,47.699 L39.389,62.75 L39.389,13.769z" }), h("path", { id: "air", stroke: "var(--honey-speaker-color,black);", fill: "none", "stroke-width": "5", "stroke-linecap": "round", d: "M48,27.6a19.5,19.5 0 0 1 0,21.4M55.1,20.5a30,30 0 0 1 0,35.6M61.6,14a38.8,38.8 0 0 1 0,48.6" }, h("animate", { id: "airanimation", attributeType: "CSS", attributeName: "opacity", from: "1", to: "0", dur: "1s", repeatCount: "indefinite" })))) : (h("svg", { id: this.ident + "-svg", xmlns: "http://www.w3.org/2000/svg", width: this.iconwidth, height: this.iconheight, role: "img", "aria-label": this.getAltText(), class: "speakerimage", viewBox: "0 0 75 75" }, h("path", { "stroke-width": "5", "stroke-linejoin": "round", d: "M39.389,13.769 L22.235,28.606 L6,28.606 L6,47.699 L21.989,47.699 L39.389,62.75 L39.389,13.769z" }), this.pure ? (h("text", { id: "eins", x: "60%", y: "55%" }, "OFF")) : (h("path", { id: "air", stroke: "var(--honey-speaker-color,black);", fill: "none", "stroke-width": "5", "stroke-linecap": "round", d: "M48,27.6a19.5,19.5 0 0 1 0,21.4M55.1,20.5a30,30 0 0 1 0,35.6M61.6,14a38.8,38.8 0 0 1 0,48.6" }))))));
}
static get assetsDirs() { return ["assets"]; }
get hostElement() { return this; }
static get style() { return honeySpeechCss; }
};
const HoneySpeech$1 = /*@__PURE__*/proxyCustomElement(HoneySpeech, [1,"honey-speech",{"pure":[4],"textids":[1],"verbose":[4],"iconwidth":[1],"iconheight":[1],"audiolang":[1],"audiopitch":[2],"audiorate":[2],"audiovolume":[2],"voicename":[1],"isPressed":[32]},[[2,"click","onClick"],[2,"keydown","onKeyDown"]]]);
const defineCustomElements = (opts) => {
if (typeof customElements !== 'undefined') {
[
HoneySpeech$1
].forEach(cmp => {
if (!customElements.get(cmp.is)) {
customElements.define(cmp.is, cmp, opts);
}
});
}
};
export { HoneySpeech$1 as HoneySpeech, defineCustomElements };