• Discord 란?
    • 불협화음.
    • 음성, 채팅, 화상통화 등을 지원하는 Instant Message Service.
    • (뛰어난 성능과 직관적인 간편함으로~ 대부분 게임 커뮤니케이션 에 사용됨)
  • 킬링 포인트
    • 대부분의 기능이 무료 !?!?!?
    • 오버레이 기능으로 떡상을 했다고 함... (skype, talkon, IRC 등등을 다 쳐바름)
    • 왠만한 게임내 음성채팅보다도... 끊김없이 음질이 뛰어나다고 함.
    • 다양한 채팅봇, 음악봇, 유튜브재생봇, 게임프로필봇 등등의 3rd 파티봇(?) 이 풍부하다고 함.
  • Discord Nitro
    • 유료 월구독자 혜택 서비스.
    • EX) 움직이는 GIF 아바타, 고화질, 커스텀 이모지, 업로드 용량, 서버 부스트 2개 지급, 게임스토어, ...
    • Server Boosting) 이렇게 유효 회원들이 -> 부스트를 많이 걸어주면 ~> 해당 서버기능이 향상되고, 수익도 배분해줌!
  • Discord 서버
    • Slack 워크스페이스 와 같은 개념이라고 보면 될 것 같음.
    • 즉, 특정 주제의 '서버'를 만들고~ 참여한 사람들끼리 슬랙처럼 대화를 한다...
  • Discord 봇
    • 슬랙처럼... 디스코드 서버에도 각종 관리, 알람, 오락 등등을 제공하는 봇을 초대 할 수 있음.
    • 이런 Bot 시장이 굉장히 활성화 되어있음. (top.gg) (koreanbots.dev)
    • 이런식으로 초대한 Bot 에게 서버의 특정 권한을 부여해주고, 초대후 각종 인터액션으로~ 여러가지 요청을 하는식...
  • 봇 개발 방식
    • https://namu.wiki/w/Discord/봇/제작법 참고.
      • 비공식(?) 라이브러리 활용
      • 공식 Discord API 활용
      • Discord Bot Maker 활용
  • 봇 개발
    • https://discord.com/developers/docs
    • 1) Application 등록 및 Bot 셋팅 및 OAuth2 URL 생성
      • 일단, 'New Applicaion' 후~ 'Add Bot' 하고~ 'OAuth2URL' 만든다...
      • 결과적으로 해당 URL으로 -> Discord 서버에 -> 봇을 -> 초대 할 수 있다!
      • 예) https://discord.com/api/oauth2/authorize?client_id=******&permissions=8&scope=bot
      • Scope에 'bot' 을 체크하면... Bot Permission 까지 체크 할 수 있음
      • 개발에 필요한 App ID, Key, Secret, Token 등등 을 활용하면 된다.
    • 1-1) HTTP REST API 기반으로 개발 (https://discord.com/api)
      • Authentication : http 인증은 아래의 두가지중 하나를 쓰면 됨
        • add 한 bot 에서 제공하는 Token 사용
          • 예) Authorization: Bot ***.***.***
        • OAuth2.0 을 기반으로 획득한 토큰 사용 (귀찮다...)
          • 예) Authorization: Bearer ******
      • ...
      • 1-1-1) 인터액션을 위한, Slash Command 등록하기
        • 기본적으로 discord 에서 -> 특정 "/커맨드 ... ..." 이벤트를 -> 나의 bot에게 콜백 해주기 위한 작업.
        • 봇의 Scope는 'bot' 과 'applications.commands' 으로 하면 된다.
        • #아래와 같이... 이상한(?) 형식으로 요청 할 수 있다.
          
          url = "https://discord.com/api/v8/applications/<app_id>/commands"
          header = {"Authorization": "Bot 123456"}
          body = {
              "name": "테스트",
              "options": [
                  {
                      "name": "옵션",
                      "type": 3,
                      "required": true,
                      "choices": [
                          {"name": "호빈이","value": "호빈이"},
                          {"name": "찬구","value": "찬구"},
                          {"name": "카밀라","value": "카밀라"}
                      ]
                  },
                  {
                      "name": "작성글",
                      "type": 3,
                      "required": true
                  }
              ]
          }
        • ...
         
      • 1-1-2) Receiving an 인터액션
        • 두가지 방법중 한가지 방법 (mutually exclusive) 으로 받을수 있다.
          • Via Interaction Create gateway event
          • Via outgoing webhook
        • (게이트웨이 이벤트는... websocket connected-client 으로 다뤄... 일단 재끼고 ㅎㅎ)
        • 웹훅 기반으로, "INTERACTIONS ENDPOINT URL" 를 걸면된다.
          • Your endpoint must be prepared to ACK a PING message
          • Your endpoint must be set up to properly handle signature headers
          • # 아래와 같이, PING Message에 -> {"type": 1} 응답을 해야하고~
            # 잘못된 signature 헤더에 관해서 -> 401 응답을 해야 된다.
            
            @app.route('/엔드포인드', methods=['POST'])
            def pong(headers, body):
                signature = None
                if 'X-Signature-Ed25519' in headers:
                    signature = headers['X-Signature-Ed25519']
                timestamp = None
                if 'X-Signature-Timestamp' in headers:
                    timestamp = headers['X-Signature-Timestamp']
            
                # Your public key can be found on your application in the Developer Portal
                PUBLIC_KEY = '키'
                verify_key = VerifyKey(bytes.fromhex(PUBLIC_KEY))
                try:
                    verify_key.verify(f'{timestamp}{body}'.encode(), bytes.fromhex(signature))
                except BadSignatureError:
                    return 401, 'invalid request signature'
                    
                if body.json["type"] == 1:
                    return {"type": 1}
        • ...
      • 최종적으로 스펙에 맞게 리턴을 하면... discord 으로 액션을 할 수 있다.
        • type 값 등등 자세한 스펙 설명은... 생략한다.
          • # tts는 디스코드 클라이언트 내장 TTS 인것 같다... 18
            
            return jsonify({
               "type": 4,
               "data": {
                	"tts": True,
                    "content": "첫 메시지 발송 추카추카추",
                    "embeds": [],
                    "allowed_mentions": { "parse": [] }
               }
            })
        • ...
    • 1-2) WSS Gateway API 기반으로 개발 (wss://gateway.discord.gg)
      • "처음에는 굳이... websocket 기반으로?" 하지만, 디스코드는 이 방식을 더 선호하는거 같음.
        • https://en.wikipedia.org/wiki/WebSocket
      • 디스코드는 그냥... 게임 회사? ㅎㅎ
      • (특히, HTTP는 voice channel 쪽을 아무리 찾아봐도 없는거 같음)
      • 다행히... 쌩으로 websocket 개발 할 필요는 없었다.
        • https://namu.wiki/w/discord.py
        • https://discordpy.readthedocs.io/en/latest/index.html
        • 비공식(?) 라이브러리 맞나 ??? ㅎㄷㄷ (굉장히 편하게 쓸수있고... 대부분 이렇게 봇을 만드는거 같음)
      • 1-2-1) 큌하게 스타트
        • 봇 토큰만 있으면... 로컬에서도 손쉽게 띄울 수 있다. ㅎㄷㄷ
        • import discord
          from discord.ext import commands
          
          bot = commands.Bot(command_prefix='~~')
          
          @bot.event
          async def on_ready():
              print(bot.user.name)
              print(bot.user.id)
          
          @bot.command()
          async def ping(ctx):
              await ctx.send(f"pong! ({round(round(bot.latency, 4)*1000)}ms)")
          
          @bot.command(name='voice', help='보이스 테스트')
          async def voice(ctx, *, text):
              try:
                  if ctx.author.voice:
                      voice_channel = ctx.voice_client
                      if voice_channel is None:
                          voice_channel = await ctx.author.voice.channel.connect()
          
                      voice_channel.play(discord.FFmpegPCMAudio(보이스 데이터))
                  else:
                      await ctx.send(f"먼저, '음성채널'에 들어와 주세요. ^^")
          
              except Exception as e:
                  await ctx.send("The bot is not connected to a voice channel.")
          
          bot.run(토큰)
          
          if __name__ == '__main__':
              print('Hi, Disco~ d`d`Disco~ d`d`Disco~ d`d`Disco~~~')
          
        • ...
      • ...
    • ...
  • ...

-끝-

'빅브로 들' 카테고리의 다른 글

OBS  (0) 2023.11.21
Slack  (0) 2021.06.27
sendbird  (0) 2021.04.28
firebase  (0) 2020.12.02
instagram  (0) 2020.11.18

+ Recent posts