- 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://namu.wiki/w/Discord/봇/제작법 참고.
- 봇 개발
- 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
- 개발에 필요한 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 ******
- add 한 bot 에서 제공하는 Token 사용
- ...
- 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}
- ...
- 두가지 방법중 한가지 방법 (mutually exclusive) 으로 받을수 있다.
- 최종적으로 스펙에 맞게 리턴을 하면... discord 으로 액션을 할 수 있다.
- type 값 등등 자세한 스펙 설명은... 생략한다.
-
# tts는 디스코드 클라이언트 내장 TTS 인것 같다... 18 return jsonify({ "type": 4, "data": { "tts": True, "content": "첫 메시지 발송 추카추카추", "embeds": [], "allowed_mentions": { "parse": [] } } })
-
- ...
- type 값 등등 자세한 스펙 설명은... 생략한다.
- Authentication : http 인증은 아래의 두가지중 하나를 쓰면 됨
- 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~~~')
- ...
- ...
- "처음에는 굳이... websocket 기반으로?" 하지만, 디스코드는 이 방식을 더 선호하는거 같음.
- ...
- ...
-끝-