1
/
5

【Python】ほぼコピペで作れる!discord.pyでおやすみBot を作ってみた



もう寝るつもりだったのに、友達とのおしゃべりが楽しくてついつい長話をしてしまう…
皆さんそんな経験を1度はしたことがあるのではないでしょうか?(あると信じてます)

自制したいけど楽しくてなかなかやめられない…意思もよわよわなのでやめられない…
なのでプログラムに頼ることにしました。

今回はどれだけ会話が盛り上がっていても、設定した時間になったら強制的に通話を終了させるBotをdiscord.pyで作成しました。


--Pythonを書く前に--

Botの作成についてはこちらの記事をご参照ください。


チャンネルIDを取得

まずBotを使用するサーバーのチャンネルIDを取得します。

このIDを使用してユーザーを退出させるボイスチャンネルを指定します。

①botを使用するサーバーのボイスチャンネルを右クリックします。

②「チャンネルIDをコピー」をクリックしてメモ帳に控えておきます。

チャンネルIDはできればコード上で取得したかったのですが、
どうもやり方が分からず泣く泣く画面上で取得しています。


ざっくりとした仕様

  • スラッシュコマンドで処理する
  • 入力形式は「/YYYY-MM-DD hh:mm」
  • ユーザーが指定する時間になったら、ボイスチャンネルに参加しているすべてのユーザーを強制退出させる
  • ボイスチャンネルに参加者がいない場合は何もしない

細かい仕様はコードの説明で書きます。


〜環境〜
・Python 3.10.7
・pip 22.2.2
・discord.py 2.4.0
※環境構築は終っている前提の記事です。


--Pythonを書いていく--

まずは全体のコードをドン。こんな感じです。

import discord

import config
import asyncio
from datetime import datetime as dt

# ⓵チャンネルID
CHANNEL_ID = 1122334455667788990

intents = discord.Intents.all()
client = discord.Client(intents=intents)

# ⓶Bot起動時のメッセージ
@client.event
async def on_ready():
for channel in client.get_all_channels():
if isinstance(channel, discord.TextChannel):
await channel.send('今回は何時に終わるシュコ?終りたい時間を入力するシュコ!(例:/2024-01-01 01:00)')

# メッセージの検知
@client.event
async def on_message(message):
# ⓷/(スラッシュ)コマンドの入力に対して処理をする
if message.content.startswith('/'):
# ボイスチャンネルを取得
channel = client.get_channel(CHANNEL_ID)

# ⓸ボイスチャンネルに参加しているユーザーがいるか
if len(channel.voice_states.keys()) > 0:
userSetTime = message.content.lstrip(message.content[0])
try:
# ⓹ユーザーの入力を datetime型に変換する
endTime = dt.strptime(userSetTime, '%Y-%m-%d %H:%M')

# ⓹現在日時を取得
dt_now = dt.now().strftime("%Y-%m-%d %H:%M:%S")
now = dt.strptime(dt_now, '%Y-%m-%d %H:%M:%S')

# ⓹ユーザーの入力時間と現在時間の差分を計算する
diffTime = 0
if endTime > now:
diffTime = endTime - now
else:
await message.channel.send('未来の日時を入力するシュコ!')

# ⓺残り時間を秒に変換して、非同期処理をさせる
timeLimit = diffTime.total_seconds()
await message.channel.send(userSetTime + '了解シュコ!')
await asyncio.sleep(timeLimit)

# ⓺ボイスチャンネルに参加しているユーザーを強制退出させる
for voiceChannel in channel.guild.voice_channels:
for vcMember in voiceChannel.members:
await vcMember.move_to(None)
await message.channel.send('みんなお休みシュコ~!')
return


# 指定の入力形式以外で入力された場合の処理
except ValueError:
await message.channel.send('/YYYY-MM-DD hh:mm の形式で半角で入力するシュコ!(例:/2024-01-01 01:00)')
else:
await message.channel.send('ボイスチャンネルに参加するシュコ!')
return

# Bot起動
client.run('your token here')


--実際の動作--

このコード実行してBotが起動するとメッセージを送ってくれます!


次にボイスチャンネルから退出させてほしい時間を入力すると、
入力した時間にボイスチャンネルから退出させるようタイマーをセットします!


そして設定した時間になると、Botが自動的にボイスチャンネルから退出させてくれます!
処理が無事終わるとBotからメッセージが送られます!


--コードの説明--

①チャンネルID

ここには記事の初めにDiscordの画面から取得したボイスチャンネルのIDを入れます。


②Bot起動時のメッセージ

