「ボイスチャット(VC)で友達と話していて、ついつい寝落ちしてしまった…」
そんな悩みを解決する、指定した時間後に自動でVCから退出させてくれるDiscord Botの作り方を、ソースコード付きで解説します。
自分で時間を設定するだけでなく、他のメンバーのタイマーを設定する機能もあるので、サーバーの管理者にも便利なBotです。
どんな機能が使えるの?
- /leave [分]
自分自身に退出タイマーを設定します。[分]
で指定した時間後に、自動でVCから退出します。 - /cancel
設定した退出タイマーをキャンセルします。 - /remaining
タイマーの残り時間を確認します。 - /forceleave [対象者] [分]
サーバー内の他のメンバーに対して退出タイマーを設定します。
準備するもの
- Python環境
PCにPythonがインストールされている必要があります。 - discord.pyライブラリ
- BOTトークン
Discord Developer Portalで自分のBotを作成し、トークンを取得します。
Python環境の構築、BOTトークンの取得方法は以下の記事で紹介しています。
実行ファイルの作成
今回はWindows11環境でのセットアップ解説です。
エクスプローラーを開き、任意のフォルダを作りましょう。
ユーザーフォルダの直下がおすすめです。

フォルダを開いて、新規作成>テキストドキュメントを作成します。
ファイル名もわかりやすいもので構いません。(今回はvcTimerとしています)

ダブルクリックをするとメモ帳が開きます。
以下のソースコードをコピー&ペーストしてください。
一番下にあるbot.run('あなたのBOTトークン')
の部分を、ご自身で取得したトークンに書き換えて保存してください。
import discord
from discord.ext import commands
from discord import app_commands
import asyncio
import time
intents = discord.Intents.default()
intents.guilds = True
intents.voice_states = True
intents.messages = True
intents.message_content = True
bot = commands.Bot(command_prefix=commands.when_mentioned_or("/"), intents=intents)
timers = {}
time_tracker = {}
auto_leaving = set()
@bot.event
async def on_ready():
print(f'ログイン完了: {bot.user.name}')
print(f'参加中のサーバー数: {len(bot.guilds)}')
await bot.tree.sync()
print("スラッシュコマンドが同期されました。")
@bot.tree.command(name="leave", description="指定した分後にVCから退出します。")
async def leave(interaction: discord.Interaction, minutes: int):
member = interaction.user
if interaction.guild is None:
for guild in bot.guilds:
member_in_guild = guild.get_member(member.id)
if member_in_guild and member_in_guild.voice:
if guild.me.guild_permissions.move_members:
if member.id in timers:
timers[member.id].cancel()
await interaction.response.send_message(
f"{member.mention} さん、{minutes}分後に {guild.name} のVCから退出します。"
)
timers[member.id] = asyncio.create_task(schedule_leave(member_in_guild, minutes, interaction))
time_tracker[member.id] = time.time() + (minutes * 60)
return
else:
await interaction.response.send_message("BOTに『メンバーを移動』する権限がありません。")
return
await interaction.response.send_message("どのサーバーにもVC接続が見つかりませんでした。\nサーバーに『VC退出タイマー』が参加している必要があります。")
return
if member.voice:
if interaction.guild.me.guild_permissions.move_members:
if member.id in timers:
timers[member.id].cancel()
await interaction.response.send_message(f"{member.mention} さん、{minutes}分後にVCから退出します。")
timers[member.id] = asyncio.create_task(schedule_leave(member, minutes, interaction))
time_tracker[member.id] = time.time() + (minutes * 60)
else:
await interaction.response.send_message("BOTに『メンバーを移動』する権限がありません。")
else:
await interaction.response.send_message("VCに接続してからコマンドを使用してください。")
@bot.tree.command(name="cancel", description="設定されたVC退出タイマーをキャンセルします。")
async def cancel(interaction: discord.Interaction):
if interaction.user.id in timers:
timers[interaction.user.id].cancel()
del timers[interaction.user.id]
del time_tracker[interaction.user.id]
await interaction.response.send_message("退出タイマーをキャンセルしました。")
else:
await interaction.response.send_message("設定されている退出タイマーはありません。")
@bot.tree.command(name="remaining", description="設定されたVC退出タイマーの残り時間を確認します。")
async def remaining(interaction: discord.Interaction):
if interaction.user.id in time_tracker:
remaining_time = time_tracker[interaction.user.id] - time.time()
await interaction.response.send_message(f"{interaction.user.mention} さん、残り時間: {int(remaining_time // 60)} 分 {int(remaining_time % 60)} 秒")
else:
await interaction.response.send_message("現在、設定されている退出タイマーはありません。")
@bot.tree.command(name="forceleave", description="他のメンバーを指定してVC退出タイマーを設定します(グループ内のみ)")
@app_commands.describe(
target="タイマーを設定したいメンバー",
minutes="何分後に退出させるか(0で即時)",
force="(上書きしたいときだけ)既存タイマーを強制上書き"
)
async def forceleave(interaction: discord.Interaction, target: discord.Member, minutes: int, force: bool = False):
if interaction.guild is None:
await interaction.response.send_message("このコマンドはサーバー内でのみ使用できます。", ephemeral=True)
return
if not target.voice or target.voice.channel is None:
await interaction.response.send_message(f"{target.display_name} さんはVCに接続していません。", ephemeral=True)
return
if not interaction.guild.me.guild_permissions.move_members:
await interaction.response.send_message("BOTに『メンバーを移動』する権限がありません。", ephemeral=True)
return
if target.id in timers and not force:
await interaction.response.send_message(f"{target.display_name} さんはすでにタイマーを設定済みです。", ephemeral=True)
return
if target.id in timers:
timers[target.id].cancel()
if minutes == 0:
await target.move_to(None)
await interaction.response.send_message(f"{target.mention} さんをVCから退出させました。")
try:
await target.send(f"{interaction.guild.name} で {interaction.user.display_name} さんがあなたをVCから退出させました。")
except discord.Forbidden:
pass
return
await interaction.response.send_message(f"{target.mention} さんを {minutes}分後にVCから退出させます。")
timers[target.id] = asyncio.create_task(schedule_force_leave(target, minutes, interaction, interaction.user))
time_tracker[target.id] = time.time() + (minutes * 60)
async def schedule_leave(member, minutes, interaction):
try:
await asyncio.sleep(minutes * 60)
auto_leaving.add(member.id)
await member.move_to(None)
channel = interaction.channel
await channel.send(f"{member.mention} さんをVCから退出させました。")
del timers[member.id]
del time_tracker[member.id]
except asyncio.CancelledError:
channel = interaction.channel
await channel.send(f"{member.mention} さんのVC退出タイマーがキャンセルされました。")
finally:
auto_leaving.discard(member.id)
async def schedule_force_leave(member, minutes, interaction, caller):
try:
await asyncio.sleep(minutes * 60)
auto_leaving.add(member.id)
await member.move_to(None)
channel = interaction.channel
await channel.send(f"{member.mention} さんをVCから退出させました。")
try:
await member.send(f"{interaction.guild.name} で {caller.display_name} さんがあなたをVCから退出させました。")
except discord.Forbidden:
pass
del timers[member.id]
del time_tracker[member.id]
except asyncio.CancelledError:
channel = interaction.channel
await channel.send(f"{member.mention} さんのVC退出タイマーがキャンセルされました。")
finally:
auto_leaving.discard(member.id)
@bot.event
async def on_voice_state_update(member, before, after):
if member.id in auto_leaving:
return
if member.id in timers:
if before.channel is not None and after.channel is None:
timers[member.id].cancel()
del timers[member.id]
del time_tracker[member.id]
try:
await member.send("VCを手動で退出したため、タイマーがキャンセルされました。")
except discord.Forbidden:
pass
bot.run('あなたのBOTトークン')
エクスプローラーに戻り、
表示>表示>ファイル名拡張子にチェックを入れてください。

