175 lines
6.9 KiB
Python
175 lines
6.9 KiB
Python
from flask import Flask, request, jsonify
|
|
import logging
|
|
import discord
|
|
from discord.ext import commands, tasks
|
|
from discord import VoiceChannel
|
|
import asyncio
|
|
|
|
app = Flask(__name__)
|
|
app.config['DEBUG'] = True
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Discord Botインスタンスを保持するための変数
|
|
bot_instance = None
|
|
quiz_message_id = None
|
|
|
|
def create_response(error_message=None, success_message=None):
|
|
if error_message:
|
|
logger.error(error_message)
|
|
return jsonify({"error": error_message}), 500
|
|
if success_message:
|
|
logger.info(success_message)
|
|
return jsonify({"message": success_message}), 200
|
|
|
|
@app.route('/join', methods=['POST'])
|
|
def join_via_api():
|
|
if bot_instance is None:
|
|
return create_response(error_message="BOTが初期化されていません")
|
|
|
|
channel_id = request.json.get('channel_id')
|
|
logger.info(f"リクエストされたチャンネルID: {channel_id}")
|
|
|
|
if not channel_id:
|
|
return create_response(error_message="チャンネルIDが必要です")
|
|
|
|
try:
|
|
channel_id = int(channel_id)
|
|
except ValueError:
|
|
return create_response(error_message=f"無効なチャンネルIDです: {channel_id}")
|
|
|
|
channel = bot_instance.get_channel(channel_id)
|
|
if channel:
|
|
logger.info(f"チャンネルが見つかりました: {channel.name}")
|
|
if isinstance(channel, VoiceChannel):
|
|
bot_instance.loop.create_task(channel.connect())
|
|
return create_response(success_message=f'{channel.name}に参加します')
|
|
else:
|
|
return create_response(error_message=f"ID {channel_id} はボイスチャンネルではありません")
|
|
else:
|
|
return create_response(error_message="指定されたチャンネルが見つかりません")
|
|
|
|
@app.route('/leave', methods=['POST'])
|
|
def leave_via_api():
|
|
if bot_instance is None:
|
|
return create_response(error_message="BOTが初期化されていません")
|
|
|
|
if bot_instance.voice_clients:
|
|
for vc in bot_instance.voice_clients:
|
|
bot_instance.loop.create_task(vc.disconnect())
|
|
return create_response(success_message="ボイスチャンネルから切断しました")
|
|
return create_response(error_message="ボイスチャンネルに接続されていません")
|
|
|
|
@app.route('/play', methods=['POST'])
|
|
def play_via_api():
|
|
if bot_instance is None:
|
|
return create_response(error_message="BOTが初期化されていません")
|
|
|
|
filename = request.json.get('filename')
|
|
volume = request.json.get('volume', 100)
|
|
try:
|
|
volume = float(volume) / 100.0
|
|
except ValueError:
|
|
return create_response(error_message="無効な音量値です")
|
|
|
|
if bot_instance.voice_clients:
|
|
for vc in bot_instance.voice_clients:
|
|
audio_source = discord.FFmpegPCMAudio(f'bucket/{filename}', options=f"-filter:a 'volume={volume}'")
|
|
vc.play(audio_source)
|
|
return create_response(success_message=f'再生中: {filename}')
|
|
return create_response(error_message="ボイスチャンネルに接続されていません")
|
|
|
|
@app.route('/start_quiz', methods=['POST'])
|
|
def start_quiz():
|
|
if bot_instance is None:
|
|
return create_response(error_message="BOTが初期化されていません")
|
|
|
|
data = request.json
|
|
intro_audio_name = data.get('intro_audio_name')
|
|
volume = data.get('volume', 100)
|
|
if not intro_audio_name:
|
|
return create_response(error_message="イントロ音源名が必要です")
|
|
|
|
try:
|
|
volume = float(volume) / 100.0
|
|
except ValueError:
|
|
return create_response(error_message="無効な音量値です")
|
|
|
|
if bot_instance.voice_clients:
|
|
for vc in bot_instance.voice_clients:
|
|
if not vc.is_connected():
|
|
return create_response(error_message="ボイスチャンネルに接続されていません")
|
|
|
|
# クイズ回答用のメッセージをVCチャットに送信
|
|
asyncio.run_coroutine_threadsafe(send_quiz_message(vc.channel, intro_audio_name, volume), bot_instance.loop)
|
|
return create_response(success_message=f'イントロ音源再生準備中: {intro_audio_name}')
|
|
return create_response(error_message="ボイスチャンネルに接続されていません")
|
|
|
|
@app.route('/stop_audio', methods=['POST'])
|
|
def stop_audio():
|
|
if bot_instance is None:
|
|
return create_response(error_message="BOTが初期化されていません")
|
|
|
|
if bot_instance.voice_clients:
|
|
for vc in bot_instance.voice_clients:
|
|
if vc.is_playing():
|
|
vc.stop()
|
|
return create_response(success_message="再生を停止しました")
|
|
return create_response(error_message="再生中の音源がありません")
|
|
|
|
async def send_quiz_message(channel, intro_audio_name, volume):
|
|
global quiz_message_id
|
|
button = discord.ui.Button(label="回答", custom_id="quiz_answer")
|
|
view = discord.ui.View()
|
|
view.add_item(button)
|
|
message = await channel.send("クイズが開始されました!", view=view)
|
|
quiz_message_id = message.id
|
|
|
|
# インターバルを設ける
|
|
await asyncio.sleep(5) # 5秒間待機
|
|
|
|
# イントロ音源を再生
|
|
for vc in bot_instance.voice_clients:
|
|
if vc.channel == channel:
|
|
audio_source = discord.FFmpegPCMAudio(f'bucket/{intro_audio_name}', options=f"-filter:a 'volume={volume}'")
|
|
vc.play(audio_source)
|
|
|
|
await disable_button_after_timeout(message)
|
|
|
|
async def disable_button_after_timeout(message):
|
|
await asyncio.sleep(30)
|
|
view = discord.ui.View()
|
|
for action_row in message.components:
|
|
for item in action_row.children:
|
|
item.disabled = True
|
|
view.add_item(discord.ui.Button.from_component(item))
|
|
await message.edit(view=view)
|
|
await message.delete()
|
|
|
|
def run_app():
|
|
app.run(host='0.0.0.0', port=80, use_reloader=False)
|
|
|
|
def set_bot_instance(bot):
|
|
global bot_instance
|
|
bot_instance = bot
|
|
|
|
@bot.event
|
|
async def on_interaction(interaction):
|
|
global quiz_message_id
|
|
global bot_instance
|
|
if interaction.data.get('custom_id') == "quiz_answer":
|
|
if interaction.message.id == quiz_message_id:
|
|
quiz_message_id = None
|
|
await interaction.response.send_message(f"{interaction.user.mention}が回答ボタンを押しました!", ephemeral=False)
|
|
if bot_instance.voice_clients:
|
|
for vc in bot_instance.voice_clients:
|
|
if vc.is_playing():
|
|
vc.stop()
|
|
view = discord.ui.View()
|
|
for action_row in interaction.message.components:
|
|
for item in action_row.children:
|
|
item.disabled = True
|
|
view.add_item(discord.ui.Button.from_component(item))
|
|
await interaction.message.edit(view=view)
|