Nutmeg advent calendar 2024

slackでの活動推進

slackでの活動推進

はじめに

みなさん、おはこんばんにちは! NUTMEGの、パラディンです! アドカレ2024の23日を担当します。

NUTMEGでは基本的な連絡はslackを使用していますが、オンラインでのミーティングなどはdiscordを使用しています。

discordの使用頻度は、普段は1on1だったり、突発の作業会がオンラインで開催される場合に使用される程度ですが、長期休みやB4が実務訓練に参加している際は特に高くなります。 ※実務訓練…長岡技術科学大学のカリキュラムで約5ヶ月の長期インターン

サークルでは他の人の活動が目に見えるということは重要なことなので、今回は「slack Incoming WebhooksとdiscordBotを使ってdiscordのボイスチャンネル入退室をslackで確認できる」ようにしました。

コードはこのリポジトリにあります。

1. Discord Botの作成

1.1 Discord Developer Portalにアクセス

Discord Developer Portal にアクセスし、Discordアカウントでログインします。 右上の「New Application」をクリックして、新しいアプリケーションを作成します。 アプリケーションに名前を付けて、「Create」をクリックします。

1.2 ボットの作成

左側のメニューから「Bot」を選択します。 「Add Bot」ボタンをクリックし、「Yes, do it!」を選択してボットを作成します。 ボットの「Token」を取得します。このトークンは後で使用するので、安全に保管してください。

1.3 Privileged Gateway Intentsの有効化

ボットの設定画面で「Privileged Gateway Intents」セクションのServer Members Intent を有効にします。 変更を保存するために「Save Changes」をクリックします。

1.4 ボットの権限設定

「OAuth2」 > 「URL Generator」に移動します。 「Scopes」セクションで bot を選択します。 「Bot Permissions」セクションで以下の権限を選択します:

  • View Channels
  • Connect
  • Speak

生成されたURLをコピーし、ブラウザで開いてボットをDiscordサーバーに追加します。

2. SlackでWebhookの設定

2.1 Slackアプリの作成

Slack API: Applications にアクセスし、「Create New App」をクリックします。 「From scratch」を選択し、アプリ名とワークスペースを選択して「Create App」をクリックします。

2.2 Incoming Webhooksの設定

アプリの管理画面で「Incoming Webhooks」を選択します。 「Activate Incoming Webhooks」をオンにします。 「Add New Webhook to Workspace」をクリックし、通知を送りたいチャンネルを選択します。 Webhook URLが生成されるので、これを取得します。このURLはいつでもコピーできるので安心してください。

3. コーディング

ディレクトリ構成

root
  ├── .env
  ├── .gitignore
  ├── bot.py
  ├── docker-compose.yml
  ├── dockerfile
  └── requirements.txt

.env

環境変数の設定

DISCORD_TOKEN=....
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/....

.gitignore

リポジトリを公開しているので、環境変数を非公開にするために.envをignoreする

.env

bot.py

通知機能の実装

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-compose.yml

また、今回は無料かつ常時稼働させる必要があるので自作のクラウドでホスティングをする。 そのために、Dockerでコンテナ化をする。

version: "3"
services:
  discobot:
    build: ./
    container_name: "discobot"
    stdin_open: true
    tty: true
    env_file: ["./.env"]

dockerfile

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"]

requirements.txt

Pythonのパッケージを一括インストールできるように、リスト化する

discord.py
requests
python-dotenv

実装する上での工夫

技術選定

ボイスチャンネル入室のslack通知実装において必須の条件となっていたのが、「常時稼働 & 無料」です。

これを実装するためにNUTMEGの自作クラウドにデプロイする必要があったので、Dockerでコンテナ化をしました。

また、B4が実務訓練に行き、discordの使用頻度が高くなる前に完成させたいという思いがあったのでなるべく早く実装できる方法を模索していました。そこで discord.py というDiscord APIを利用したアプリケーションを作成するのに便利なPythonライブラリがあるということでこれを使用しました。

退出はいらん

bot.pyでコメントアウトされている部分がありますが、最初は入質・退室の両方を通知しようと思い実装をしました。 しかし、退出まで通知されると通知量が多くなってしまいslackの通知チャンネルを見たくなくなります。

他の人のdiscord活動を見えるようにすることで、本来の目的である「モチベーションを高めたり」、「一緒に作業すること」ができなくなってしまうので入室のみ通知をとれるようにしました。

入退室

1on1チャンネルの除外

NUTMEGのdiscordには2人しか入れない、1on1をするためのチャンネルが存在します。 ここを使うことはそうそうありませんが、プライバシー性が高い話をする際に使用されることが考えられるのでこのチャンネルでの入室通知は取らないことにしました。

スクリーンショット 2024-12-23 18.54.28

作ってみて

想像以上にメンバーからの好評な意見をもらいました。 「通知があると誰がdiscordにいるか分かりやすい!」 「いちいちslackのtimesでdiscord作業会していることを報告しなくてもいい!」

また、明らかにdiscordでの通話しながらの活動が増えた気がします。特に11月はほぼ毎日、誰かがdiscordでの活動をしていました!

最後に

きっかけはサークルの活動をより良いものにするという思いなので、これからもwebアプリだけではなく、幅広く開発していきたいですね。

ちなみに、「slackのみんなのtimesをXのタイムラインのような形で見られるようにする」という実装もしたので、1か月後くらいに導入してみての結果を踏まえたブログを書こうと思います!