본문 바로가기
CODING/Python

파이썬으로 디스코드 음악봇 제작기 - 2

by NOBLESSE 2021. 12. 22.
728x90
반응형

디스코드 사진


  • 기능(아래의 기능은 개발이 진행되면서 추가 혹은 변경, 제거가 될 수 있습니다.)
    • 유튜브 영상의 음성 출력
    • 추가한 리스트 목록 확인
    • 플레이리스트(추가한 노래 리스트) 저장 및 불러오기
    • 리스트 목록 개별 제거
    • loop 기능
    • leave 기능
    • skip 기능
    • pause 기능
    • resume 기능
    • save 기능(2에 추가)
    • open 기능(2에 추가)

파이썬으로 디스코드 음악 봇 제작기는 3까지 진행될 것 같습니다.

이번 2에서는 플레이리스트 기능과 각종 기타 기능을 추가하는 가벼운 작업(?)이 되겠습니다.

 

추후에 있을 제작기 3에 완성된 소스코드를 올리도록 하겠습니다! 이번 회차까지는 부분 별로 코드를 업로드하겠습니다.

감사합니다.


  • 파이썬으로 디스코드 음악 봇 제작기
  • 간략한 구현 과정
    • 플레이리스트 제작
    • 각종 기능(일시정지, 다시시작, 넘기기 등)
  • 파이썬으로 구현된 코드
            • 좀 더 봇같은 대화를 위해 Embed 사용을 위해 함수를 만들어줬습니다.
              def set_Embed(title = '', description = ''):
                  #embed = discord.Embed(title="메인 제목", description="설명", color=0x62c1cc)
                  return discord.Embed(title=title, description=description)​
            • 플레이리스트 적용을 위해서 전역변수 i(int형)를 추가했습니다.
            • Loop 기능 적용을 위해서 전역변수 loop(bool형), playlist(list형)을 추가했습니다.
            • 바뀐 song_start함수와 play함수 코드를 보여드리겠습니다.
              async def song_start(voice, i):
                  try:
                      if not voice.is_playing() and not voice.is_paused():
                          ydl_opts = {'format': 'bestaudio'}
                          FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
                          with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                              info = ydl.extract_info(f'https://www.youtube.com{playlist[i][1]}', download=False)
                              URL = info['formats'][0]['url']
                          
                          voice.play(discord.FFmpegPCMAudio(URL, **FFMPEG_OPTIONS))
                      #voice.play(discord.FFmpegPCMAudio(executable = './ffmpeg-4.4-full_build-shared/bin/ffmpeg.exe', source='./song.mp3'))
              
                      while voice.is_playing() or voice.is_paused():
                          await asyncio.sleep(0.1)
                  except:
                      return
              
              @bot.command(aliases = ['play', 'p', 'ㅔ'])
              async def Play(ctx,*,  keyword):
                  try:
                      results = YoutubeSearch(keyword, max_results=1).to_dict()
              
                      global playlist
                      playlist.append([results[0]['title'], results[0]['url_suffix']]) # 플레이리스트에 노래 추가
                      await ctx.send(embed=set_Embed(title='노래 추가',description=f"{results[0]['title']}"))
              
                      channel = ctx.author.voice.channel
                      if bot.voice_clients == []:
                          await channel.connect()
                          #await ctx.send("connected to the voice channel, " + str(bot.voice_clients[0].channel))
                      voice = bot.voice_clients[0]
              
                      if not voice.is_playing() and not voice.is_paused():
                          global i
                          i = 0
                          while True:
                              await song_start(voice, i)
                              if loop:
                                  if i < len(playlist) - 1:
                                      i = i + 1 
                                  else:
                                      i = 0
                                  continue
                              elif i < len(playlist) - 1:
                                  i = i + 1
                                  continue
                              playlist = [[]]
                              break
                      #await voice.disconnect()
                  except:
                      await ctx.send("Play Error")​
            • 저장한 플레이리스트를 파일로 저장하고 불러오는 기능을 통해 영구 보존할 수 있게끔 했습니다.
              @bot.command(aliases = ['save'])
              async def Save(ctx, * , arg):
                  with open(f'{arg}.txt','w',encoding='UTF-8') as f:
                      global playlist
                      f.write(str(playlist))
              
              @bot.command(aliases = ['open'])
              async def Open(ctx, * , arg):
                  try:
                      with open(f'./{arg}.txt','r',encoding='UTF-8') as f:
                          global playlist
                          playlist = eval(f.read())
              
                      global i
                      await ctx.send(f"플레이리스트 추가 완료\n{arg}")
              
                      channel = ctx.author.voice.channel
                      if bot.voice_clients == []:
                          await channel.connect()
              
                      voice = bot.voice_clients[0]
                      if voice.is_playing() or voice.is_paused():
                          i = -1
                          bot.voice_clients[0].stop()
                      else:
                          i = 0
                          while True:
                              await song_start(voice, i)
                              if loop:
                                  if i < len(playlist) - 1:
                                      i = i + 1 
                                  else:
                                      i = 0
                                  continue
                              elif i < len(playlist) - 1:
                                  i = i + 1
                                  continue
                              playlist = [[]]
                              break
                  
              
                  except:
                      await ctx.send("Open Error")​
            • remove와 q 명령어를 통해 플레이리스트에 있는 노래를 제거하거나 볼 수 있게끔 했습니다.
              @bot.command(aliases = ['q', 'ㅂ'])
              async def Que(ctx):
                  try:
                      queText = ''
                      for title in range(len(playlist)):
                          try:
                              queText = f'{queText}\n' + f'{title + 1}. {playlist[title][0]}'
                          except:
                              del playlist[title]
                      await ctx.send(embed=set_Embed(title='플레이리스트',description=f"{queText}"))
                  except:
                      pass
              
              @bot.command(aliases = ['remove'])
              async def Remove(ctx, arg):
                  try:
                      global playlist
                      remove_song = playlist[int(arg)- 1][0]
                      del(playlist[int(arg)- 1])
                      global i
                      i = i - 1
                      if (i + 1) == int(arg) - 1:
                          bot.voice_clients[0].stop()
                      await ctx.send(embed=set_Embed(title='노래 삭제',description=f"{remove_song}"))
                  except:
                      await ctx.send('노래 제거중 오류 발생!')​
            • 루프 사용은 loop 변수를 true/false로만 변경해주고 처리는 play함수에서 진행하게끔 했습니다.
              @bot.command(aliases = ['loop', 'l', 'ㅣ'])
              async def Loop(ctx):
                  try:
                      global loop
                      loop = True if loop == False else False # true false 서로 변경
                      await ctx.send(f"현재 LOOP 상태: {loop}")
                  except:
                      await ctx.send("Loop Error")​
            • 기타 기능들입니다.
              @bot.command(aliases = ['leave'])
              async def Leave(ctx):
                  try:
                      await bot.voice_clients[0].disconnect()
                  except:
                      await ctx.send('Leave Error')
              
              @bot.command(aliases = ['skip', 's'])
              async def Skip(ctx):
                  try:
                      bot.voice_clients[0].stop()
                  except:
                      await ctx.send("Skip Error")
              
              @bot.command(aliases = ['pause'])
              async def Pause(ctx):
                  try:
                      bot.voice_clients[0].pause()
                  except:
                      await ctx.send("Pause Error")
              
              @bot.command(aliases = ['resume'])
              async def Resume(ctx):
                  try:
                      bot.voice_clients[0].resume()
                  except:
                      await ctx.send("Resume Error")​

 

복잡한 코드가 없어서 주석을 안 넣었습니다.(최종본에는 들어갈지도,,,) 

 

일단 남은 문제점은 여러 채널에서 사용하려하면 오류가 나는 것입니다. 하나의 thread만 사용해서 그런 것 같은데, 천천히 찾아보면서 고치려고 합니다. 해당 문제가 고쳐지면 소스코드 정리해서 최종본을 업로드할 계획입니다.

 

코드에 궁금한 점이 있으면 댓글로 물어봐주시면 좋겠습니다!

 

날이 많이 쌀쌀해졌는데, 감기 조심하시구 재밌는 프로그래밍 하시길 바랍니다~

감사합니다~!!!

 

(구독도 ^^7)

728x90
반응형

'CODING > Python' 카테고리의 다른 글

파이썬으로 디스코드 음악봇 제작기 - 1  (0) 2021.09.08
[파이썬:Python]달팽이배열  (0) 2020.07.04
[파이썬:Python]타자게임  (0) 2019.06.13