みなさん、おはこんばんにちは! NUTMEGの、パラディンです! アドカレ2024の23日を担当します。
NUTMEGでは基本的な連絡はslackを使用していますが、オンラインでのミーティングなどはdiscordを使用しています。
discordの使用頻度は、普段は1on1だったり、突発の作業会がオンラインで開催される場合に使用される程度ですが、長期休みやB4が実務訓練に参加している際は特に高くなります。 ※実務訓練…長岡技術科学大学のカリキュラムで約5ヶ月の長期インターン
サークルでは他の人の活動が目に見えるということは重要なことなので、今回は「slack Incoming WebhooksとdiscordBotを使ってdiscordのボイスチャンネル入退室をslackで確認できる」ようにしました。
コードはこのリポジトリにあります。
Discord Developer Portal にアクセスし、Discordアカウントでログインします。 右上の「New Application」をクリックして、新しいアプリケーションを作成します。 アプリケーションに名前を付けて、「Create」をクリックします。
左側のメニューから「Bot」を選択します。 「Add Bot」ボタンをクリックし、「Yes, do it!」を選択してボットを作成します。 ボットの「Token」を取得します。このトークンは後で使用するので、安全に保管してください。
ボットの設定画面で「Privileged Gateway Intents」セクションのServer Members Intent を有効にします。 変更を保存するために「Save Changes」をクリックします。
「OAuth2」 > 「URL Generator」に移動します。 「Scopes」セクションで bot を選択します。 「Bot Permissions」セクションで以下の権限を選択します:
生成されたURLをコピーし、ブラウザで開いてボットをDiscordサーバーに追加します。
Slack API: Applications にアクセスし、「Create New App」をクリックします。 「From scratch」を選択し、アプリ名とワークスペースを選択して「Create App」をクリックします。
アプリの管理画面で「Incoming Webhooks」を選択します。 「Activate Incoming Webhooks」をオンにします。 「Add New Webhook to Workspace」をクリックし、通知を送りたいチャンネルを選択します。 Webhook URLが生成されるので、これを取得します。このURLはいつでもコピーできるので安心してください。
root
├── .env
├── .gitignore
├── bot.py
├── docker-compose.yml
├── dockerfile
└── requirements.txt
環境変数の設定
DISCORD_TOKEN=....
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/....
リポジトリを公開しているので、環境変数を非公開にするために.envをignoreする
.env
通知機能の実装
import discord
import requests
import os
from dotenv import load_dotenv
# 環境変数をロード
load_dotenv()
# DiscordボットのトークンとSlackのWebhook URLを環境変数から取得
DISCORD_TOKEN = os.getenv('DISCORD_TOKEN')
SLACK_WEBHOOK_URL = os.getenv('SLACK_WEBHOOK_URL')
# Intentsの設定
intents = discord.Intents.default()
intents.voice_states = True # ボイスチャンネルの状態を監視
intents.guilds = True
intents.members = True # メンバー情報を取得
# Discordクライアントの初期化
client = discord.Client(intents=intents)
EXCLUDED_CHANNELS = ['1on1']
def send_slack_message(message):
payload = {
"text": message
}
response = requests.post(SLACK_WEBHOOK_URL, json=payload)
if response.status_code != 200:
print(f"Slack webhook failed with status {response.status_code}: {response.text}")
@client.event
async def on_ready():
print(f'Logged in as {client.user}')
@client.event
async def on_voice_state_update(member, before, after):
if (before.channel and before.channel.name in EXCLUDED_CHANNELS) or (after.channel and after.channel.name in EXCLUDED_CHANNELS):
return
if before.channel is None and after.channel is not None:
# メンバーがボイスチャンネルに参加した
message = f"{member.display_name} がボイスチャンネル 「{after.channel.name}」 に参加しました!"
send_slack_message(message)
# elif before.channel is not None and after.channel is None:
# message = f"{member.display_name} がボイスチャンネル 「{before.channel.name}」 から退出しました!"
# send_slack_message(message)
elif before.channel != after.channel:
message = f"{member.display_name} がボイスチャンネル 「{before.channel.name}」 から 「{after.channel.name}」 に移動しました!"
send_slack_message(message)
if __name__ == "__main__":
client.run(DISCORD_TOKEN)
また、今回は無料かつ常時稼働させる必要があるので自作のクラウドでホスティングをする。 そのために、Dockerでコンテナ化をする。
version: "3"
services:
discobot:
build: ./
container_name: "discobot"
stdin_open: true
tty: true
env_file: ["./.env"]
FROM python:3.11-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
build-essential \
&& rm -rf /var/lib/apt/lists/*
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
CMD ["python", "bot.py"]
Pythonのパッケージを一括インストールできるように、リスト化する
discord.py
requests
python-dotenv
ボイスチャンネル入室のslack通知実装において必須の条件となっていたのが、「常時稼働 & 無料」です。
これを実装するためにNUTMEGの自作クラウドにデプロイする必要があったので、Dockerでコンテナ化をしました。
また、B4が実務訓練に行き、discordの使用頻度が高くなる前に完成させたいという思いがあったのでなるべく早く実装できる方法を模索していました。そこで discord.py というDiscord APIを利用したアプリケーションを作成するのに便利なPythonライブラリがあるということでこれを使用しました。
bot.pyでコメントアウトされている部分がありますが、最初は入質・退室の両方を通知しようと思い実装をしました。 しかし、退出まで通知されると通知量が多くなってしまいslackの通知チャンネルを見たくなくなります。
他の人のdiscord活動を見えるようにすることで、本来の目的である「モチベーションを高めたり」、「一緒に作業すること」ができなくなってしまうので入室のみ通知をとれるようにしました。
NUTMEGのdiscordには2人しか入れない、1on1をするためのチャンネルが存在します。 ここを使うことはそうそうありませんが、プライバシー性が高い話をする際に使用されることが考えられるのでこのチャンネルでの入室通知は取らないことにしました。
想像以上にメンバーからの好評な意見をもらいました。 「通知があると誰がdiscordにいるか分かりやすい!」 「いちいちslackのtimesでdiscord作業会していることを報告しなくてもいい!」
また、明らかにdiscordでの通話しながらの活動が増えた気がします。特に11月はほぼ毎日、誰かがdiscordでの活動をしていました!
きっかけはサークルの活動をより良いものにするという思いなので、これからもwebアプリだけではなく、幅広く開発していきたいですね。
ちなみに、「slackのみんなのtimesをXのタイムラインのような形で見られるようにする」という実装もしたので、1か月後くらいに導入してみての結果を踏まえたブログを書こうと思います!