名前の変更でtxt部分をpyに変えてください。
これでPythonのファイルになります。

discord.pyライブラリのインストール
画面左下のWindowsスタートボタンを押し、キーボードで「cmd」と入力します。表示された「コマンド プロンプト」をクリックして起動してください。

黒い画面が表示されたら、以下のコマンドを入力し、Enter
キーを押します。
pip install discord.py

ファイルの実行
いよいよファイルの実行です。
先ほど作成したpyファイルをダブルクリックで実行しましょう!

「スラッシュコマンドが同期されました。」と表示されたら成功です!
Botをサーバーに追加する
Discord Developer PortalでBotを選択したページで表示される、APPLICATION IDというものを控えてください。

以下のURLのAPPLICATION IDの箇所を控えた数字と置き換えてください。
https://discord.com/oauth2/authorize?client_id=APPLICATION ID&permissions=3214336&integration_type=0&scope=bot+applications.commands
できたURLにアクセスするとDiscordでBot追加のページが立ち上がります。

指示に従ってサーバーに追加をしてください。
Botを使ってみよう
利用できるコマンドは以下の4つです。
- /leave minutes:
サーバーでもBotとのDMでも利用できます。
DMで送った場合は現在参加しているVCを自動で特定してセットします。 - /cancel
サーバーでもBotとのDMでも利用できます。
セットした退出タイマーをキャンセルします。 - /remaining
サーバーでもBotとのDMでも利用できます。
セットした退出タイマーの残り時間を応答します。 - /forceleave target: minutes:
サーバーでのみ利用できます。
target:で指定したユーザーにminutes:で指定した時間のタイマーを設定します。
「サーバーの管理者権限がない人が寝落ちしている人を落としたい」といった場合に利用できます。
追加オプションでforceをTrueにすることで、現在設定されているものを上書きしてセットできます。
セットするminutesを0にすることで瞬時に退出させることも可能です。
まとめ
お疲れ様でした!これで、VCでの寝落ちの心配が減りますね!!
他のBotもぜひご覧ください!
コメント