diff --git a/src/lib/handleAnivMessage.ts b/src/lib/handleAnivMessage.ts index 3ec2026..e09f2a3 100644 --- a/src/lib/handleAnivMessage.ts +++ b/src/lib/handleAnivMessage.ts @@ -4,6 +4,7 @@ import { sendMessage } from "lib/commandUtils"; import { redis } from "lib/redis"; import { timeout } from "lib/timeout"; import type User from "user"; +import { playTTS } from "web/alerts/serverFunctions"; const ANIVNAMES: anivBots[] = ["a_n_e_e_v", "a_n_i_v"]; @@ -43,6 +44,7 @@ export default async function handleMessage( user: User, ) { if (ANIVNAMES.map((a) => a.toLowerCase()).includes(user.username)) { + await playTTS({ text: msg.messageText }); const data: anivMessageStore = await redis .get("anivmessages") .then((a) => (a === null ? {} : JSON.parse(a))); diff --git a/src/web/alerts/TTSTypes.ts b/src/web/alerts/TTSTypes.ts new file mode 100644 index 0000000..40adba1 --- /dev/null +++ b/src/web/alerts/TTSTypes.ts @@ -0,0 +1,9 @@ +export type MSTTS = { + type: "microsoft"; + text: string; + voice: string; + pitch: string; + speed: string; +}; + +export type TTS = MSTTS; diff --git a/src/web/alerts/serverFunctions.ts b/src/web/alerts/serverFunctions.ts index 5c0e206..f6b8e6e 100644 --- a/src/web/alerts/serverFunctions.ts +++ b/src/web/alerts/serverFunctions.ts @@ -11,3 +11,29 @@ export async function playAlert(alert: alert) { alert, }); } + +type TTSOptions = { + text: string; + voice?: string; + pitch?: number; + speed?: number; +}; + +export async function playTTS(options: TTSOptions) { + await sendAlertEvent({ + function: "playTTS", + tts: { + type: "microsoft", + voice: options.voice ?? "Sam", + pitch: options.pitch ? options.pitch.toString() : "100", + speed: options.speed ? options.speed.toString() : "150", + text: options.text, + }, + }); +} + +export async function stopTTS() { + await sendAlertEvent({ + function: "cancelTTS", + }); +} diff --git a/src/web/alerts/types.ts b/src/web/alerts/types.ts index 17c0719..68058e3 100644 --- a/src/web/alerts/types.ts +++ b/src/web/alerts/types.ts @@ -1,4 +1,5 @@ import type { serverNotificationEvent } from "web/serverTypes"; +import type { TTS } from "./TTSTypes"; type alertBase = { name: name; @@ -51,4 +52,17 @@ type playAlertEvent = { alert: alert; }; -export type alertEventData = playAlertEvent | serverNotificationEvent; +type playTTS = { + function: "playTTS"; + tts: TTS; +}; + +type cancelTTS = { + function: "cancelTTS"; +}; + +export type alertEventData = + | playAlertEvent + | playTTS + | cancelTTS + | serverNotificationEvent; diff --git a/src/web/alerts/www/src/alertManager.ts b/src/web/alerts/www/src/AlertManager.ts similarity index 100% rename from src/web/alerts/www/src/alertManager.ts rename to src/web/alerts/www/src/AlertManager.ts diff --git a/src/web/alerts/www/src/TTSManager.ts b/src/web/alerts/www/src/TTSManager.ts new file mode 100644 index 0000000..e3bed8f --- /dev/null +++ b/src/web/alerts/www/src/TTSManager.ts @@ -0,0 +1,52 @@ +import type { TTS } from "web/alerts/TTSTypes"; + +class TTSManager { + private busy: boolean; + private ttsQueue: TTS[]; + private audio: HTMLAudioElement; + + constructor() { + this.busy = false; + this.ttsQueue = []; + this.audio = new Audio(); + document.body.appendChild(this.audio); + } + + private async playAudio(url: string) { + return new Promise((res) => { + this.audio.src = url; + this.audio.load(); + this.audio.play(); + this.audio.onended = res; + this.audio.onpause = res; + }); + } + + private async playTTS(tts: TTS) { + this.busy = true; + switch (tts.type) { + case "microsoft": + await this.playAudio( + `https://tetyys.com/SAPI4/SAPI4?text=${tts.text}&voice=${tts.voice}&pitch=${tts.pitch}&speed=${tts.speed}`, + ); + break; + } + + const newTTS = this.ttsQueue.shift(); + if (!newTTS) { + this.busy = false; + return; + } else this.playTTS(newTTS); + } + + public queueTTS(input: TTS) { + if (this.busy) this.ttsQueue.push(input); + else this.playTTS(input); + } + + public endTTS() { + this.audio.pause(); + } +} + +export default new TTSManager(); diff --git a/src/web/alerts/www/src/main.ts b/src/web/alerts/www/src/main.ts index 970d189..c2bf2d4 100644 --- a/src/web/alerts/www/src/main.ts +++ b/src/web/alerts/www/src/main.ts @@ -1,7 +1,8 @@ import type { alertEventData } from "web/alerts/types"; import type { serverInstruction } from "web/serverTypes"; -import alertManager from "./alertManager"; +import AlertManager from "./AlertManager"; import "@fontsource/jersey-15"; +import TTSManager from "./TTSManager"; const wsAddress = `ws${location.protocol === "https:" ? "s" : ""}://${location.host}`; @@ -19,7 +20,13 @@ socket.onmessage = (event) => { const data: alertEventData = JSON.parse(event.data); switch (data.function) { case "playAlert": - alertManager.queueAlert(data.alert); + AlertManager.queueAlert(data.alert); + break; + case "playTTS": + TTSManager.queueTTS(data.tts); + break; + case "cancelTTS": + TTSManager.endTTS(); break; case "serverNotification": console.log(data.message);