discord botのDM機能で遊ぼう！

#はじめに
この記事は[リンク情報システム](https://www.lis.co.jp/)の「[2021新春アドベントカレンダー Tech Connect](https://qiita.com/dgkz/items/eabde6515457d8acec9b)」のリレー記事です。
engineer.hanzomonのグループメンバーによってリレーされます。

(リンク情報システムのFacebookは[こちらです](https://ja-jp.facebook.com/lis.co.jp/))

15日目担当の@o-changです。
私はいつでもdiscord！！！


#やりたいこと
discordにはユーザー同士で直接やり取りできる、DM機能があります。
勿論botでもこの機能を使用することができます。
前回の記事で少し触った程度だったので、備忘録的にまとめておこうと思います。

ソースコード自体はシンプルに、botとやりとりする機能を実装してみます。

#開発環境
言語：Python3
ライブラリ：discord.py

discord.pyを使用して実装します。
botそのものについては[前々回](https://qiita.com/o-chang/items/e45fb7074654f8eb26ea)、
Cogについては[前回](https://qiita.com/o-chang/items/51214b667511d435e1f1)を参照してください。

#実装

メッセージを受け取った「イベント」として実行する場合と、
「コマンド」としてメッセージを受け取る場合の実装例を両方載っています。
仕組みは共通ですので、自身のbotに併せた実装をしてみてください。

###botの本体(イベント)
```discordbot.py
# コマンド拡張機能
from discord.ext import commands
# discordのAPI
import discord
# DmCogの取り込み(./cogsにファイルを置いています)
import cogs.DmCog as DmCog

# コマンドプレフィックスを設定
bot = commands.Bot(command_prefix='$')

# bot起動時に発生するイベント
@bot.event
async def on_ready():
    print('-----')
    print(bot.user.name)
    print(bot.user.id)
    print('-----')
    text = f'Logged on as {bot.user}!'
    GameCog.setup(bot)
    channel = bot.get_channel(チャンネルID(数値))
    await channel.send('start success')

async def on_message(message):
    # botの発言は無視する(無限ループ回避)
    if message.author.bot:
        return
    elif message.content == '':
        await message.author.send('「$hello」 と送信してね！')

# botの起動
bot.run('botのアクセストークン(文字列)')
```

###DmCogクラス(Commandコグ)

```DmCog.py
# exitの実装
import sys

# コグクラス
class DmCog(commands.Cog):
    # DmCogクラスのコンストラクタ。Botを受取り、インスタンス変数として保持。
    def __init__(self, bot):
        self.bot = bot

    # 起動確認のコマンド
    @commands.command()
        async def test(self, message):
        await message.channel.send('test ok')

    # 終了コマンド
    @commands.command()
    async def shutdown(self, message):
        await message.channel.send("shutdown bot")
        sys.exit()

    # 簡単な応答をする
    @commands.command()
    async def hello(self, message):
        if (type(message.channel) == discord.DMChannel) and (client.user == message.channel.me):
            await message.author.send("World!")
        else:
            await message.channel.send("DMで送信してね！")

# Bot本体側からコグを読み込む際に呼び出される関数。メンバ関数ではないです。
def setup(bot):
    # cogクラスにbotを渡してインスタンス化
    bot.add_cog(DmCog(bot))
```


#解説



###①特定のユーザーにDMを送信する方法
受け取ったメッセージのauthorにユーザー情報が入っているので、sendメソッドを利用してDMを送信できます。
簡単にですが、送信先の指定方法をまとめておきます。

```send.py
message.channel.send(txt) # メッセージが入力された場所(テキストチャネル)に送信する
message.author.send(txt)  # メッセージの送信者にDMを送信する
channel.send(txt)         # 任意のチャンネルIDを使用してchannel

# (番外編)
txt = f'{message.author.mention} Hey!'
message.channel.send(txt) # 送信者にメンションを送ることができる。author.send()との比較用。
```

###②DMを受け取る方法
discordのbotにコマンドを送る場合、botが入っているサーバーやbotのDMなど、botにメッセージを読み取る権限がある場所ならどこでもOKです。
そのため、他のコマンドと基本的に同様の記述方法で問題ありません。

受け取ったコマンドの詳細を確認することで、DMが使用されているか否かを判断します。
・「コマンドが送信された場所はDMである」
・「そのDMは、bot自身のDMである」
ことを確認し、DMでコマンドを受け取ったと判断していています。

追加で送信ユーザーの確認を「if(message.author() == ○○)」で行うと、特定のユーザーからのDMのみに反応することもできそうです。


#おわりに
時勢柄、様々なオンラインツールに注目が集まっていますが、離れたご友人とコミュニケーションを取る場所としてdiscordを利用してみては如何でしょうか？
個人的にはチャットの自由さが気に入ってます。
Markdown形式で記述できるのが非常に楽しい…！
是非ご友人を誘って一度使ってみてください！

そして面白くて便利なbotを実装して、ヒーローになりましょう！(。-`ω-)


---
[リンク情報システム株式会社](https://www.lis.co.jp)では一緒に働く仲間を[随時募集](https://www.lis.co.jp/employ_top)しています！
また、お仕事のご依頼、ビジネスパートナー様も募集しております。[お気軽にご連絡](https://www.lis.co.jp/inquiry)ください。