import { AudioPlayerStatus, AudioResource, createAudioPlayer, VoiceConnection } from "@discordjs/voice"; import { Voice } from "../db/generated/prisma/enums"; import TTSTypecastModel from "../tts/typecast"; import TTSPapagoModel from "../tts/papago"; import { Guild } from "discord.js"; import { getOrCreateVoiceConnection } from "./util"; import TTSModelBase from "../tts"; import { DiscordUserProfile } from "../db/generated/prisma/client"; import { nyaize } from "../utils/nyaize"; import { OutputHandler } from "../utils/outputHandler"; export async function createVoiceBuffer(voice: Voice, text: string): Promise { if (voice == "TypeCast") { const content = TTSTypecastModel.instance.ttsify(text); if (!content.length) throw new Error("Empty content"); return await TTSTypecastModel.instance.getMemcachedVoice( TTSTypecastModel.instance.createRequestId(content) ); } else if (voice == "Papago") { const content = TTSTypecastModel.instance.ttsify(text); if (!content.length) throw new Error("Empty content"); return await TTSPapagoModel.instance.getMemcachedVoice( TTSPapagoModel.instance.createRequestId(content) ); } else { throw new Error(`Unknown voice type: ${voice}`); } } class VoiceQueue { private connection: VoiceConnection; private list: AudioResource[]; constructor(connection: VoiceConnection) { this.connection = connection; this.list = []; } public static fromConnection(connection: VoiceConnection): VoiceQueue { return (connection as any).queue ??= new VoiceQueue(connection); } private play() { if (!this.list[0]) return; const player = createAudioPlayer(); this.connection.subscribe(player); player.once(AudioPlayerStatus.Idle, this.next.bind(this)); player.play(this.list[0]); } public enqueue(resource: AudioResource) { this.list.push(resource); if (this.list.length == 1) { this.play(); return; } } public next() { this.list.shift(); this.play(); } } export async function playVoice(guild: Guild, profile: DiscordUserProfile, text: string) { if (profile.nya) text = nyaize(text); try { let connection = await getOrCreateVoiceConnection(guild); if (!connection) throw new Error("Yaeju is not joined VoiceChat"); let voiceBuffer: Buffer; if (profile.voice == "TypeCast") { if (profile.canTypecast) { voiceBuffer = await createVoiceBuffer(profile.voice, text); } else { throw new Error(`the user ${profile.userId} is can't use typecast voice`); } } else { voiceBuffer = await createVoiceBuffer(profile.voice, text); } VoiceQueue.fromConnection(connection).enqueue( TTSModelBase.bufferToAudioResource(voiceBuffer) ); } catch(err) { OutputHandler.errorLog("[PlayVoice Error]", err); throw new Error(err as any); } }