プロセカ 選曲bot
サムネ用

はい、かく。ただの自己満をつらつらと...。
こんにちは、ゆめです。
プロセカを始めて令和8年3月30日で2年となります。
この期間で多くの人と出会ったり切ったりでなんやかんや遊ぶメンバーが固定されてきているような気がします。
めんどくさいんで話は直球に。あと敬語難しいし関西弁混ぜます。
botの作成するなんて思っていませんでした。でもできちゃった。なんで作ったんかな...。ってなったからまとめることにしました。
使ってるパソコンとか環境について
パソコン:MacBook Air
CPU:Apple M1
メモリ:8 GB
プログラミング言語:Python 3.14
開発環境:PyCharm
途中から「プログラミング言語」とか「開発環境」とか何かいてるんやろって思った人は、Pythonっていう言語(言葉)をPyCharmっていうノートに書き殴ってbotを作ったって思っといてください。
作ることになったきっかけ
かかんでいいと思ったけど、やっぱいるよね。
FFさんとチャレライの選曲botほしいって話してたから!!!!!!!
理由なんてないよ。こんなもん。
プロセカのおまかせで選曲してるといい感じのレベルってなかなか選ばれなくって...。
MASTERの32とかやっばいのくるんよなぁああああああ
レベルと難易度を指定できるbot作ってみようってなりました。
botの中身
以下、ソースコード(ノートに書き殴った言語)
import discord
from discord.ext import commands
import json
import random
# 1. ボットの準備
intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix='!', intents=intents)
# ユーザーごとの回数を記録する辞書
user_counts = {}
# 固定したいチャンネルのID
TARGET_CHANNEL_ID = [チャンネルのID, チャンネルのID]
# 2. 起動確認
@bot.event
async def on_ready():
print(f'🍳 もやしいため({bot.user})がシャキシャキに仕上がりました!')
# 3. メッセージが送られた時の処理
@bot.event
async def on_message(message):
if message.author == bot.user:
return
if message.channel.id not in TARGET_CHANNEL_ID:
return
# --- 1. !help コマンド ---
if message.content == '!help':
help_msg = (
"📖 **ボット「もやしいため」取扱説明書(2026年3月23日更新)**\n"
"━━━━━━━━━━━━━━━━━━\n"
"🎸 **基本の抽選**\n"
"┣ `!music` : Lv.30以上の全曲からランダム\n"
"┗ `!music [Lv]` : 指定したLvからランダム (例: `!music 26`)\n\n"
"🎯 **高度な抽選**\n"
"┣ `!music [Min] [Max]` : 範囲指定 (例: `!music 27 29`)\n"
"┗ `!music [Lv] [難易度]` : 難易度絞り込み\n"
" (例: `!music 31 m` → MASTERの31のみ)\n"
" ※難易度は `e`(EXP), `m`(MAS), `a`(APE) で指定OK!\n\n"
"📊 **データ確認**\n"
"┗ `!status` : 現在のレベル別・難易度別の登録曲数を確認\n"
"━━━━━━━━━━━━━━━━━━\n"
"🍳 *今日もシャキシャキに叩こう!*"
)
await message.channel.send(help_msg)
return
# --- !status コマンド ---
if message.content == '!status':
try:
with open('songs.json', 'r', encoding='utf-8') as f:
data = json.load(f)
all_songs = data['music_list']
diff_groups = {"EXPERT": {}, "MASTER": {}, "APPEND": {}}
for s in all_songs:
diff = s['difficulty'].strip().upper()
lv = s['level']
if diff not in diff_groups: diff_groups[diff] = {}
diff_groups[diff][lv] = diff_groups[diff].get(lv, 0) + 1
status_msg = "🍳 **ボット「もやしいため」お品書き内訳**\n━━━━━━━━━━━━━━\n"
for diff_name in ["EXPERT", "MASTER", "APPEND"]:
counts = diff_groups[diff_name]
if not counts: continue
diff_total = sum(counts.values())
icon = "🎸" if diff_name == "EXPERT" else "🎹" if diff_name == "MASTER" else "⌨️"
status_msg += f"{icon} **{diff_name}**({diff_total}曲)\n"
for lv in sorted(counts.keys()):
status_msg += f"・Lv.{lv}: {counts[lv]}曲\n"
status_msg += "\n"
status_msg += "━━━━━━━━━━━━━━"
await message.channel.send(status_msg)
return # statusが実行されたらここで終了
except Exception as e:
await message.channel.send(f"エラー:{e}")
return
# --- 3. !music コマンド ---
if message.content.startswith('!music'):
user_id = message.author.id
if user_id not in user_counts:
user_counts[user_id] = 0
user_counts[user_id] += 1
my_count = user_counts[user_id]
try:
parts = message.content.split()
with open('songs.json', 'r', encoding='utf-8') as f:
data = json.load(f)
all_songs = data['music_list']
selected_diffs = []
for p in parts:
p_low = p.lower()
if p_low in ["master", "m"]:
selected_diffs.append("MASTER")
elif p_low in ["expert", "e"]:
selected_diffs.append("EXPERT")
elif p_low in ["append", "a"]:
selected_diffs.append("APPEND")
if len(parts) >= 3 and parts[1].isdigit() and parts[2].isdigit():
min_lv, max_lv = int(parts[1]), int(parts[2])
songs = [s for s in all_songs if min_lv <= s['level'] <= max_lv]
msg_type = f"📂 **Lv.{min_lv} ~ Lv.{max_lv}**"
elif len(parts) >= 2 and parts[1].isdigit():
target_lv = int(parts[1])
songs = [s for s in all_songs if s['level'] == target_lv]
msg_type = f"🎯 **Lv.{target_lv}限定**"
else:
songs = [s for s in all_songs if s['level'] >= 30]
msg_type = "🎵 **Lv.30以上ランダム**"
if selected_diffs:
songs = [s for s in songs if s['difficulty'].strip().upper() in selected_diffs]
msg_type += f" 【{', '.join(selected_diffs)}】"
if not songs:
await message.channel.send("対象の曲が見つかりませんでした。")
return
chosen = random.choice(songs)
comment = "フルコン目指してがんばろう!"
if my_count == 3:
comment = "✨ あなたのガチャ3回目!"
elif my_count == 7:
comment = "🍀 ラッキー7回目!得意な曲が出るといいね!"
elif my_count == 39:
comment = "🥗 39(ミク)回目!もやしもネギも大好きだよ!"
elif my_count >= 10:
comment = f"🔥 あなたの累計{my_count}回目!"
reply = (
f"{msg_type}\n"
f"━━━━━━━━━━━━━━\n"
f"曲名: **{chosen['title']}**\n"
f"難易度: {chosen['difficulty']}\n"
f"レベル: {chosen['level']}\n"
f"━━━━━━━━━━━━━━\n"
f"{comment}"
)
await message.channel.send(reply)
except Exception as e:
await message.channel.send(f"エラーが発生しました:{e}")
# 4. ボットを動かす
bot.run('トークン')
ソースコードの解説いる?これ読んでる人そこまでいらんやろ!!!!!!!
Geminiちゃんに聞いたらなんでも答えてくれるよ。これつくったのもほぼGeminiちゃんだよ。
このソースコードの中身ちょっと変えてるからそこだけ。
鯖のチャンネルIDとbotのトークンはセキュリティの都合上消してます。
botはこれだけでは終わらなくてmusic_listも作ってます。ランダムに選曲するってなるとリストないとだめなんです。
アルファベットいやな人向けに書くと...。
曲のくじ引きをするのに、くじを入れる箱とくじの紙を作ったって感じ
イメージ

