여느때와 같이 백수 생활을 즐기다가 클라이언트(친구)가 요즘 TTS봇은 예의가 없다고 한다.
뭔 소리인가 했더니 우리 서버는 TTS봇 사용하고 있는데 얘가 일정 시간 메세지가 올라오지 않으면 음성채널에서 나간다. 그런데 얘가 말도 없이 나간다고 나갈 땐 인사하고 나가야하지 않겠냐는 말이었다.
그런가?
그리하여 나갈 때 인사하고 나가는 TTS봇을 만들기로 했다
전체 소스코드는 하단 링크 참고
https://github.com/HYK-Nov/polite-tts-bot-js
지난 글과 같이 Discord.js를 사용했다.
그리고 Typescript로 코드 작성하였으나 Javascript랑 크게 다르진 않으니 보는데는 문제 없다.
일단 초반부는 위 글과 얼추 비슷하니 설정까지는 위에서 작성한 것과 동일하게 하면 된다.
npm install google-tts-api
추가로 google-tts를 설치해주자
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
],
});
client.login(BOT_TOKEN);
클라이언트를 설정해주자. TTS봇은 메세지를 읽어줘야하기 때문에 Message 기능을 넣어주어야 한다.
let voiceConnection: VoiceConnection;
const audioPlayer = createAudioPlayer();
let ttsTimeout: NodeJS.Timeout;
let disconnectTimeout: NodeJS.Timeout;
const closeTTSUrl = googleTTS.getAudioUrl('저는 이만 가볼게요', {lang: 'ko'});
const closeAudioResource = createAudioResource(closeTTSUrl);
위와 같이 작성해준다. 각각 무슨 역할인지는 아래 참고
voiceConnection
: 음성채널 연결 관련audioPlayer
: 오디오 재생 플레이어ttsTimeout
: 퇴장 인사 재생 타이밍disconnectTimeout
: 음성채널 연결 해제 타이밍closeTTSUrl
: TTS 음성 생성closeAudioResource
: audioPlayer
에 집어넣을 리소스 생성client.on('messageCreate', (msg) => {
if (msg.author.bot) return;
})
메세지를 수신해야하기 때문에 메세지가 새로 생길 때 이벤트를 만들어준다.
그리고 혹여나 다른 봇이 날린 메세지를 읽어주면 안되니 작성자가 봇이면 바로 이벤트를 끝내버린다
const ttsUrl = googleTTS.getAudioUrl(msg.content, {lang: 'ko', slow: false});
const audioResource = createAudioResource(ttsUrl);
Discord.js Voice 모듈은 놀랍게도 googleTTS로 만들어진 url을 그냥 집어넣으면 재생이 된다. url을 audioResource
에 집어넣어준다.
voiceConnection = joinVoiceChannel({
channelId: VOICE_CHANNEL_ID,
guildId: GUILD_ID,
adapterCreator: msg.guild?.voiceAdapterCreator!,
});
voiceConnection.subscribe(audioPlayer);
audioPlayer.play(audioResource);
voiceConnection
으로 음성채널에 들어가주고 audioPlayer
에 TTS음성을 재생시켜준다.
clearTimeout(ttsTimeout);
clearTimeout(disconnectTimeout);
ttsTimeout = setTimeout(() => audioPlayer.play(closeAudioResource), 12_000);
disconnectTimeout = setTimeout(() => voiceConnection.destroy(), 15_000);
마지막으로 음성채널에서 나갈 타이밍을 설정해준다.
위에서 미리 timeout을 만들어준 이유가 clearTimeout
을 하기 위함이었다. 만약 setTimeout
이 설정된 상태인데 새로운 메세지가 올라오면 timeout을 취소한다.
그리고 다시 timeout을 설정하고 일정 시간동안 메세지가 올라오지 않으면 미리 만들어두었던 퇴장 인사를 재생하고 나간다.