미사용/(舊)디스코드봇 강좌

디스코드봇(파이썬) 02 | 기본적인 내용을 주고 받자.

건유1019 2020. 3. 28. 17:05

이번에는 기존 1편에서 진행한, 내용에 이어서 파이썬을 통하여 내용을 주고받도록 해봅시다.


일단 강의를 효율적으로 진행하기 위해 예제를 가져와 봤습니다.

 

import discord
import asyncio
 
client = discord.Client()
 
@client.event
async def on_ready(): 
    print("디스코드 봇 로그인이 완료되었습니다.")
    print("디스코드봇 이름:" + client.user.name)
    print("디스코드봇 ID:" + str(client.user.id))
    print("디스코드봇 버전:" + str(discord.__version__))
    print('------')
    await client.change_presence(status=discord.Status.online, activity=discord.Game("서술"))
 
@client.event
async def on_message(message): 
    content = message.content 
    guild = message.guild 
    author = message.author 
    channel = message.channel 
    if content.startswith("!test"): 
        await message.channel.send("test" + message.content) 
    if content == "!ping": 
        await message.channel.send("Pong!") 
 
client.run('토큰번호')

이제부터 이 코드를 하나하나 직접 분석해 봅시다.

import discord
import asyncio

client = discord.Client()

이 내용은 인덱스를 불러오는 것입니다. discord라는 1편에서 설치한 모듈과 asyncio라는 비동기 함수를 불러오는 것입니다. 여기서 비동기 함수란? 비동기적으로 코드가 작동한다는 뜻으로, 만약에 이미 진행 중인 내용이 있어도 추가적으로 돌릴 수 있습니다.

 

<정확한 뜻.> asyncio는 고성능 네트워크 및 웹 서버, 데이터베이스 연결 라이브러리, 분산 작업 큐 등을 제공하는 여러 파이썬 비동기 프레임워크의 기반으로 사용됩니다. (출처)

 

또한 client라는 변수를 만들어 discord.Client()를 넣어줍니다. 이것은 나중에 코드 내용을 줄이기 위해 사용됩니다.

@client.event
async def on_ready(): 
    print("디스코드 봇 로그인이 완료되었습니다.")
    print("디스코드봇 이름:" + client.user.name)
    print("디스코드봇 ID:" + str(client.user.id))
    print("디스코드봇 버전:" + str(discord.__version__))
    print('------')
    await client.change_presence(status=discord.Status.online, activity=discord.Game("서술"))

다음은 이것에 대해 분석해봅시다.

이벤트 중에서 on_ready라는 것이 들어오면 작동하게 됩니다. 이벤트 중에는 on_message, on_connect 등 여러 가지가 존재하지만, 이것은 추후 이벤트 강좌를 준비해보도록 하겠습니다.

 

일단 저건 디스코드 봇이 성공적으로 로그인하면 작동하게 됩니다.

client.user.name 에는 유저 이름을 가져올 수 있습니다. 사실 이건 저만 되는 꼼수일지도 있지만 str(client.user)로 해도 가져올 수 있습니다. 

client.user.id라고 하면 해당 봇의 ID를 구할 수 있습니다. 이는 나중에 역할 작업 아니면, 다른 서버와 상호작용을 할 때 유용하게 사용됩니다. 그리고 discord.__version__으로 디스코드 버전을 구할 수 있습니다. 사실 위 print는 없애도 됩니다. 그러나 확인은 해야 한다고 생각해서 추가해 보았습니다.

 

await client.change_presence(status=discord.Status.online, activity=discord.Game("서술")) 이것은 디스코드 상태 그리고 상태 메시지를 설정할 수 있습니다.

status에는 온라인, 자리 비움, 방해금지, 오프라인 등으로 4가지의 설정이 가능하며,

discord.Status.online ▶상태가 온라인이라고 표시됩니다.

discord.Status.offline ▶ 상태에서 오프라인이라고 표시됩니다. (그러나, 실제로 봇이 오프라인 되는 것은 아닙니다;;)

discord.Status.idle ▶ 상태에서 "자리비움"이라고 표시됩니다.

discord.Status.dnd ▶상태에서 "다른 용무중"이라고 표시가 되긴 합니다.

discord.Status.do_not_disturb ▶dnd 경우에는 편의상 요약한 것이며 이렇게 적어도 "다른 용무 중"이라고 나옵니다.

이렇게 해서 사용을 하실수 있습니다.

 

또한 activity 에는 ~~플레이 중, ~~방송 중, ~~시청 중등으로 설정하실 수 있습니다.

 

discord.Activity(name="서술", type=discord.ActivityType.(종류)) ▶상태를 아래의 2개 말고 직접 설정하여 설정하실 수 있습니다. 

type에는 위 5개를 넣어주실 수 있습니다.

discord.ActivityType.playing ~~플레이 중이라고 표시됩니다. discord.Game()과 동일한 기능 중 하나입니다.

discord.ActivityType.playing 라고 하면 위와 같이 표현됩니다.

discord.ActivityType.streaming ~~방송 중으로 표시됩니다. discord.Streaming()과 동일한 기능 중 하나입니다.

특히 이기능을 사용 시에는 아래에 서술하겠지만 저렇게 다 설정해주셔야 합니다.

discord.ActivityType.streaming 라고 하면 위와 같이 표현됩니다.