これ作ったのが一番大変やった...。
これ貼るか迷ったんだけど全部貼ったらすごいことになるから流石にやめとく。
省略して載せるとこんな感じ
{
"music_list": [
{"title": "オーダーメイド", "difficulty": "EXPERT", "level": 21},
{"title": "君の夜をくれ", "difficulty": "EXPERT", "level": 21},
{"title": "Where shall we go?", "difficulty": "EXPERT", "level": 21},
{"title": "彗星ノ銀河", "difficulty": "EXPERT", "level": 21},
{"title": "レイヤーノート", "difficulty": "EXPERT", "level": 21},
{"title": "余花にみとれて", "difficulty": "EXPERT", "level": 21},
{"title": "回る空うさぎ", "difficulty": "EXPERT", "level": 21},
{"title": "あなたの空が泣くのなら", "difficulty": "EXPERT", "level": 21},
{"title": "Tell Your World", "difficulty": "EXPERT", "level": 22},
{"title": "ラムネ", "difficulty": "MASTER", "level": 29},
{"title": "カラフルファンデーション", "difficulty": "MASTER", "level": 29},
{"title": "透明エレジー", "difficulty": "MASTER", "level": 30},
{"title": "ペンタトニック", "difficulty": "MASTER", "level": 30},
{"title": "ネクラチューンサーカス", "difficulty": "APPEND", "level": 37},
{"title": "0.0000034", "difficulty": "APPEND", "level": 37},
{"title": "怪獣になりたい", "difficulty": "APPEND", "level": 38}
]
}
これ最初100行くらい手で打ってたの本当に頭悪かった。現段階で一番下の } が1431行目にあるから察して。データ飛んだら泣く。
途中からこのサイトとGeminiちゃん使って書いたらめっちゃ楽だった。ありがとう。
bot作ってる時に起こったトラブル
エラーなんて当たり前
全角スペース入れちゃった♡
1番のトラブルは、曲数が1曲足りないとか3曲足りないってことが発覚した時かな。あれは泣いたね。
曲数が足りないっていうのは、エラーじゃないから間違ってる場所がわからないってこと!
上から順番に探すしかないんです。修行かな...。
足りない曲を一緒に探してくれたFFの方、ほんとうにありがとうございました。
まじで見つかってよかった。
さいごに
botの起動テストに付き合ってくれた2人と曲が足りない時に一緒に探してくれたFFの方、そしてこのbotを受け入れてくれた鯖主さんありがとうございます。
これからもうちのbotをみんなに使ってもらえたら嬉しいな。
機能とか説明はGeminiちゃんに聞くのが一番だと思います。
bot作成の流れも今回はGeminiちゃんに聞いて作りました。
質問あったらとりまGeminiちゃんに聞いて
ここまで読んでくれてありがとうございました。