Eat, Play, Nap and Code

食とあそびと昼寝とプログラミング学習

Discordで音声チャンネル内のユーザーをランダムで指名するBotを作った

f:id:eatplaynap329:20210818083151p:plain

はじめに

こんにちは。ここ2週間ほど週報をサボってしまったんですが、この間はフィヨルドブートキャンプのプラクティスを一時中断しDiscord Botを作っていました。 先週頭に完成し、自分のサーバーとフィヨルドのサーバーに導入してもらい使えるようになったので、bot作りについて軽くまとめてみようかと思います。

もくじ

どんなbot

Discordの音声チャンネルにミュート解除状態で参加している参加者をランダムで指名するbotです。 コマンド!youで1人が指名できます。!you 4のように引数を渡すと引数分の人数が指名できます。 リポジトリは↓

github.com

コードの中身

discordrbというgemを使ってRubyで書きました。 最初は単純な条件分岐で書いていたんですが、有識者リファクタリングしてもらい、今動かしているコードはガード節で書き換えたものになります。

# frozen_string_literal: true

require 'dotenv/load'
require 'discordrb'

bot = Discordrb::Commands::CommandBot.new token: (ENV['TOKEN']).to_s, prefix: '!'

bot.command(:you) do |event, number|
  channel = event.user.voice_channel
  return event.send_message('ボイスチャンネルに入ってからコマンドを実行してください') if channel.nil?
  return event.send_message('ミュートを解除してください') if channel.users.all?(&:self_muted?)

  number = number&.to_i || 1
  return event.send_message('選択人数は正の整数を入れてください') unless number > 0

  unmuted_users = channel.users.reject(&:self_muted?)
  user_names = unmuted_users.map(&:name)
  chosen_users = user_names.sample(number)

  event.send_message chosen_users.join(", ")
end

bot.run

最初に作るDiscordrb::Commands::CommandBotインスタンスがどういう情報を持ってるかが分かると、その後のコードはドキュメントを熟読しなくてもそんなに苦労せずに書けるかなと思います。 私はこのbotを作りはじめて、ようやくbinding.irbを使ってインスタンスの中身を見ることができるようになってきました…。

なんのために作ったか

毎朝Discord上で輪読会を開催しているのですが、毎回司会1名、ドライバー1名、感想の発表者4人を決めるという作業があります。

bot導入前は、共有のHackMD上の、司会・ドライバー・感想発表を決めるRubyのコードの中に参加者が各々自分の名前を入力してもらい、前回の担当者がターミナルからirbを起動し、コードを実行して決めていました。

具体的に言うと↓を司会、ドライバー、発表者分繰り返す感じ。

irb(main):001:0> %w[hirono yamamori otomo matsunaga makihara].sample
=> "matsunaga"

この決め方には下記のような問題がありました。

  1. 毎回書きこむのが面倒
  2. 絶対誰かが書き忘れる
  3. 前回のコードをコピペするとその場にいない人も当たる
  4. 毎回irbを起動するのが面倒
  5. HackMDの中身がごちゃごちゃする

輪読会が週1くらいの頻度だったら我慢していたのだと思うのですが、平日毎日やっているため、些細なことながらフラストレーションが溜まっていて、なんとかできないかな〜と思ってました。

そんな中、フィヨルドブートキャンプのミートアップにて卒業生のmisosoupさんが、自作サービスでDiscord botを作ったという卒業発表をされているのを聞き、「そうか、Discord上にいる人から選ぶbotを作ればいいのか〜!」と閃き、その翌々日から作り始め大体1週間で完成しました。

大変だったこと

Discord APIの仕様を知ることと、discordrbのドキュメントを読むのがとても大変でした。

さらにdiscordrb人口が少ないため、サンプルコードやStackOverflowでの回答がほとんど見つからなかったのが辛かったです。 あと、スクールのカリキュラム外のことをやっているため、うまく行ってないとき孤独感も強く感じやすいなと思いました。 自分の場合は気持ちが暗くなって何も手につかなくなってしまったため、オンラインカウンセリングを受けたりしてました。受けてすごく気が楽になったので、これから先のプラクティスでも上手に活用していきたいなと思います。

ありがたかったこと

discordrb人口が少なく、抱えている問題を誰に聞けば解決できるのか分からないのが辛かった中、色んな方が手助けしてくれたのがありがたかったです。 特に、Botを公開したその日に、yana_gi (id:yana_g) さんが引数で人数を指定できる機能追加のPR、メンターのu1tnkさんがコード全体のリファクタリングのPRを送ってくださったのがすごく嬉しかったです。

正解は自分で見つけていくしかないんだけど、相手がdiscordrbの専門家かどうかとか、bot作りの経験があるかとか、100%の答えを持っているかどうかに関わらず色んな人に相談してよかったなって思います。

何より毎朝の輪読会で使ってもらえてるのが嬉しく、bot導入前よりずっと便利になったと自分でも思うので、苦労した甲斐があったな〜と思ってます。

これからのこと

このbotの機能拡張案はいろいろ出ていて、人から言われたものをざっとあげると↓のような感じです。

  • 指名対象からbotを除外したい
  • ただの名前の出力ではなく@でメンションされるようにしたい
  • Discordの登録名ではなくニックネームで表示したい
  • helpコマンドが欲しい
  • 何回も指名したいとき複数回コマンドを打つのが面倒なので絵文字の反応とかでコマンドが実行されるようにしたい

現状なくてめちゃくちゃ困ってる機能というわけではないので、また情熱が戻ってきたらやろうかな〜って感じです。

あとdiscord.pyは国内外で活発な活動をしているようなので、次作りたいbotができたら、Pythonを勉強してdiscord.pyで書いてもいいかなと思ってます。

最後に、Bot作りに関わってくださった方、興味を持ってくださった方、本当にありがとうございました!!

Bot作りで参考にしたURL一覧

公式情報

Discord bot作りの大体の流れを把握

GitHub経由でHerokuにデプロイする

秘密情報を環境変数に入れる

コマンドで動くbotにする

Heroku上で動かす

作りたいbotのイメージ作りに参考にした例