discord.ActivityType.listening ~~듣는 중으로 표시됩니다.

discord.ActivityType.listening 라고 하면 위와 같이 표현됩니다.

discord.ActivityType.watching ~~시청 중으로 표시됩니다.

discord.ActivityType.watching 라고 하면 위와 같이 표현됩니다.

discord.ActivityType.custom  사실 이거 사용법을 모릅니다... 댓글로 통한 제보 부탁드립니다.

discord.Game("서술") ▶ "서술"하는 중라고 표시됩니다. 저위에서 type를 discord.ActivityType.playing라고 해도 똑같이 표시됩니다.

 

discord.Game 하면 위와같이 표현됩니다.

discord.Streaming(name="서술",platform="Youtube 혹은 Twitch", details="진정한 서술", url="유튜브 링크 혹은 트위치 링크") ▶ "서술"하는 중이라고 표시되긴 합니다. 근데 일부에선 "서술" 방송 중이라고 표시될 수도 있습니다. url에 링크를 넣으면 "보기" 버튼이 생기며, 클릭 시 그 영상을 확인하실 수 있습니다. name에는 넣어도 의미 없는 거 같긴 합니다만... 일단 넣어줍니다.

discord.Streaming 라고 하면 위와 같이 표현됩니다.

discord.CustomActivity(name="") ▶ 상태 메시지를 커스텀하는 것으로 알려줬지만 사실, 실제로 사용법을 모르겠습니다... 댓글로 통한 제보 부탁드립니다.

 

이제 다음 on_message에 대해 분석해봅시다.

@client.event
async def on_message(message): 
    content = message.content 
    guild = message.guild 
    author = message.author 
    channel = message.channel 
    if content.startswith("!test"): 
        await message.channel.send("test" + message.content) 
    if content == "!ping": 
        await message.channel.send("Pong!") 

이것은 사용자가 메시지를 적었을 때 작동하는 것으로, 카카오톡 봇에서는 function response(room, msg, sender, isGroupChat, replier, imageDB)와 동일한 기능입니다. 단지 여기선 message라는 dict형식의 변수로만 받으면 된다는 점이 존재합니다.

 

위 4개의 변수 선언의 의미는 아래와 같습니다.

message.content ▶ 사용자가 보낸 내용을 표시합니다.

message.guild ▶ 보낸 서버 이름을 표시합니다.

message.author ▶ 보낸 유저의 태그까지 포함해서 표시합니다.

message.channel ▶ 보낸 유저의 채널을 표시합니다.

이것을 카카오톡 봇으로 본다면 content가 msg이고, author가 sender, room이 guild와 channel이라고 보시면 됩니다.

 

if content.startswith("수신 내용"):이라고 하면 "수신 내용"이 시작되는 단어면 작동이 됩니다.

if content == "수신 내용":이라고 하면 "수신 내용"과 동일해야 작동합니다.

이 기능은 나중에 유용하게 사용할 곳이 존재합니다. 이렇게 본다면, 두 개의 장단점을 확인할 수 있습니다.

startswith를 사용하면 이후 내용을 이어서 받을 수 있다는 장점이 있지만 저 말과 비슷한 단어도 감지된다는 겁니다.

예를 들면 if content.startswith("=help"): 를 먼저 하고 if content.startswith("=help_alpha"):라고 한다고 가정해봅시다.

=help라고 입력하게 되면 둘 다 작동한다는 단점을 볼 수 있습니다. if content == "수신 내용"을 사용하면, 이후 내용을 이어서 받을 수 없고 무조건 일치해야 합니다.

 

사실 위 2개가 유용하게 사용됩니다 이외에도. find(),. endswith()를 사용하여 값을 얻을 수도 있습니다.

if content.find("수신 내용") == -1:라고 한다면 수신 내용이 포함돼있으면, 작동하게 되는 것입니다.

if content.endswith("수신 내용"):라고 한다면 내용 끝이 "수신 내용"이라고 포함돼있으면 작동하게 됩니다

사실 2개는 크게 쓸 곳이 없습니다. find 경우에만 비속어 탐지 등으로 유용하지 크게 의미가 없는 것들입니다.

 

시현.

여기서 맨마지막에 !ping (추가내용)을 적었지만 인식하지 못했습니다 왜냐하면 if content == "!ping":  라고 했기 때문에 일치하게 적어야만 인식합니다.

 

이제 마지막으로 client.run('토큰 번호')에 대해 알아봅시다.

client.run('토큰번호')

이건, 사실 시작할 때 돌려도 의미 있습니다.(?) 맨 마지막으로 돌려주세요. client 가 돌아가게 하는 겁니다

토큰 번호에 저번 1편에서 강의한 토큰 번호를 넣어주시면 됩니다. 이것을 또 함부로 유출하게 되면, 상당히 피해가 큽니다. 실제로 저도 호스팅을 사용 중인데 호스팅에서 토큰을 유출시켜버리는 바람에 대참사를 만들었습니다. 진짜 이것만은 잘 지킵시다.


이상으로 2편을 마칩니다. 참고로 이것을 지난주에 연재했어야 하지만, 사정(랜섬웨어 및 토큰유출 사건)으로 인해 오늘 2개를 올려보겠습니다. 다음에는 embed를 사용하여 저 내용을 깔금하게 보는법을 알려드리겠습니다.