ここはユーザーにBotが起動したことを知らせるメッセージを書いています。
client.get_all_channels()でBotが参加しているすべてのチャンネルを取得しています。
しかしこれだとボイスチャンネルも取得してしまうので、
if isinstance(channel, discord.TextChannel):でテキストチャンネルを判定します。discord.TextChannelというのが、iscord内で扱われているチャンネルのタイプですね。
※ボイスチャンネルではメッセージの送信(send())ができないため、
プログラム実行時にエラーとなってしまいます。


③/(スラッシュ)コマンドの入力に対して処理をする

/(スラッシュ)コマンドの判定は、message.content.startswith('/'):で行っています。
ユーザーが入力したメッセージの開始が /(スラッシュ)となっているか判定しています。


④ボイスチャンネルに参加しているユーザーがいるか

channel.voice_states.keys()でボイスチャンネルに参加しているユーザー取得しています。


⑤時間の取得と計算

「ユーザーの設定した時間になった」という判定は、
「現在時間 – ユーザーの設定した時間」を秒に変換して非同期処理をさせることで実現しています。
strptime()strftime()でごちゃごちゃと型を変換していますが、
すべて「現在時間 – ユーザーの設定した時間」をするためです。

ユーザーから現在より過去の日時が入力された場合は、未来の日時を入力するようメッセージを送信します。


⑥非同期処理

非同期処理await asyncio.sleep()に⑤で計算した値をセットすることで、
「〇秒後に処理を実行する」という処理をさせ、
あたかもユーザーの設定した時間に終了したように見せています。

そして設定した秒数が経つと、await vcMember.move_to(None)が実行され、
ボイスチャンネルに参加しているユーザーを順番に退出させていきます。
vcMember.move_to()はユーザーを他のボイスチャンネルに移動させる時にも使いますが、
ここにNoneをセットすることでボイスチャンネルから退出させることができます。


余談

他の実現方法として、task.loop()を使用したやり方があるみたいです。
こちらは〇秒ごとのループ実行によるもので、イメージとしては cronが近いかもしれません。

私が非同期処理を選んだのは、単純にコードが少なそうだったのと、
task.loop()では細かな時間が設定できなくなると考えたからです。
まぁ今回秒の入力は受け付けてないんですがね。
1秒ごとのループ実行にしてしまうと、今回の処理内容だと毎秒現在時間を取得して
ユーザーの設定時間と比較して…という処理が走ることになり、恐らく1秒以内に処理が終わらないため好ましくないと思い今回は採用しませんでした。


--さいごに--

いかがでしたでしょうか?
今回は、時間になったらボイスチャンネルの参加者を強制退出させるBotを作ってみました。
この記事を書いている時に、ああすればよかった、あれが足りてないとか
いろいろ気づいてしまったのですが、まぁ伸びしろということにしたいです。(笑)
それにdiscord.pyはまだまだビギナーなのでいい機会になりました。

今回のBotに限らず、こんなのあったら楽しそう便利そうって思ったものを自分で作れたら
きっと楽しいし嬉しいですよね。
そんなこんなで皆様も良きもの作りライフを。

そういえばBotのアイコンに使わせていただいたロージーが可愛いのでドアップで載せときますね。

ロジカルスタジオではエンジニアを募集しています。

興味を持っていただけたら、是非採用サイトからご応募ください!

PHPエンジニア
即戦力募集中!PHPで世界をちょっとよくしたいエンジニアをWanted!
ロジカルスタジオは、テクノロジーとデザインの視点からクライアントの課題解決をめざす、大阪のクリエイティブプロダクションです。 クライアントの期待を超えて「もっと良くなる、を見つける」のが私たちのスタイル。企画・提案からデザイン制作・システム構築、運用、改善提案をワンストップで行えるのが一番の強みです。近年ではその実績と品質が評価され、案件も急増しています。 代表の古川が掲げる企業理念は「絆を大切に、周りの人を豊かにし、社会に貢献する」。 私たちはこのミッションを推進するため、「新しい技術へのチャレンジ精神」を軸に、「切磋琢磨する仲間」と「働きやすい職場環境」を整え、「成長と可能性を大切にする風土」を育ててきました。 2019年9月に増床し、外部向けのセミナーにも活用できるカンファレンスルームを拡充。スタッフによる公式ブログや、マスコットキャラクター「ロージー&カール」によるTwitterなど、情報発信も強化しています。 可能性の芽をすくい上げられるこの場所を、より大きくしていきたい。 私たちと一緒に、このビジョンを実現しませんか。
株式会社ロジカルスタジオ


Invitation from 株式会社ロジカルスタジオ
If this story triggered your interest, have a chat with the team?
株式会社ロジカルスタジオ's job postings
6 Likes
6 Likes

Weekly ranking

Show other rankings
Like 古中 友花's Story
Let 古中 友花's company know you're interested in their content