愛犬アレックスの独り言
🐶「お腹すいたわん、でも、ご主人はdiscordで通話中。困ったわん」
🐶「そうだ!discord経由で連絡すればいいわん!」
🐶「この間ご主人がくれたこのボタン、discordのbotになってるって言ってたわん!」
🐶「押してみよ!」
U・ω・U)ノ凸”ポチッ
bot「🐶<ご飯くれ!」
ワシ「あー忘れてたごめん!!」
🐶「やったー!ご飯だわん」
🐶「でも、毎日これをやるのは面倒だわん」
今日は、🐶が頑張らなくても、
- 特定の時間
- 特定のチャンネルに
- 任意の曜日に
- 任意のメッセージを送信する
botを作るわん!
前提条件・実行環境
- python3以上
- discord.pyのインストール
- disocrdでのアプリ作成・TOKENなどの取得
- botの権限周りの設定が完了している
- 投稿日現在は機能しているが、discordAPIのアップデートによる仕様変更の可能性あり
上記の環境設定が完了していることを前提とします。
階層構造
├── scheduler.py
└── .env
コードの内容
.env
DISCORD_BOT_TOKEN='自分のTOKEN。公開してはいけない'
DEFAULT_CHANNEL_ID='デフォルトで設定しておくchannelのid'
※.envは公開しないでください!
scheduler.py
import datetime
import schedule
import time
import discord
from dotenv import load_dotenv
import os
import asyncio
# .envファイルを読み込みます
load_dotenv()
TOKEN = os.getenv('DISCORD_BOT_TOKEN')
DEFAULT_CHANNEL_ID = int(os.getenv('DEFAULT_CHANNEL_ID'))
# 基本的な設定
intents = discord.Intents.default()
intents.messages = True
client = discord.Client(intents=intents)
# botの起動と同時に走る関数
@client.event
async def on_ready():
print(f'Logged in as {client.user}') # ログインしたユーザーの名前を出力
await send_message("起動しました", DEFAULT_CHANNEL_ID)
# メッセージを送るための基本的な関数
async def send_message(msg, channel_id):
try:
channel = client.get_channel(channel_id)
if channel:
await channel.send(msg)
print(f'Message sent to channel {channel.name}')
else:
print(f'Channel with ID {channel_id} not found.')
except Exception as e:
print(f'Error sending message: {e}')
# job通知を非同期で実行
async def job(msg, channel_id):
now = datetime.datetime.now()
print(str(now) + " 通知したよ")
await send_message(str(now) + " : " + msg, channel_id)
# 曜日の判定
def schedule_job(msg, weekdays, channel_id):
now = datetime.datetime.now()
if now.weekday() in weekdays:
client.loop.call_soon_threadsafe(asyncio.create_task, job(msg, channel_id))
# スケジュール設定 ここの部分で個別に設定していく
schedule.every().day.at("16:13").do(lambda: schedule_job("毎日", range(7), DEFAULT_CHANNEL_ID)) # 0-6: Monday to Sunday
schedule.every().day.at("16:13").do(lambda: schedule_job("火曜日", [1], DEFAULT_CHANNEL_ID)) # 1: Tuesday
schedule.every().day.at("16:13").do(lambda: schedule_job("スケジュール", range(5), DEFAULT_CHANNEL_ID)) # 0-4: Monday to Friday
# スケジュールを実行する関数
def run_schedule():
while True:
schedule.run_pending()
time.sleep(60) # 60秒に一度判定を行う
# スケジュール実行を別スレッドで行う
import threading
schedule_thread = threading.Thread(target=run_schedule)
schedule_thread.start()
# ボットの起動
client.run(TOKEN)
詳細説明
このPythonスクリプトは、Discordボットを使用して定期的なメッセージ送信を管理するものです。以下では、スクリプトの各部分について詳細に説明します。
1. ライブラリのインポートと環境変数の読み込み
import datetime
import schedule
import time
import discord
from dotenv import load_dotenv
import os
import asyncio
-
datetime
,schedule
,time
,discord
: 時間処理、スケジューリング、Discord API、環境変数の操作に必要なライブラリをインポートします。 -
load_dotenv()
,os.getenv()
:.env
ファイルから環境変数を読み込みます。DISCORD_BOT_TOKEN
とDEFAULT_CHANNEL_ID
がここで使用されています。
2. Discordクライアントのセットアップ
# 基本的な設定
intents = discord.Intents.default()
intents.messages = True
client = discord.Client(intents=intents)
-
discord.Client
インスタンスを作成し、イベントを処理するために必要な設定を行います。メッセージの送受信を有効にしています。
3. イベントハンドラーの定義
# botの起動と同時に走る関数
@client.event
async def on_ready():
print(f'Logged in as {client.user}') # ログインしたユーザーの名前を出力
await send_message("起動しました", DEFAULT_CHANNEL_ID)
-
on_ready()
関数は、Discordにボットがログインし準備が完了したときに実行されます。send_message()
を使用して指定されたチャンネルにメッセージを送信します。
4. メッセージ送信のための関数
# メッセージを送るための基本的な関数
async def send_message(msg, channel_id):
try:
channel = client.get_channel(channel_id)
if channel:
await channel.send(msg)
print(f'Message sent to channel {channel.name}')
else:
print(f'Channel with ID {channel_id} not found.')
except Exception as e:
print(f'Error sending message: {e}')
-
send_message()
関数は、指定されたチャンネルIDにメッセージを非同期で送信します。チャンネルが見つからない場合やエラーが発生した場合に例外を処理します。
5. スケジュール関数と非同期ジョブ
# job通知を非同期で実行
async def job(msg, channel_id):
now = datetime.datetime.now()
print(str(now) + " 通知したよ")
await send_message(str(now) + " : " + msg, channel_id)
# 曜日の判定
def schedule_job(msg, weekdays, channel_id):
now = datetime.datetime.now()
if now.weekday() in weekdays:
client.loop.call_soon_threadsafe(asyncio.create_task, job(msg, channel_id))
-
job()
関数は非同期で実行され、指定されたメッセージとチャンネルIDでメッセージを送信します。 -
schedule_job()
関数は、特定の曜日にジョブをスケジュールするために使用されます。schedule.every().day.at()
で指定された時間に、lambda
を使用して非同期のジョブが実行されます。
6. スケジュールの設定と実行
# スケジュール設定 ここの部分で個別に設定していく
schedule.every().day.at("16:13").do(lambda: schedule_job("毎日", range(7), DEFAULT_CHANNEL_ID)) # 0-6: Monday to Sunday
schedule.every().day.at("16:13").do(lambda: schedule_job("火曜日", [1], DEFAULT_CHANNEL_ID)) # 1: Tuesday
schedule.every().day.at("16:13").do(lambda: schedule_job("スケジュール", range(5), DEFAULT_CHANNEL_ID)) # 0-4: Monday to Friday
-
schedule.every().day.at()
を使用して、特定の時間にスケジュールを設定します。lambda
を使用して、非同期のschedule_job()
関数を実行し、ジョブをスケジュールします。
7. スケジュール実行の管理
# スケジュールを実行する関数
def run_schedule():
while True:
schedule.run_pending()
time.sleep(60) # 60秒に一度判定を行う
# スケジュール実行を別スレッドで行う
import threading
schedule_thread = threading.Thread(target=run_schedule)
schedule_thread.start()
-
run_schedule()
関数は、スケジュールされたジョブが実行されるように定期的にschedule.run_pending()
を呼び出します。 -
threading.Thread
を使用して、スケジュール実行をメインスレッドとは別のスレッドで行います。
8. ボットの起動
# ボットの起動
client.run(TOKEN)
-
client.run()
を使用して、Discordボットを起動します。これにより、Discord APIに接続し、イベントの受信や処理が開始されます。
これらの要素が組み合わさって、このスクリプトは指定されたチャンネルに定期的にメッセージを送信する Discord ボットを実現しています。
終わりに
🐶「やっった!わざわざご主人に連絡する必要なくなった!」
🐶「明日からは空腹に耐えずに済むぜ〜」