yaejunyang/packages/bot/tts.ts
2026-02-10 10:09:25 +00:00

92 lines
3.1 KiB
TypeScript

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<Buffer> {
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);
}
}