본문 바로가기

디스코드봇

[JS] 디스코드 노래 봇 4

반응형

이제 얼추 정리는 끝났다.

유튜브search api도 가져왔고, 그걸 이용하여 노래 재생까지 완료된 상태다.

여기에 명령어를 정리하여 코드를 정리해보자

 

현재까지 작성했던 내용을 바탕으로 조금 정리해본 코드이다.

const { Client, GatewayIntentBits } = require('discord.js');
const { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus } = require('@discordjs/voice');
const ytdl = require('ytdl-core');
const { token, youtubeApiKey } = require('./discordConfig.js');

const sodium = require('libsodium-wrappers'); // 추가된 부분
const search = require('youtube-search'); // 유튜브 검색 추가

const client = new Client({
    intents: [
      GatewayIntentBits.Guilds,
      GatewayIntentBits.GuildVoiceStates,
      GatewayIntentBits.GuildMessages,
      GatewayIntentBits.MessageContent
    ]
  });

const opts = {
  maxResults: 1,
  key: youtubeApiKey,
  type: 'video'
};

// 준비
client.on('ready', () => console.log(`${client.user.tag} 에 로그인됨`));

let connection;
let voiceChannel;
let player;
let isPlaying = false;


//명령어가 !재생인경우
function prefixPlay(message){
  const query = message.content.replace('!재생', '').trim();

    if (!query) {
      return message.reply('재생할 노래 제목이나 URL을 입력하세요.');
    }

    voiceChannel = message.member.voice.channel;
    if (!voiceChannel) {
      return message.reply('채널에 먼저 선 입장 필요');
    }

    const permissions = voiceChannel.permissionsFor(message.client.user);
    if (!permissions.has('CONNECT') || !permissions.has('SPEAK')) {
      return message.reply('권한이 없습니다.');
    }

    search(query, opts, async (err, results) => {
      if (err) return console.error(err);

      if (results.length === 0) {
        return message.reply('검색 결과가 없습니다.');
      }

      const playUrl = results[0].link;

      if (!isPlaying) {
        playNext(voiceChannel, message.guild, playUrl);
      } 
    });
}

// 노래 재생
async function playNext(voiceChannel, guild, playUrl) {
  try {
  	if (!connection) {
        connection = joinVoiceChannel({
          channelId: voiceChannel.id,
          guildId: message.guild.id,
          adapterCreator: message.guild.voiceAdapterCreator,
        });
    }

    const playStream = () => {
      const stream = ytdl(playUrl, {
        filter: 'audioonly',
        fmt: "mp3",
        highWaterMark: 1 << 62,
        liveBuffer: 1 << 62,
        dlChunkSize: 0, //disabling chunking is recommended in discord bot
        bitrate: 128,
        quality: "lowestaudio"
       });
      const resource = createAudioResource(stream);
      player.play(resource);
    }

    player = createAudioPlayer();

    playStream();
    connection.subscribe(player);

    player.on(AudioPlayerStatus.Idle, () => {
      playStream();
    });

  } catch (error) {
    console.error(error);
  }
}

function leaveChannel(message){
  
  if(!connection) return message.channel.send("채널에없음")

  connection.destroy()
  connection = "" // connection 을 null로 만들어야지 다음 join이 됨...
  isPlaying = false;
}

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

    if (message.content.startsWith("!재생")) prefixPlay(message);
    else if(message.content === '!컷'){
        isPlaying = false;
        if (player) {
        	player.stop();
        }
        if (connection) {
        	leaveChannel(message)
        }
    }
});

client.login(token);

 

!재생 노래이름 입력시 노래이름을 기준으로 유튜브에 검색되어 해당 링크로 노래가 재생되도록 되어있다.

!컷 입력시 노래봇이 중지되며 퇴장되는데

이유는 모르겠지만 connection.destory() 시에 이미 선언한 connection 이 제대로 없어지지 않아 다음 노래 재생때 노래봇이 채널에 입장하지 못하는 이슈가 있다.

그래서 connection.destroy() 후에 connection=null 로 초기화를 하도록 해두었다.

해당 이슈에 대해서는 아직도 해결을 못하는 중이다.

 

어쨋든 이렇게 재생과 중지 명령어를 붙여서 코드를 한번 정리했다.

이후에 반복재생, 재생목록도 추가해야겠다.

반응형

'디스코드봇' 카테고리의 다른 글

[JS] 디스코드 노래 봇 5  (0) 2024.08.24
[JS] 디스코드 노래 봇 3  (0) 2024.06.30
[JS] 디스코드 노래 봇 2  (1) 2024.06.16
[JS] 디스코드 노래 봇  (1) 2024.06.16