Node.js 디스코드 음악봇 - node.js diseukodeu eum-agbos

discord-musicbot

discord.js v14로 만든 디스코드 음악봇입니다.

유튜브 검색 API를 사용하여 검색을 진행합니다.

discord.js v14로 업그레이드와 queue 구현을 완료했습니다.

설치 & 실행

npm i

create .env file

nodemon

.env

DISCORD_TOKEN=(Discord Bot Token)
CLIENT_ID=(Discord Bot ClientId)
GUILD_ID=(Your GuildId)
YOUTUBE_API=(Youtube API Key)

사용법

/help

사용 가능한 명령어들을 출력합니다.

/play

Youtube Data API v3을 사용하여 키워드를 검색한후 가장 첫번째로 나오는 영상을 재생합니다.

queue가 없는경우 자동으로 생성하고 다른음악이 재생중이라면 queue에 넣습니다.

/skip

재생중인 음악을 건너뛰기 합니다.

queue에서 가장 첫번째(재생중인 음악)를 없애고 다음 음악을 재생합니다.

/stop

음악재생을 중지하고 해당 서버에 대한 queue를 삭제합니다.

queue는 play 명령어 입력시 다시 생성됩니다.

/q

지금 재생중인 음악의 정보를 담은 Embed를 출력합니다.

/pause

음악재생을 일시중지합니다.

/unpause

일시중지를 해제합니다.

- 이 강좌는 Node.js와 npm이 컴퓨터에 깔려있다는 전제 하에 작성되었습니다.

전에 썼던 디스코드 챗봇 만들기에 이어서 이번에는 자바스크립트를 이용해 음성을 출력할수 있는 봇을 만들어보려 합니다. discord.js의 사용법을 모르는 분들은 여기를 먼저 읽으시면 됩니다.

모듈 설치하기

음성 기능을 이용하기 위해서는 음성관련 처리를 해주는 새로운 모듈이 필요한데요, node-opus 입니다. node-opus 말고 opusscript라는 모듈을 대신 사용할 수 있지만, 처리 효율성으로 봤을때 node-opus가 훨씬 좋습니다.

Node.js 디스코드 음악봇 - node.js diseukodeu eum-agbos

package.json의 dependencies에 추가한 뒤 cmd를 켜서 npm install이라고 명령하거나, npm install node-opus를 쳐 주시면 됩니다. 다만 이 모듈의 경우에는 c로 작성되어 있어서 node-gyp 모듈이 필요합니다.

npm install node-opus

설치할때 화면에 로그가 엄청나게 많이 표시될겁니다. 그게 정상이에요.

음성봇 만들기

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

const Discord = require("discord.js");

const client = new Discord.Client();

client.on('message', message => {

//(개인 1:1 채팅인 경우 보이스채널개념이 없음) => 제외

if (!message.guild) return;

if (message.content === "/재생") {

if (message.member.voiceChannel) {

message.member.voiceChannel.join()

.then(connection => {

message.reply("재생한다!");

connection.playFile("파일명.mp3");

})

.catch(console.log);

else {

message.reply("널 따라갈건데 너가 보이스채널에 없어.");

}

}

});

client.login("비밀키");

cs

음성봇도 사용은 단순합니다. 먼저 1:1 채팅인 경우에는 채널이라는 개념이 없기 때문에 특정 채널에 들어가는것이 불가능합니다. 그러므로 개인채팅에서는 사용할 수 없게 return을 합니다.

만약에 개인채팅이 아니라면 /재생 이라고 입력했는지 비교하고, 입력했다면 메시지를 보낸 사람이 보이스채널에 들어가있는지 체크합니다. 만약 들어가있다면 봇은 그 보이스채널에 join()을 해서 들어갑니다. 그리고 보이스채널에 성공적으로 연결되면 특정 파일을 재생합니다.

물론 코드가 있는 폴더에 mp3 파일이 있어야 됩니다.

이제 [node 파일명] 을 해서 실행하세요.

유저가 먼저 보이스채널에 들어간뒤, /재생 을 치면 재생이 됩니다. 지금은 이렇게 단순하지만, discord.js에서 이용할 수 있는 보이스 기능은 이것보다 더 방대합니다. 다른 모듈, 스트림과 함께 사용하면 youtube 영상을 플레이할수도 있습니다. 이런 추가적인 기능들은 나중에 써보도록 하겠습니다.

그럼 전 이만.

// Extract the required classes from the discord.js module

const { Client, Attachment } = require('discord.js');

// Create an instance of a Discord client

const client = new Client();

client.on('ready', () => {

console.log(`Logged in as ${client.user.tag}!`);

client.user.setActivity('봇 만들자', { type: 'WATCHING' })

});

client.on('message', msg => {

if (msg.content.startsWith('r.help')) {

msg.reply('Powered by node.js\nMade by M4ndU');

}

if (msg.content.startsWith('r.gif')) {

const args = msg.content.split(' ').slice(1); // All arguments behind the command name with the prefix

var no = args.join(' '); // Amount of messages which should be deleted

if (!no) no = '1';

if (isNaN(no) || no > 14return msg.reply('only number 1-14');

// Create the attachment using Attachment

var path = "./gif/";

path = path.concat(no,".gif");

console.log(path);

const attachment = new Attachment(path);

// Send the attachment in the message channel with a content

msg.channel.send(attachment);

}

if (msg.content === 'r.play') {

// Only try to join the sender's voice channel if they are in one themselves

if (msg.member.voiceChannel) {

msg.member.voiceChannel.join()

.then(connection => { // Connection is an instance of VoiceConnection

msg.reply('playing music!');

const dispatcher = connection.playFile('./music.mp3');

dispatcher.on("end", end => {});

})

.catch(console.log);

else {

msg.reply('먼저 방에 들어가');

}

}

if (msg.content === 'r.leave') {

// Only try to join the sender's voice channel if they are in one themselves

if (msg.member.voiceChannel) {

msg.member.voiceChannel.leave();

msg.reply('bye!');

else {

msg.reply('이미 나왔는데..');

}

}

if (msg.content.toLowerCase().startsWith("r.clear")) {

const args = msg.content.split(' ').slice(1); // All arguments behind the command name with the prefix

const amount = args.join(' '); // Amount of messages which should be deleted

if (!amount) return msg.reply('You haven\'t given an amount of messages which should be deleted!'); // Checks if the `amount` parameter is given

if (isNaN(amount)) return msg.reply('The amount parameter isn`t a number!'); // Checks if the `amount` parameter is a number. If not, the command throws an error

if (amount > 10return msg.reply('You can`t delete more than 10 messages at once!'); // Checks if the `amount` integer is bigger than 100

if (amount < 1return msg.reply('You have to delete at least 1 message!'); // Checks if the `amount` integer is smaller than 1

msg.channel.fetchMessages({ limit: amount }).then(dmsg => { // Fetches the messages

msg.channel.bulkDelete(dmsg // Bulk deletes all messages that have been fetched and are not older than 14 days (due to the Discord API)

).catch(console.log);});

}

if (msg.content === 'r.whoami') {

// Send the user's avatar URL

msg.reply(msg.author.avatarURL);

}

});

client.login('token');