うどん県出身グーナーの呟き

神奈川県在住のグーナーです。プログラムをやっているので勉強していることや作った便利ツールを公開したいと思います。

【Python】Discord用チーム分けBotをPythonで作ったよ【discord.py】

github.com

TeamMaker

Member List Maker Bot for Discord App

2019/12/05

ご指摘がありましたので追記します。

現在、Discord.pyはver 1.0 ~ になっていますが、現状このTeamMakerボットはver 0.7より以前のもののみ対応しています。

理由は下のリンクにありますが、変数名やクラス構成が大きく変わったことが原因となります。

現在、Discord.pyのversion確認をしつつ、1.0以降も対応できるように変更中です。

変更が完了次第、こちらの記事も追記したいと思います。

discordpy.readthedocs.io

2019/12/27 追記 version 1.2.5でも問題なく稼働することを確認しました。 ご指摘いただいた方、ありがとうございました。

2020/10/20 編集 ソースコードの整理を実施した関係で実行する際に呼び出すコードが

TeamMaker.py -> BotBase.py

に変更しました。 TeamMaker.pyはチーム分け機能のみを持つクラスになっています。

トーナメント表を自動で作る機能も追加しました。 ryo-udon.hatenadiary.jp


TeamMakerとは / What is TeamMaker

皆さん、ゲームは好きですか?

僕は大好きです。 夜な夜な友人と集まり、サッカーゲームを楽しんでいます。 そんな中、ある日あまりにも人数が集まり過ぎて、紅白戦をすることになりました。

さて、チーム分けをしよう!

...

どうやって?

結局、その場では適当なスマホアプリをインストールしましたが、何度もそれをやるのは面倒!

という個人的な理由から生まれたのがこのTeam Makerです。

TeamMakerとはボイスチャットアプリとして有名な Discordで動かせるチーム分けBotになります。

使い方は簡単。ただ指定のボイチャチャンネルに参加する人が集まった状態で一言、 "!start" とコメントするだけ。 これだけで自動的にチーム分けをしてくれます。

その他にもいろいろと機能があり、今後も追加していく予定です。 まずは使用方法から見てみてください。

TeamMaker使用方法 / How to use TeamMaker

現在搭載されている機能は2つのチームにランダムで分けてくれることです。 それ以外にも機能はありますが、現在開発中なので、随時別記事に追加していきます。

!start

すでにこのbotをサーバーに入れられている方は友達と一緒にVOICE CHANNELSにあるGeneralに参加して から以下の画像のように !startと打ってください。 するとGeneralに参加したメンバを勝手に2つのチームに分けてくれます。 f:id:ryo_udon:20190407113427p:plain

!teams (2020/07/17  追記 )

最初から追加していた機能なのにこちらのブログで紹介するのを忘れていたので追記します。

TeamMakerにはチーム数を指定して、チーム分けをする機能があります。

コマンドは簡単

!teams (分けたいチームの数)

でチーム分けができます。

!men (2020/07/17 追記)

こちらもまたまた最初から追加しているのに紹介するのを忘れておりました。

チームの数の他に、一チームあたりの人数でチーム分けをする機能があります。

!men (人数)

でチーム分けができます

TeamMaker追加方法 / How to invite TeamMaker

家庭用PC(Windows, Macにてインストールする場合)

基本的にはいろいろなブログで掲載されている情報の通り、DeveloperサイトでBotを作成したあと、自分のサーバに追加してください。

その後、Botのtokenを取得し、TeamSetting.jsonというファイルに追記してください。 このGithubにはsampleとしてSampleSetting.jsonというファイルがSettingディレクトリに 入っていますので、その名前を変更してしてください。

TeamSetting.json

{
    "F1ileName":"TeamSetting.json",
    "Token":"---your token----",
    "ServerName":"---your server---",

    "MainChannel":"General",
    "Channel1":"General",
    "Channel2":"Channel2",

    "Group1":"General",
    "Group2":"Group2"
}

基本的に編集が必要なのはこのファイルだけです。 頭から説明すると、

{
    "FileName":"TeamSetting.json",      // この設定ファイルの名前
    "Token":"---your token---",         // ここにDiscord.comにて作成したBotへのアクセスtokenを追加してください。
    "ServerName":"---your server---",   // ここにこのbotを参加させるserverの名前を入れてください。TeamMakerはこのサーバーのみを見に行きます

    "MainChannel":"General"            // チーム分けをする際に最初に全員に入っていてもらうvoice channnelです。
}

ここで記載しなかったものについては現在、整備中のものですので気にしないでください。 (今、releaseとdevelopにブランチを分けています.もう少々お待ち下さい)

ここまでくれば後は簡単です。お使いのPCからコマンドで

sudo pip install discord.py

でdiscord.pyをインストールしたあと、

python BotBase.py

を実行すればTeamMaker Botを起動することができます。 このTeamMaker.py BotBase.pyはどのディレクトリからでも実行ができます。

もし、これで実行できない場合は

  • tokenが間違っていないか

  • AnaCondaなどを使わず、通常のPythonを利用する

などを試してみてください。 二個目についてはどうやらDiscord.pyがソケット通信を利用していることが原因で、 Discord.comに接続できないことがあるようです。

ちなみに私はMacにAnacondaをインストールして無事に動きましたが、

あとで説明するRasbianでminicondaを入れた際にはいろいろとネットワークの

設定を頑張りましたが、うまく接続させることができませんでした。

常時稼働環境の作成 / How to run this bot with raspberry pi

現在、私はこのbotを自分のPCからではなく、Raspberry pi 2B+にて常時稼働させています。

