NosferatuVN
Junior Member
Chắc chẳng ai còn lạ gì Discord nữa nhỉ, ngoài dùng để giao tiếp, Discord còn cho phép người dùng tạo những con bot rất thú vị nhờ API của mình. Mình mới vọc vạch được ít lâu nên mạo muội chia sẻ cách tạo một con bot phát nhạc từ Youtube đơn giản cho người mới bắt đầu, ai cao thủ rồi thì bỏ qua nhé <(")
1. Tạo bot:
Để tạo một bot, đầu tiên vào trang Discord Developers, đăng nhập, chọn New Application và nhập tên mà bạn muốn (đây không phải tên bot):
Chọn Bot -> Add Bot -> Sửa tên, avatar của bot theo ý, và copy cái Token này (quan trọng):
Vậy là xong bước tạo bot, muốn bot vào kênh của mình thì bạn lên mục OAuth2 -> tích vào bot -> copy link dán vào trình duyệt:
2. Cài những công cụ cần thiết:
Trong bài viết này mình sẽ dùng thư viện Discord.JS để tương tác với API của Discord. Discord.JS là 1 module NodeJS nên nếu chưa cài NodeJS thì hãy lên trang chủ để tải nhé : nodejs.org
Sau khi cài xong NodeJS, cài các thư viện cần thiết, để phát được nhạc từ youtube thì ngoài Discord.JS bot cần opusscript hoặc @discordjs/opus, ffmpeg và ytdl (hoặc bất cứ thằng nào tương tự).
Trước tiên là tạo file index.js (hoặc abc.js hay bất cứ tên gì bạn muốn) ở thư mục bạn muốn đặt mã nguồn (source code) của bot, có thể tạo thêm file config.json để lưu những giá trị quan trọng nếu muốn. Để coding thì bạn dùng bất cứ phần mềm text editor nào cũng được (notepad, notepad++,...), trong bài viết này mình dùng Sublime Text 3.
Mở Command Prompt (cmd) ở thư mục chứa file index.js tạo ở trên, gõ:
Sau khi cài xong chúng ta sẽ tiến hành coding.
3. Coding:
Mở file index.js mà bạn vừa tạo ở trên, nhập các module vào:
Đăng nhập để bot online:
Trong bài hướng dẫn này chúng ta chỉ sử dụng 2 event là ready (khi bot đăng nhập thành công) và message (khi có tin nhắn mới được gửi), ngoài ra còn rất nhiều event hay ho khác bạn có thể đọc trong tài liệu của DiscordJS.
Đầu tiên là event ready:
Đoạn code đầu tiên sẽ giống như thế này:
Thử mở cmd ở thư mục chứa file index.js gõ: node index.js
Nếu màn hình cmd in ra chữ Ready nghĩa là bạn đã thành công bước đầu.
Tiếp theo là event message (khi có tin nhắn mới được gửi trong các kênh mà bot tham gia):
Ctrl + C trong cmd và node index.js lại, thử chat trong kênh là ping, nếu bot trả lời Pong! nghĩa là code hoạt động tốt, đến lúc bắt tay vào code phần phát nhạc.
Mình sẽ lập constructor cho 2 đối tượng Queue và Song và tạo một đối tượng queues sẵn để tiện cho việc sử dụng:
Hàm Map() sẽ tạo 1 đối tượng chứa các cặp key-value. Mục đích của việc này là bot có thể phát nhạc ở nhiều máy chủ khác nhau. Mỗi máy chủ chỉ phát được ở 1 channel 1 lúc nên key sẽ là ID của máy chủ, value là cái Queue chứa thông tin (kênh phát, luồng phát, bài hát, âm lượng,...).
Giờ chúng ta code để bot biết khi người dùng gửi lệnh phát. Trong sự kiện message ở trên, thêm code vào như sau (mình sẽ giải thích ở từng dòng cho tiện). Tạm thời mình chỉ hướng dẫn cách đơn giản là phát nhạc khi nhập chính xác url của video. Bạn nào muốn nâng cao hơn (tìm kiếm bài hát) thì tham khảo Youtube API.
Hàm playSong, thực ra chỗ ytdl chỉ cần ytdl(song.url) là đủ, nhưng đôi khi bị lỗi chưa phát hết bài đã ngừng vì vậy phải thêm option highWaterMark: 1<<25, mấy cái còn lại không quan trọng lắm.
Code sẽ như thế này:
Về cơ bản thì bot đã phát nhạc tốt, nhưng cần thêm vài chức năng như stop, pause, resume, skip, set volume để hoàn chỉnh hơn:
Chức năng stop:
Chức năng skip, về cơ bản thì tương tự stop, chỉ khác cái là không xóa danh sách phát:
DiscordJS cung cấp sẵn các chức năng pause, resume, setVolume...
Muốn lặp lại bài đang phát thì chỉ cần đặt Queue.repeat = true và ngược lại là được, vì ở trong hàm playMusic nếu repeat = true thì sẽ không xóa phần tử (bài hát đầu tiên), vì vậy nó sẽ lặp lại mãi đến khi người dùng tắt thì thôi.
Lấy danh sách phát:
Vậy là chúng ta đã tạo xong một con bot Discord với chức năng phát nhạc đơn giản, đây cũng là lần đầu mình viết hướng dẫn (mới học JS vài tháng) nên nếu có sai sót gì mong mn thông cảm nhé.
Mọi người có thể xem source code tại: Github
1. Tạo bot:
Để tạo một bot, đầu tiên vào trang Discord Developers, đăng nhập, chọn New Application và nhập tên mà bạn muốn (đây không phải tên bot):
Chọn Bot -> Add Bot -> Sửa tên, avatar của bot theo ý, và copy cái Token này (quan trọng):
Vậy là xong bước tạo bot, muốn bot vào kênh của mình thì bạn lên mục OAuth2 -> tích vào bot -> copy link dán vào trình duyệt:
2. Cài những công cụ cần thiết:
Trong bài viết này mình sẽ dùng thư viện Discord.JS để tương tác với API của Discord. Discord.JS là 1 module NodeJS nên nếu chưa cài NodeJS thì hãy lên trang chủ để tải nhé : nodejs.org
Sau khi cài xong NodeJS, cài các thư viện cần thiết, để phát được nhạc từ youtube thì ngoài Discord.JS bot cần opusscript hoặc @discordjs/opus, ffmpeg và ytdl (hoặc bất cứ thằng nào tương tự).
Trước tiên là tạo file index.js (hoặc abc.js hay bất cứ tên gì bạn muốn) ở thư mục bạn muốn đặt mã nguồn (source code) của bot, có thể tạo thêm file config.json để lưu những giá trị quan trọng nếu muốn. Để coding thì bạn dùng bất cứ phần mềm text editor nào cũng được (notepad, notepad++,...), trong bài viết này mình dùng Sublime Text 3.
Mở Command Prompt (cmd) ở thư mục chứa file index.js tạo ở trên, gõ:
Code:
npm init -y
npm install discord.js @discordjs/opus ffmpeg-static ytdl-core --save
Sau khi cài xong chúng ta sẽ tiến hành coding.
3. Coding:
Mở file index.js mà bạn vừa tạo ở trên, nhập các module vào:
Code:
const Discord = require('discord.js');
const ytdl = require('ytdl-core');
const prefix = '!'; // tiền tố để nhận biết lệnh (!play, !stop), đổi thành cái gì tùy ý bạn
const token = ""; //token của bot
Đăng nhập để bot online:
Code:
const client = new Discord.Client();
client.login(token)
Trong bài hướng dẫn này chúng ta chỉ sử dụng 2 event là ready (khi bot đăng nhập thành công) và message (khi có tin nhắn mới được gửi), ngoài ra còn rất nhiều event hay ho khác bạn có thể đọc trong tài liệu của DiscordJS.
Đầu tiên là event ready:
Code:
client.once('ready', () =>{
console.log('Ready'); //bot đăng nhập thành công
});
Thử mở cmd ở thư mục chứa file index.js gõ: node index.js
Nếu màn hình cmd in ra chữ Ready nghĩa là bạn đã thành công bước đầu.
Tiếp theo là event message (khi có tin nhắn mới được gửi trong các kênh mà bot tham gia):
Code:
client.on('message', async msg => {
if (msg.author.bot) return; //nếu người gửi là bot thì khỏi chạy tiếp
if (msg.content === 'ping') {
msg.reply('Pong!'); //nếu tin nhắn có nội dung là ping thì bot trả lời Pong~
}
}
Ctrl + C trong cmd và node index.js lại, thử chat trong kênh là ping, nếu bot trả lời Pong! nghĩa là code hoạt động tốt, đến lúc bắt tay vào code phần phát nhạc.
Mình sẽ lập constructor cho 2 đối tượng Queue và Song và tạo một đối tượng queues sẵn để tiện cho việc sử dụng:
Code:
const queues = new Map();
class Queue {
constructor(voiceChannel) {
this.voiceChannel = voiceChannel;
this.connection = null;
this.songs = [];
this.volume = 100;
this.playing = true;
this.repeat = false;
}
}
class Song {
constructor(title, url) {
this.title = title;
this.url = url;
}
}
Giờ chúng ta code để bot biết khi người dùng gửi lệnh phát. Trong sự kiện message ở trên, thêm code vào như sau (mình sẽ giải thích ở từng dòng cho tiện). Tạm thời mình chỉ hướng dẫn cách đơn giản là phát nhạc khi nhập chính xác url của video. Bạn nào muốn nâng cao hơn (tìm kiếm bài hát) thì tham khảo Youtube API.
Code:
if (msg.content.startsWith(prefix)) { //prefix là tiền tố để xác định lệnh đã được khai báo ở trên ("!")
const args = msg.content.slice(prefix.length).split(/ +/); //bỏ đi tiền tố và chia thành nhiều chuỗi nhỏ theo khoảng trắng
const command = args[0]; //lệnh sẽ là chuỗi đầu tiên
if (command === 'play') { //lệnh phát nhạc
let voiceChannel = msg.member.voice.channel; //kênh voice của người gửi lệnh
if (!voiceChannel) return msg.reply("Vào kênh âm nhạc trước đã!"); //nếu người dùng chưa vào kênh voice nào sẽ thông báo
let permissions = msg.member.voice.channel.permissionsFor(msg.client.user); //kiểm tra quyền vào kênh và nói của bot
if (!permissions.has('CONNECT')||!permissions.has('SPEAK')) return msg.reply("Thiếu quyền vào kênh âm nhạc hoặc phát nhạc!");
let url = args.slice(1).join(' '); //bỏ lệnh đi thì ta có url
let video = await ytdl.getInfo(url); //dùng ytdl lấy thông tin video từ url
if (!video) return msg.reply("Url không hợp lệ!");
const song = new Song(video.title, video.video_url); //tạo đối tượng Song, có 2 giá trị là title và url lấy từ video ở trên
const serverQueue = queues.get(msg.guild.id); //kiểm tra trong đối tượng queues đã có value (giá trị) của cái id guild chưa
if (!serverQueue) { //nếu chưa có value của guild id tức là chưa phát nhạc
let queue = new Queue(voiceChannel); tạo đối tượng Queue chứa thông tin về lần phát nhạc ở server này
queues.set(msg.guild.id, queue); //đặt key là id guild, value là đối tượng queue tạo ở dòng trên
queue.songs.push(song); //thêm bài hát vào danh sách phát
let connection = await voiceChannel.join(); //bot tham gia vào kênh voice
queue.connection = connection;
playSong(msg); //hàm playSong sẽ viết ở dưới
} else { //nếu serverQueue tồn tại tức là đang phát nhạc
serverQueue.songs.push(song); //thêm bài hát vào danh sách phát và thông báo
msg.channel.send(`:notes: Thêm vào hàng chờ: ${song.title}`);
}
return
}
}
}
Code:
async function playSong(msg) {
const serverQueue = queues.get(msg.guild.id); //kiểm tra xem có tồn tại value cho cái id guild không
if (!serverQueue) return; //nếu value không tồn tại thì dừng lại
if (serverQueue.songs.length < 1) { //nếu value tồn tại nhưng danh sách phát trống (phát hết rồi)
serverQueue.voiceChannel.leave(); //bot rời kênh nhạc
queues.delete(msg.guild.id); //xóa cặp key-value của guild id khỏi đối tượng queues
return msg.channel.send("Hết nhạc!");
}
let song = serverQueue.songs[0]; //lấy thông tin bài đầu tiên của danh sách phát
let dispatcher = serverQueue.connection.play(ytdl(song.url, {filter: 'audioonly', highWaterMark: 1<<25, type: 'opus'})); //phát nhạc
dispatcher.setVolume(serverQueue.volume/100); //âm lượng
msg.channel.send(`:notes: Bắt đầu phát: ${song.title}`);
dispatcher.on('finish', () => { //khi luồng phát kết thúc
if (!serverQueue.repeat) serverQueue.songs.shift(); //nếu repeat (lặp lại bài đang phát) = false thì bỏ bài hát đầu tiên bằng hàm shift()
return playSong(msg); //tiếp tục phát cho đến khi danh sách phát = 0 (<1 ở trên) thì thôi
});
}
Về cơ bản thì bot đã phát nhạc tốt, nhưng cần thêm vài chức năng như stop, pause, resume, skip, set volume để hoàn chỉnh hơn:
Chức năng stop:
Code:
if (command === 'stop') {
const serverQueue = queues.get(msg.guild.id);
if (!serverQueue) return msg.reply("Có bài nào đâu!");
serverQueue.songs = []; //xóa toàn bộ danh sách phát
serverQueue.connection.dispatcher.end(); //kết thúc luồng đang phát
return
}
Code:
if (command === 'skip') {
const serverQueue = queues.get(msg.guild.id);
if (!serverQueue) return msg.reply("Có bài nào đâu!");
serverQueue.connection.dispatcher.end();
msg.channel.send(`:notes: Bỏ qua bài: ${serverQueue.songs[0].title}`);
return
}
Code:
if (command === 'volume') {
const serverQueue = queues.get(msg.guild.id);
if (!serverQueue) return msg.reply("Có bài nào đâu!");
let volume = parseInt(args.slice(1).join(""));
if (!isNaN(volume)) return msg.reply("Âm lượng không hợp lệ!");
serverQueue.volume = volume;
serverQueue.connection.dispatcher.setVolume(volume/100);
return
}
if (command === 'pause') {
const serverQueue = queues.get(msg.guild.id);
if (!serverQueue) return msg.reply("Có bài nào đâu!");
serverQueue.connection.dispatcher.pause();
return
}
if (command === 'resume') {
const serverQueue = queues.get(msg.guild.id);
if (!serverQueue) return msg.reply("Có bài nào đâu!");
serverQueue.connection.dispatcher.resume();
return
}
Code:
if (command === 'repeat') {
const serverQueue = queues.get(msg.guild.id);
if (!serverQueue) return msg.reply("Có bài nào đâu!");
serverQueue.repeat = true;
msg.channel.send(`:notes: Lặp lại bài: ${serverQueue.songs[0].title}`);
return
}
if (command === 'offrepeat') {
const serverQueue = queues.get(msg.guild.id);
if (!serverQueue) return msg.reply("Có bài nào đâu!");
serverQueue.repeat = false;
msg.channel.send(`:notes: Ngừng lặp lại bài: ${serverQueue.songs[0].title}`);
return
}
Code:
if (command === 'queue') {
const serverQueue = queues.get(msg.guild.id);
if (!serverQueue) return msg.reply("Có bài nào đâu!");
let result = serverQueue.songs.map((song, i) => {
return `${(i == 0) ? `\`Đang phát:\`` : `${i}.`} ${song.title}`
}).join('\n');
msg.channel.send(result);
return
}
Vậy là chúng ta đã tạo xong một con bot Discord với chức năng phát nhạc đơn giản, đây cũng là lần đầu mình viết hướng dẫn (mới học JS vài tháng) nên nếu có sai sót gì mong mn thông cảm nhé.
Mọi người có thể xem source code tại: Github