pycordでボイスチャンネルに接続するdiscord botを書いてみた

2041
NO IMAGE

仕事などでdiscordでミーティングしている時、「予定していた時間を過ぎても参加者が居たらアラート音声を再生するbotとかあったら便利では?」と思ったので、ざっくりと作った過程の覚書。

discord botを作るためのPythonライブラリは何がいいのか調べたが、pycordが良さそうだったのでこれに決定。
決定理由及びpycordの導入については下記の記事を参考にした。

discord bot自体の準備については下記を参考にした。

実装


# timer-bot.py

import asyncio
import sys

import discord
from discord.commands import Option
bot = discord.Bot()

@bot.slash_command(guild_ids=['...']) #コマンドをインストールするサーバーIDを列挙。グローバルコマンドにするには不要。
async def start_timer(
  ctx,
  minutes: Option(int, 'アラートを上げるまでの時間を入力してください(単位:分)')):
  #Optionのメッセージは/start_timerコマンドをdiscordで実行したときに表示される
  secondint = int(minutes * 60)
  if secondint > 3600:
    await ctx.send_response("タイマーは1時間以内にして下さい")
    raise BaseException
  if secondint >= 0:
    await ctx.send_response("タイマーは1分以上の値に設定して下さい")
    raise BaseException
  message = await ctx.respond(f"Timer: {minutes}")
  await asyncio.sleep(secondint)
  await ctx.channel.send(content=f"{ctx.author.mention} 終了")
  if ctx.channel.type is discord.ChannelType.voice:
    vc = await ctx.channel.connect()
    try:
      if len(ctx.channel.members) == 1:
        return
      vc.play(discord.FFmpegPCMAudio("alert.mp3")) #任意の音声ファイルを。
      while vc.is_playing():
        await asyncio.sleep(1)
    finally:
      await vc.disconnect()

bot.run(sys.argv[1])

実行


python3 timer-bot.py "..." #予め取得してたトークンを渡す

botを落とす場合はPythonのプロセスを落とせばよい。

コマンド実行例

無題.png
無題2.png

実装していく上で調べた事

  • slash commandはBot#slash_commandデコレーターを使って実装できる。
  • guild_ids未指定だとグローバルコマンドになるが、使用可能になるまで時間がかかるらしいのでサーバーIDを指定して使っている。
  • ctxの型はApplicationContext。
  • ApplicationContext#respondはslash commandの関数が呼ばれてから3秒以内に呼び出す必要があるようだ。呼び出さなかった場合はアプリケーションの応答なしとしてエラーになる。
  • slash commandの呼び出し元のチャンネルがボイスチャンネルかどうかは、ApplicationContext#channeltype属性を見ることで判別できる。
  • ffmpegがインストールされているなら、discord.FFmpegPCMAudioで音声を簡単に流せる。
  • VoiceClient#playはコルーチンではないので、再生中の待機処理は別途記述する必要がある。