ACSimBot / app.py
TonyD365's picture
Update app.py
df797a6 verified
Raw
History Blame Contribute Delete
7.7 kB
# 导入自定义 DNS 库
from dns_resolver import dns_manager
# --- 注入 DNS 补丁 ---
# 必须在所有网络连接尝试之前执行
dns_manager.patch_socket()
import os
import discord
import time
from fastapi import FastAPI
import uvicorn
import asyncio
from threading import Thread
from discord import app_commands, ui
# 导入数据库基础类
from mongo import MongoManager
# 初始化数据库管理器
db_manager = MongoManager(os.getenv("MONGO_URL"), "Main")
# 身份组权限列表
#mod = [1357078628969746462, 1357079285113819146, 1436537252317626449, 1357079707539214417, 1357079889160835183]
# --- 1. FastAPI 保活 ---
app = FastAPI()
# 使用显式的方法定义,并使用 JSONResponse 确保兼容性
@app.api_route("/", methods=["GET", "HEAD"])
async def status():
# 使用 JSONResponse 包装,防止 Starlette 误判
return {"status": "hi"}
def run_flask():
# Hugging Face 默认使用 7860 端口
port = int(os.environ.get('PORT', 7860))
uvicorn.run(app, host='0.0.0.0', port=port)
# --- 2. 辅助函数 ---
def format_pings(role_input: str):
pass
# --- 3. Modal 表单定义 ---
class AnnounceModal(ui.Modal):
def __init__(self, channel: discord.TextChannel, ping_roles_str: str = None):
super().__init__(title="New Announcement")
self.channel = channel
self.ping_roles_str = ping_roles_str
announcement_title = ui.TextInput(label="Title", placeholder="Enter title...", style=discord.TextStyle.short)
announcement_body = ui.TextInput(label="Body", placeholder="Enter message...", style=discord.TextStyle.long)
async def on_submit(self, interaction: discord.Interaction):
content = self.announcement_body.value
pings = self.ping_roles_str
if pings: pass
embed = discord.Embed(
title=self.announcement_title.value,
description=content,
color=discord.Color.red()
)
footer = f"\n\n||{pings}||\n\n---\n**Sent by:** ||{interaction.user.mention}||\n**Time:** <t:{int(time.time())}:f>"
embed.description += footer
await self.channel.send(embed=embed)
await interaction.response.send_message(f"✅ Sent to {self.channel.mention}!", ephemeral=False)
class EditAnnounceModal(ui.Modal):
def __init__(self, message: discord.Message, new_ping_roles_str: str = None):
super().__init__(title="Edit Announcement")
self.message = message
self.new_ping_roles_str = new_ping_roles_str
old_title = message.embeds[0].title if message.embeds else ""
old_body = message.embeds[0].description.split("\n\n---")[0] if message.embeds else ""
self.edit_title = ui.TextInput(label="Title", default=old_title, style=discord.TextStyle.short)
self.edit_body = ui.TextInput(label="Body", default=old_body, style=discord.TextStyle.long)
self.add_item(self.edit_title)
self.add_item(self.edit_body)
async def on_submit(self, interaction: discord.Interaction):
content = self.edit_body.value
pings = self.new_ping_roles_str
if pings: pass
new_embed = discord.Embed(
title=self.edit_title.value,
description=content,
color=discord.Color.blue()
)
footer = f"\n\n||{pings}||\n\n---\n**Edited by:** ||{interaction.user.mention}||\n**Time:** <t:{int(time.time())}:f>"
new_embed.description += footer
await self.message.edit(embed=new_embed)
await interaction.response.send_message(f"✅ Updated announcement {self.message.id} !", ephemeral=False)
# --- 4. 机器人主体 ---
class MyBot(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.tree = app_commands.CommandTree(self)
async def setup_hook(self):
await self.tree.sync()
print(f"✅ Slash commands synced")
client = MyBot()
client.db = db_manager
# --- 5. 指令定义 ---
@client.tree.command(name="announce", description="Post announcement")
async def announce(interaction: discord.Interaction, channel: discord.TextChannel, role_ids: str = None):
#if not any(role.id in mod for role in interaction.user.roles):
#await interaction.response.send_message("❌ **Access Denied**", ephemeral=True)
#return
await interaction.response.send_modal(AnnounceModal(channel, role_ids))
@client.tree.command(name="announce_edit", description="Edit announcement")
async def announce_edit(interaction: discord.Interaction, channel: discord.TextChannel, message_id: str, new_role_ids: str = None):
#if not any(role.id in mod for role in interaction.user.roles):
#await interaction.response.send_message("❌ **Access Denied**", ephemeral=True)
#return
try:
message = await channel.fetch_message(int(message_id))
await interaction.response.send_modal(EditAnnounceModal(message, new_role_ids))
except Exception as e:
await interaction.response.send_message(f"❌ Error: {e}", ephemeral=False)
@client.tree.command(name="commands", description="Show all avaliable commands")
async def wismer_commands(interaction: discord.Interaction):
await interaction.response.send_message(
'''**Avaliable Commands**:
`/announce`: Post an announcement.
`/announce_edit`: Edit an announcement.''',
ephemeral=False
)
#ADMIN_LOG_CHANNEL_ID = 1468391869686878455
# 允许调用指令的用户名列表(或者 User ID)
ALLOWED_USERS = ["tonydong365"]
# 另一个独立的函数:负责最后的匿名发送
async def send_anonymous_message(channel, content):
await channel.send(content)
@client.tree.command(name="say", description="idk what is this")
@app_commands.describe(content="idk")
async def secret(interaction: discord.Interaction, content: str):
# 1. 读取并核对用户名
current_user = interaction.user.name
# 检查当前用户是否在允许列表中
if current_user not in ALLOWED_USERS:
# 如果不是特定用户,直接回复一个仅自己可见的消息并结束
# 或者干脆不给任何反馈直接 return
await interaction.response.send_message("This is nothing.", ephemeral=True)
return
# 2. 如果是特定用户,先发送一个极其简短的“瞬时响应”来完成交互
# 这样频道里其他人完全看不见
await interaction.response.send_message("指令已确认...", ephemeral=True)
# 3. 立即清理掉这个“瞬时响应”,不留痕迹
await interaction.delete_original_response()
# 4. 调用另一个函数进行“无关联”发送
await send_anonymous_message(interaction.channel, content)
@client.tree.command(name="hi")
async def hi(interaction: discord.Interaction):
await interaction.response.defer(ephemeral=False)
await interaction.followup.send("hi!")
# --- 6. 启动逻辑 ---
async def start_bot():
token = os.getenv('DISCORD_TOKEN')
while True:
try:
print("正在尝试连接 Discord...")
await client.start(token)
except Exception as e:
print(f"❌ 连接失败: {e},15秒后重试...")
# 报错后尝试关闭客户端,清理 aiohttp session 缓存
try:
await client.close()
except:
pass
await asyncio.sleep(15)
if __name__ == "__main__":
# 启动 Web 保活
t = Thread(target=run_flask)
t.daemon = True
t.start()
# 启动机器人异步循环
try:
asyncio.run(start_bot())
except KeyboardInterrupt:
pass