PCからでも問題はないのですが、PCそのものをネットワークのつながらないところに持っていくことがあったり、

また、そもそも自分のPCに常時動いてほしくないというワガママから、家の中に眠っていたRaspberry Pi を引っ張りだすことにしました。

ただ、以外と落とし穴が多く存在していたので、念の為情報を残したいと思います。

まず、目指すべき環境は、

**"Raspberry Pi + Python 3.6 ~ + Discord.py"**

になります。

本来であればminicondaなどを入れて環境を作りたいと思ったのですが、 そのせいで逆に環境構築に時間がかかるというなんとも悲しい経験をしたので、ここでは一番シンプルな方法を紹介します。

まず、RasbianのイメージをmicroSDに焼きます。 ここでRasbianをチョイスした理由は、Raspberry Piユーザとしては身近だったことと、 どうやらDiscord.pyを簡単に動かせるようだという前情報を入手したからです。

実際、Lubuntu, Xubuntuなどで試してうまくDiscord.comに接続できなかったため、現在はRaspbianで運用しています。 (実際は全く違う理由であることに気づいたのですが、それは後ほど説明します)

microSDへのイメージの焼付方法ですが、以下のページを参考にしました。

基本的にそんなに難しいことはないのでこの流れに沿って操作するのみです。 もしバックアップが取りたいという方がいれば、自分のRaspberry Piの設定を.imgに書き出すという方法があります。リンク

イメージが書き込めたらそれをRaspberry Piに差し込んで、起動します。 Raspbianの設定についてはユーザ名やパスワードを設定するだけなので、ここでは省略します。

次にPythonの実行環境を整えていきます。 RaspbianにはデフォルトでPython 3.5がインストールされていますが、Discord.pyの推奨は3.6なためアップグレードを行います。 アップグレード方法は以下のページを参考にして、3.6.5を入れました。

ここまでくれば後少しです。 Ctrl + Alt + t でターミナルを開いていただき、

sudo pip3 install discord.py

と打ち込んでください。これで環境構築は終了です!

後は、Git cloneなり、USBメモリで適当なディレクトリにこのTeamMakerを入れていただき、

     python3 BotBase.py

と実行していただければこれで常時稼働でこのBotを動かすことができます。

TeamMaker Botの構成

TeamMakerの構成は基本的に以下の通りです。

├── Setting
│   └── TeamSetting.json  <-- 各サーバ名とDiscord.comで作成したBotのtokenを入力 <br>
├── config
└── src
    ├── InitSetting.py     <-- TeamSetting.jsonを読み込むクラス<br>
    ├── ServerControl.py    <-- サーバ内のメンバのリストなどを取得するクラス<br>
    └── TeamMaker.py    <-- チーム分けを行うクラス + Main() <br>

InitSetting.pyはTokenやサーバ名を登録するクラス ServerControl.pyは登録したサーバ名をもとにメンバのリストとそのID列を取ってきます。 ここではメンバリストがログイン順になっており、Discord APIの中でもそれを基準にIDをふっているようなので、ランダムにチーム分けができるようにID列を取得する際にrandom()を使用してランダムな配列にしています。

ServerControl.py

    def GetChannelUsers(self, channelName):
        members = []
        for server in self.client.servers:
            if server.name == self.serverName:
                for channel in server.channels:
                    if channel.name == channelName:
                        for member in channel.voice_members:
                            members.append(member)
        return members

    def GetListIDs(self, members):
        memberListSize = len(members)
        listIDs = list(range(memberListSize))
        random.shuffle(listIDs)
        return listIDs

最後にTeamMaker.pyが今回の肝になるソースコードになります。 チーム分けの部分はシンプルなのでそれは後で確認いただくとして、基本的なDiscordのBotがどのように動くのかを説明します。

TeamMaker.py


client = discord.Client() # 接続に使用するオブジェクト
initInfo    = INIT_SETTING() #token、サーバ名、Channel名を取得


# ①起動時に通知してくれる処理
@client.event
async def on_ready():
    print('ログインしました')

# ②何かメッセージが送信された際に実行される処理
@client.event
async def on_message(message):
    sendMessage = ""
    sc      = SERVER_CONTROL(client, initInfo.serverName, BOT_NAME)
    members, listIDs = sc.GetMemberAndListIDs(initInfo.mainChannel)
    
    # ここでメッセージを区別
    if message.content.startswith('/neko'):
        reply = 'にゃーん'
        await client.send_message(message.channel, reply) 
    
    # !がついているとコマンドとして扱う
    elif message.content.startswith("!"):
        tm      = TEAM_MAKER(members, listIDs)
        sendMessage = tm.Main(message)
        await client.send_message(message.channel, sendMessage)
   
# Discord.comに接続する
client.run(initInfo.token)

特に難しいことはありません。ただ、tokenをもとにclientがrun()を実行し、Discord.comに接続します。 接続完了後、①の処理に入り、BotがOnlineであることを知らせてくれます。 基本Botはこの状態で待機を続け、何かメッセージが送られた際に②の処理に入り、コマンドの判定をした後に チーム分けをするかを判断し、

 await client.send_message(message.channel, sendMessage)

にてチーム分けの結果が格納された文字列 を以下のように送信しています。

f:id:ryo_udon:20190407123814p:plain
実行結果

TeamMakerの説明は以上です。

/*コードブロックに言語名を表示*/ pre.code:before { content: attr(data-lang); display: inline-block; background: white; color: #666; padding: 3px; position: absolute; margin-left: -10px; margin-top: -30px; } pre.code { padding-top: 30px !important; }