Discord botをpythonで作成
本記事では詳しいことは省いてどんなコードでどんなことができるのか
実際に使用しているbotのコードを以下の三つ紹介します。
コマンド
テキスト読み上げ
ユーザーがVCから落ちた時のメッセージ
■モジュールのインポート
discordとgtts(ffmpeg)はインストールが必要です。
# discord botに必要
import discord
from discord.ext import commands
from discord import app_commands
import asyncio
# 読み上げに必要
from gtts import gTTS
import re
# 必須ではないですが、ランダム要素を使用したいのであれば
import random
# その他
import os
■ボットがどの情報を受け取るか
# 標準的な Intent を有効化
intents = discord.Intents.default()
# メッセージ本文の取得を許可
intents.message_content = True
# サーバーのメンバー情報の取得を許可
intents.members = True
# ボイスチャンネルの入退室やミュート状態の取得を許可
intents.voice_states = True
# 関係ないけど最初の方に定義してください。
vc = None
■コマンドを使用する際の接頭辞を設定
" ! " でなくてもよいです。
後述するスラッシュコマンドに置き換わるのでそんなに気にしなくても大丈夫です。
# コマンドのプレフィックス設定
bot = commands.Bot(command_prefix="!", intents=intents)
■ボットのトークン
discordのdevelopers pageのsettingsのbotの欄にあるので、取得してください。
※絶対に他人に見せないでください。
https://discord.com/developers/
# bot token
BOT_TOKEN = "XXXXXXXXXXXXXXXXX"
# botを起動させます。
# 一番最後に記載してください。
bot.run(BOT_TOKEN)
■起動時に実施
ボットが起動した際にスラッシュコマンドを同期させています。
スラッシュコマンドが不要の方は起動メッセージだけでよいです。
# 起動時のメッセージ
@bot.event
async def on_ready():
try:
synced = await bot.tree.sync()
print(f"{len(synced)} 件のスラッシュコマンドを同期しました。")
except Exception as e:
print(f"同期エラー: {e}")
print(f"{bot.user} 起動しました。")
コマンド
スラッシュコマンドはサーバーに表示される情報なので、変更があった時はボットをサーバーに入れ直す必要があります。
■スラッシュコマンド
/hi
と打つとこんにちはと返ってきます。
discordで/
を打った際に、出てくる名前と、説明を設定します。
# Hi command
@bot.tree.command(
name="Hi",
description="挨拶を返します。"
)
async def hi(interaction: discord.Interaction):
await interaction.response.send_message("こんにちは")
■特定のチャンネルにのみ送信
この場合、スラッシュコマンドを定義してしまうと、誰にでもコマンドの存在がばれてしまうので、!unko
と打つと特定のチェンネルに送信するように設定します。
チャンネルを右クリするとチャンネルIDをコピーと出てくるのでそちらを記載してください。
この場合スラッシュは使用できません。
CHANNEL_ID = 12345678910
@bot.command()
async def unko(channel):
channel = bot.get_channel(CHANNEL_ID)
if channel:
await channel.send("うんこ!")
■ランダムにメッセージを送信
# hoge リスト
hoge_word = [
"hoge1",
"hoge2",
"hoge3",
"hoge4",
"hoge5",
"hoge6",
]
# 合計値の比率で確立を設定
# この場合 hoge6が0.3%で出力されます。
weights = [19.94, 19.94, 19.94, 19.94, 19.94, 0.3]
# hogeコマンド
@bot.tree.command(
name="hoge",
description="hogeがランダムに出力されます。"
)
async def hoge(interaction: discord.Interaction):
result = random.choices(hoge_word, weights=weights, k=1)[0]
await interaction.response.send_message(result)
テキスト読み上げ
読み上げに必要なので、ffmpeg をインストールする必要があります。
https://ffmpeg.org/download.html
全てのチャンネルを読み上げるわけにはいかないので、読み上げるチャンネルを指定して、指定のチャンネルに送られたときのみ読み上げます。
また、指定のVCにいるときにのみ指定のチャンネルを読み上げます。
鍵VCにいるときは鍵チャットを読み上げるように
オープンVCにいるときはオープンチャットを読み上げるように
# OPEN VC1, & OPEN VC2
OPEN_CHANNEL_IDS = {123456789101, 123456789102}
# オープンVCチャット
OPEN_READ_CHANNEL_ID = 123456789103
# 秘密のVC
SECRET_CHANNEL_ID = 123456789104
# 秘密のチャット
SECRET_READ_CHANNEL_ID = 123456789105
# 読み上げ
@bot.event
async def on_message(message):
global vc
await bot.process_commands(message)
if message.author == bot.user:
return
# Botが接続しているVCのチャンネルIDを取得
current_vc_id = None
if bot.voice_clients:
current_vc_id = bot.voice_clients[0].channel.id
# VCごとに読むチャンネルを切り替え
if current_vc_id == SECRET_CHANNEL_ID:
if message.channel.id != SECRET_READ_CHANNEL_ID:
return
elif current_vc_id in OPEN_CHANNEL_IDS:
if message.channel.id != OPEN_READ_CHANNEL_ID:
return
else:
# Botが指定のVCにいない場合は読み上げしない
return
# 読み上げ処理
# URLやスタンプがすべて読まれてしまうので、マッチしたものを置換
if vc and vc.is_connected():
raw_text = message.content
text = re.sub(r"https?://\S+", "[URL省略]", raw_text)
text = re.sub(r":.*:\d*", "[スタンプ]", text)
text = re.sub(r"<@!?(\d+)>", "[メンション]", text)
if not text.strip():
return
tts = gTTS(text=text, lang="ja")
tts.save("speech.mp3")
while vc.is_playing():
await asyncio.sleep(0.5)
vc.play(
discord.FFmpegPCMAudio(
"speech.mp3", options='-filter:a "atempo=2.0"' # 読み上げ速度
)
)
ユーザーがVCから落ちた時のメッセージ
フレンドに回線が弱い人がいるので、落ちたときにすぐ気づけるように書きました。
# WIFI壊れてる画像
IMAGE_URL = "https://images.xxxxxxx.jpg"
# User ID
hoge = 123456789106
# メッセージを送信するチャンネル
CHANNEL_ID = 123456789107
@bot.event
async def on_voice_state_update(member, before, after):
# userを指定してください。
if member.id == hoge and before.channel is not None and after.channel is None:
print(f"{member.name} has left the voice channel.")
# 送信するチャンネルID変数を入れてください
channel = bot.get_channel(CHANNEL_ID)
if channel:
await channel.send(f"{IMAGE_URL} \n回線よわ!w")
最後に
今はChatGPTでコードを聞けば答えてくれるので、こんな記事必要ないかもしれませんが、
誰かの参考になれば幸いです。
参考URLを記載しておきます。