Discord bot with Javascript(node.js)
가끔 지인들이랑 디스코드로 게임을 하는데 사람이 너무 많으면 편가르기를 하는데
그때마다 지인들은 네이버 사다리를 이용하고 이를 스트리밍해서 정보를 공유한다
근데 나는 엄청난 귀차니즘의 소유자라 사실 스트리밍에 들어가는 것을 보는 것 조차 귀찮다
그래서 디스코드 봇 중에서 팀나누기 봇이 있는지 검색해보는 과정에서 한글화된 봇이 없다는 점과 디스코드를 구축한 언어 중 하나가 Javascript라는 얘기를 들어본적이 있어서
이참에 한글화 된 봇을 만들어보면 어떨까해서 이렇게 글을 쓴다
먼저 이번 글에서는 기본적인 디스코드 봇의 개념과 디스코드 API를 어떻게 활용할 수 있는지 등에 대해서 알아보기 위해 일단 유튜브 강의를 통해 기본적인 튜토리얼을 해보자
먼저 Discord documentation에 접속해서 오른쪽 상단의 New Application
을 클릭해보자
그러면 봇의 이름을 정하라고 할텐데 강의 내용대로 나는 Encourage Bot
이라고 하겠다
생성을 하고 나면 왼쪽에서Bot
탭을 클릭한 후 Add Bot
을 클릭해서 봇을 추가하도록 하자
Authorization Flow
에서OAuth2(Open Authentication 2)
란 페이스북, 카카오 등에서 제공하는 인증을 위한 표준 프로토콜이다
우리는 공개 봇으로 되있는 기본설정을 유지한 채로 진행하도록 하자
TOKEN
이 있는데 이 TOKEN
이 내 봇의 비밀번호가 될 것이다
이 TOKEN
을 통해 내가 만든 디스코드 봇, 내 서버에 접속할 수 있기때문에 타인에게 공개하지 말도록 하자
만약 실수로 어딘가에 공개했다면
Regenerate
를 눌러 새로 발급받기로 하자
이제 서버에 봇을 불러오기 위해 왼쪽에서 Oauth2
탭을 눌러 SCOPES
에서 bot
을 체크해주고 BOT PERMISSIONS
에서 원하는 권한을 선택해주자
나는 강의대로 TEXT PERMISSIONS
에서 Send TTS Messages
를 제외한 모든 것을 선택해주고 GENERAL PERMISSIONS
에서 View Channels
를 선택해주겠다
원하는 권한을 다 선택했다면 SCOPES
가장 하단에 있는 주소를 Copy
버튼을 눌러 복사하도록 하자
이 복사된 주소로 접속하게 되면
위와 같은 화면이 나올텐데 ADD TO SERVER:
에서 원하는 서버를 선택한 후 계속하기
를 눌러주고 아까 PERMISSIONS
에서 선택했던 권한들을 그대로 둔 채 승인
버튼을 눌러 이 봇을 실제 디스코드 서버에 추가해주도록 하자
이제 코딩을 해볼텐데 코딩에 앞서서 나는 이번 프로젝트에서 repl.it을 사용하길 추천한다
repl.it
은 설치없이 IDE환경을 구축해주며 각종 언어들도 설치없이 쉽게 사용이 가능하다
그리고 local server
를 이용하면 내 컴퓨터를 계속 켜줘야되는데 repl.it
을 통해 내가 컴퓨터를 종료해도 디스코드 봇은 계속 실행되도록 서버를 구축할 수 있기 때문이다
repl.it
에 대한 사용법을 모르는 분들은 간단히 찾아보길 바란다
우리는 javascript
를 이용해서 디스코드 봇을 만들 것이기 때문에 new repl
을 클릭하고 언어는 node.js
를 선택, 이름은 자신이 원하는 이름을 지어주면 된다
먼저 우리는 index.js
라는 파일에 디스코드 라이브러리를 추가하도록 하자
const Discord = require('discord.js');
로컬환경이었다면 직접 라이브러리를 설치한 후 불러와야했겠지만 repl.it
은 Run
버튼을 누르면 설치되지 않은 라이브러리들이 자동으로 설치를 해준다는 점이 매력적이다
가끔 에러가 발생하면 Shell
탭에 들어가서 직접 설치를 하는 방법으로 해결해주면 된다
메세지에 응답하는 아주 간단한 봇을 구축해보면서 디스코드 봇의 구조를 살펴보자
먼저 repl.it
에서 제공하는 .env
즉 환경변수를 사용하는데
왼쪽 탭에서 자물쇠 모양의 secret
을 선택한 후 key
, value
를 설정해주면 된다
const Discord = require('discord.js');
const client = new Discord.Client(); // discord 서버와 연결
const TOKEN = process.env['TOKEN'] // repl.it에서 제공하는 .env 변수 사용
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`)
});
client.on('message', msg => {
if (msg.content === `hello`) {
msg.reply(`hello ! my name is ${client.user.tag}!`)
}
});
client.login(TOKEN)
위와 같이 작성한 후 Run
을 누르면
정상적으로 코드가 작동된 것을 볼 수 있고
디스코드 상에서도 봇이 온라인 상태가 된 것을 알 수 있다
위에서 메세지가 만약 hello
라면 대답을 하기로 되어있으므로 다른 메세지에는 대답을 하지 않다가 hello
에 지정된 답변을 해주는 모습이다
이제 https://zenquotes.io/api
를 통해 명언을 return
해주는 함수를 만들어 이를 봇이 답변해주도록 해보자
const Discord = require('discord.js');
const client = new Discord.Client(); // discord 서버와 연결
const TOKEN = process.env['TOKEN'] // repl.it에서 제공하는 .env 변수 사용
const fetch = require('node-fetch');
function getQuote() {
return fetch('https://zenquotes.io/api/random')
.then(res => {
return res.json();
})
.then(data => {
return data[0]['q'] + ' -' + data[0]['a']; // q = quote, a = author
})
}
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`)
});
client.on('message', msg => {
if (msg.author.bot) return;
if (msg.content === '$inspire') {
getQuote().then(quote => msg.channel.send(quote))
}
});
client.login(TOKEN)
Run
버튼으로 실행하고 디스코드 서버로가서 채팅을 하게되면 위와 같이 대답을 해준다
비동기 호출에 관해 개념적으로 어려운 부분 혹은 이해가 안되는 부분이 있다면 최하단
reference
을 참고하도록 하자
이제 우리는 지정된 단어에 대한 지정된 대답을 할 수 있는 기능을 넣어보도록 하겠다
강의에서는 encourage bot
이라는 이름처럼 격려해주는 봇을 만들어보도록 하자
const Discord = require('discord.js');
const client = new Discord.Client(); // discord 서버와 연결
const TOKEN = process.env['TOKEN'] // repl.it에서 제공하는 .env 변수 사용
const fetch = require('node-fetch');
const sadWords = ['sad', 'depressed', 'unhappy', 'angry'];
const encouragements = [
'Cheer up !',
'Hang in there',
'You are a great person !'
];
function getQuote() {
return fetch('https://zenquotes.io/api/random')
.then(res => {
return res.json();
})
.then(data => {
return data[0]['q'] + ' -' + data[0]['a']; // q = quote, a = author, zenquotes api의 문법
})
}
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`)
});
client.on('message', msg => {
if (msg.author.bot) return; // 채팅한 사람이 봇일 경우 대답하지 않음
if (msg.content === '$inspire') {
getQuote().then(quote => msg.channel.send(quote))
}
// sadWords안에 있는 곳을 살펴 본 후 msg에 word가 포함되어 있으면 실행
if (sadWords.some(word => msg.content.includes(word))) {
const RANDOM_NUM = Math.floor(Math.random() * encouragements.length);
const encouragement = encouragements[RANDOM_NUM];
msg.reply(encouragement);
}
});
client.login(TOKEN)
지정된 단어가 포함된 문장을 입력하면 위와 같이 정해진 선택지에서 랜덤하게 대답을 해준다
왼쪽에서 database
탭을 눌러서 Import the database
아래 insert
버튼을 눌러서 database
를 불러오자
그 후 그 database
에 우리의 encouragements
배열을 기본값으로 설정하고 추가, 삭제할 수 있는 기능을 넣어보자
const Discord = require('discord.js');
const fetch = require('node-fetch');
const Database = require("@replit/database");
const client = new Discord.Client(); // discord 서버와 연결
const db = new Database();
const TOKEN = process.env['TOKEN'] // repl.it에서 제공하는 .env 변수 사용
const sadWords = ['sad', 'depressed', 'unhappy', 'angry'];
const defaultEncouragements = [
'Cheer up !',
'Hang in there',
'You are a great person !'
];
//database에 encouragements(key)로 value를 불러옴
// 만약 NULL or length가 0이면 defaultEncouragements를 encouragements의 value로 설정
db.get('encouragements').then(encouragements => {
// 처음은 NULL이지만 나중엔 length가 0일수도 있기 때문에
if (!encouragements || encouragements.length < 1) {
db.set('encouragements', defaultEncouragements)
}
});
function updateEncouragements(encouragingMessage) {
db.get('encouragements').then(encouragements => {
encouragements.push([encouragingMessage]);
db.set('encouragements', encouragements);
});
};
function deleteEncouragement(index) {
db.get('encouragements').then(encouragements => {
if (encouragements.length > index) {
encouragements.slice(index, 1);
db.set('encouragements', encouragements);
}
});
}
function getQuote() {
return fetch('https://zenquotes.io/api/random')
.then(res => {
return res.json();
})
.then(data => {
return data[0]['q'] + ' -' + data[0]['a']; // q = quote, a = author, zenquotes api의 문법
})
};
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`)
});
client.on('message', msg => {
if (msg.author.bot) return; // 채팅한 사람이 봇일 경우 대답하지 않음
if (msg.content === '$inspire') {
getQuote().then(quote => msg.channel.send(quote))
}
// sadWords안에 있는 곳을 살펴 본 후 msg에 word가 포함되어 있으면 실행
if (sadWords.some(word => msg.content.includes(word))) {
db.get('encouragements').then(encouragements=> {
const encouragement = encouragements[Math.floor(Math.random() * encouragements.length)];
msg.reply(encouragement);
})
}
if (msg.content.startsWith('$new')) {
encouragingMessage = msg.content.split('$new')[1]; //'$new'가 0번째 element가 됨
updateEncouragements(encouragingMessage);
msg.channel.send('New encouraging message added.');
}
if (msg.content.startsWith('$del')) {
index = parseInt(msg.content.split('$del')[1]);
deleteEncouragement(index);
msg.channel.send('encouraging message deleted.');
}
});
client.login(TOKEN);
위와 같이 이제 $new
와 $del
명령어를 추가하여 사용할 수 있게 되었다
이제 봇의 on/off를 ture
, false
로 키고 끌 수 있게끔 하는 명령어와 encouragements
안에 있는 encouragingMessage
의 list를 출력하는 명령어를 추가해보도록 하자
const Discord = require('discord.js');
const fetch = require('node-fetch');
const Database = require("@replit/database");
const client = new Discord.Client(); // discord 서버와 연결
const db = new Database();
const TOKEN = process.env['TOKEN'] // repl.it에서 제공하는 .env 변수 사용
const sadWords = ['sad', 'depressed', 'unhappy', 'angry'];
const defaultEncouragements = [
'Cheer up !',
'Hang in there',
'You are a great person !'
];
//database에 encouragements(key)로 value를 불러옴
// 만약 NULL or length가 0이면 defaultEncouragements를 encouragements의 value로 설정
db.get('encouragements').then(encouragements => {
// 처음은 NULL이지만 나중엔 length가 0일수도 있기 때문에
if (!encouragements || encouragements.length < 1) {
db.set('encouragements', defaultEncouragements)
}
});
db.get('responding').then(value => {
if (value == null) {
db.set('responding', true);
}
})
function updateEncouragements(encouragingMessage) {
db.get('encouragements').then(encouragements => {
encouragements.push([encouragingMessage]);
db.set('encouragements', encouragements);
});
};
function deleteEncouragement(index) {
db.get('encouragements').then(encouragements => {
if (encouragements.length > index) {
encouragements.slice(index, 1);
db.set('encouragements', encouragements);
}
});
}
function getQuote() {
return fetch('https://zenquotes.io/api/random')
.then(res => {
return res.json();
})
.then(data => {
// q = quote, a = author, zenquotes api의 문법
return data[0]['q'] + ' -' + data[0]['a'];
})
};
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`)
});
client.on('message', msg => {
if (msg.author.bot) return; // 채팅한 사람이 봇일 경우 대답하지 않음
if (msg.content === '$inspire') {
getQuote().then(quote => msg.channel.send(quote))
}
db.get('responding').then(responding => {
// responding의 value가 true일 경우만 반응해줌
// sadWords안에 있는 곳을 살펴 본 후 msg에 word가 포함되어 있으면 실행
if (responding && sadWords.some(word => msg.content.includes(word))) {
db.get('encouragements').then(encouragements=> {
const encouragement = encouragements[Math.floor(Math.random() * encouragements.length)];
msg.reply(encouragement);
});
}
})
if (msg.content.startsWith('$new')) {
encouragingMessage = msg.content.split('$new')[1]; //'$new'가 0번째 element가 됨
updateEncouragements(encouragingMessage);
msg.channel.send('New encouraging message added.');
}
if (msg.content.startsWith('$del')) {
index = parseInt(msg.content.split('$del')[1]);
deleteEncouragement(index);
msg.channel.send('encouraging message deleted.');
}
if (msg.content.startsWith('$list')) {
db.get('encouragements').then(encouragements => {
msg.channel.send(encouragements);
});
}
if (msg.content.startsWith('$responding')) {
value = msg.content.split('$responding')[1];
if (value.toLowerCase() == true) {
db.set('responding', true);
msg.channel.send('responding is on.')
} else {
db.set('responding', false);
msg.channel.send('responding is off.')
}
}
});
client.login(TOKEN);
이제 $list
와 $responding
도 등록하여 정상적으로 작동할 것이다
남은건 내가 repl.it
을 종료하여도 background
상에서 이 봇이 계속 실행되도록 해주기만 하면 된다
첫번째는 왼쪽 상단에 보면 본인의 프로젝트 명이 보일텐데(내 경우는 Encourage Bot JS
) 그걸 클릭하면 위와 같이 보일텐데 Upgrade to Hacker
를 눌러 유료플랜을 사서 아래 Always On
을 켜서 background
에서도 활성화를 시키는 방법이다
두번째는 uptime robot을 사용하는 방법인데 일단 server.js
라는 파일을 만들어 준 후
const express = require('express');
const server = express();
// '/'으로 지정하여 루트 도메인에서 모든 http 요청에 응답
server.all('/', (req, res) -> {
res.send('Bot is running !')
});
function keepAlive() {
server.listen(3000, () => {
console.log('Server is ready.')
});
}
module.exports = keepAlive;
위와 같이 작성해 준 후 다시 index.js
(봇을 구현한 js file)의 상단에
const keepAlive = require('./server');
를 추가해 주고 클라이언트가 로그인 하기 전에 이 모듈을 실행시켜 준다
keepAlive();
client.login(TOKEN); //최하단에 있던 클라이언트 로그인 코드
위와 같이 작성한 후 Run
을 누르면
봇이 실행중인 것을 확인할 수 있다
여기까지 정상적으로 따라왔다면 Uptime robot에 가입 후 로그인하고 왼쪽 상단의 Add New Monitor
를 눌러서 아래와 같이 설정해주면 된다
참고로 URL
은 본인의 repl.it
에서 방금 server를 구현 후 Run
을 눌렀을 때 나타났던 웹페이지의 URL
을 입력하면 된다
Friendly Name
을 바꾸고싶다면 본인이 원하는 것으로 설정하면 된다
이제 우리의 컴퓨터가 꺼져있고 repl.it
을 꺼버려도 봇은 계속 실행되고 있을 것이다
여기까지가 내가 이 유튜브 강의를 보면서 배운 내용이고, 사실 나도 아직 javascript
에 대한 지식이 부족하기 때문에 누군가의 궁금증을 해결해주기에는 턱없이 부족할 것이라고 생각한다
하지만 누군가는 이 게시물을 통해 무언가 창작을 하는 것에 있어 기쁨을 얻을 수 있으면 좋겠다
reference
I. Youtube: Code a Discord Bot with JavaScript - Host for Free in the Cloud
II. Discord.js
III. 자바스크립트 비동기 처리와 콜백 함수
IV. Array.prototype.some()
V. Map.prototype.get()
VI. Web-APIs: Fetch
Author And Source
이 문제에 관하여(Discord bot with Javascript(node.js)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@zxcvbnm5288/Discord-bot-with-Javascript저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)