SARACEN's Blog
  • 파이썬으로 디스코드 음악봇 제작기 - 2
    2021년 12월 22일 15시 13분 43초에 업로드 된 글입니다.
    작성자: RACENI

    디스코드 사진


    • 기능(아래의 기능은 개발이 진행되면서 추가 혹은 변경, 제거가 될 수 있습니다.)
      • 유튜브 영상의 음성 출력
      • 추가한 리스트 목록 확인
      • 플레이리스트(추가한 노래 리스트) 저장 및 불러오기
      • 리스트 목록 개별 제거
      • 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)

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

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