上传文件至 /
nya~
This commit is contained in:
514
__init__.py
Normal file
514
__init__.py
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
from nonebot import on_command, get_driver
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, MessageSegment, MessageEvent, Event
|
||||||
|
from nonebot.plugin import PluginMetadata
|
||||||
|
from nonebot import logger
|
||||||
|
from fastapi import APIRouter, Request
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
import io
|
||||||
|
import asyncio
|
||||||
|
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
||||||
|
from playwright.async_api import async_playwright
|
||||||
|
|
||||||
|
# -------------------- 插件元信息 --------------------
|
||||||
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
name="maimai helper",
|
||||||
|
description="神秘功能",
|
||||||
|
usage="见 /maihelp",
|
||||||
|
extra={
|
||||||
|
"version": "5.2",
|
||||||
|
"author": "xiaoxin"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# -------------------- 全局配置 --------------------
|
||||||
|
API_BASE = ""
|
||||||
|
HELP_BG_API = ""
|
||||||
|
STATUS_URL_XIN = ""
|
||||||
|
STATUS_URL_SBGA = ""
|
||||||
|
|
||||||
|
# -------------------- 帮助 --------------------
|
||||||
|
async def fetch_background_bytes(retries: int = 3, timeout: int = 10) -> bytes | None:
|
||||||
|
headers = {"User-Agent": "Mozilla/5.0 (MaimaiBot/5.2)"}
|
||||||
|
for _ in range(retries):
|
||||||
|
try:
|
||||||
|
async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client:
|
||||||
|
r = await client.get(HELP_BG_API, headers=headers)
|
||||||
|
if r.status_code == 200 and "image" in r.headers.get("content-type", ""):
|
||||||
|
return r.content
|
||||||
|
except Exception:
|
||||||
|
await asyncio.sleep(0.3)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# -------------------- 字体加载 --------------------
|
||||||
|
def load_font(title_size=38, text_size=24):
|
||||||
|
paths = [
|
||||||
|
"./fonts/msyh.ttc",
|
||||||
|
"msyh.ttc",
|
||||||
|
"/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
|
||||||
|
"/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.otf",
|
||||||
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||||
|
]
|
||||||
|
for p in paths:
|
||||||
|
try:
|
||||||
|
title = ImageFont.truetype(p, title_size)
|
||||||
|
text = ImageFont.truetype(p, text_size)
|
||||||
|
return title, text
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
return ImageFont.load_default(), ImageFont.load_default()
|
||||||
|
|
||||||
|
# -------------------- 帮助图渲染 --------------------
|
||||||
|
def render_help_image(bg_bytes: bytes | None) -> bytes:
|
||||||
|
W, H = 1920, 1080
|
||||||
|
|
||||||
|
# 背景
|
||||||
|
if bg_bytes:
|
||||||
|
try:
|
||||||
|
bg = Image.open(io.BytesIO(bg_bytes)).convert("RGBA")
|
||||||
|
ratio = bg.width / bg.height
|
||||||
|
target = W / H
|
||||||
|
if ratio > target:
|
||||||
|
new_h = H
|
||||||
|
new_w = int(new_h * ratio)
|
||||||
|
else:
|
||||||
|
new_w = W
|
||||||
|
new_h = int(new_w / ratio)
|
||||||
|
bg = bg.resize((new_w, new_h), Image.LANCZOS)
|
||||||
|
left = max((new_w - W) // 2, 0)
|
||||||
|
top = max((new_h - H) // 2, 0)
|
||||||
|
bg = bg.crop((left, top, left + W, top + H))
|
||||||
|
except:
|
||||||
|
bg = Image.new("RGBA", (W, H), (50, 50, 60, 255))
|
||||||
|
else:
|
||||||
|
bg = Image.new("RGBA", (W, H), (50, 50, 60, 255))
|
||||||
|
|
||||||
|
draw = ImageDraw.Draw(bg)
|
||||||
|
title_font, text_font = load_font()
|
||||||
|
|
||||||
|
# 数据:两个列布局
|
||||||
|
sections_left = [
|
||||||
|
("账号相关", [
|
||||||
|
"/bind <二维码字符串> 绑定舞萌状态",
|
||||||
|
"/info 查看简略信息",
|
||||||
|
"/user 查看账号信息",
|
||||||
|
"/fbind <token> 绑定水鱼 token",
|
||||||
|
"/funbind 解绑水鱼 token",
|
||||||
|
]),
|
||||||
|
("状态", [
|
||||||
|
"/网站状态 网站状态",
|
||||||
|
"/舞萌状态 舞萌状态",
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
sections_right = [
|
||||||
|
("成绩相关", [
|
||||||
|
"/up 上传成绩到水鱼",
|
||||||
|
"/del <musicID> 删除成绩",
|
||||||
|
"/upload 上传成绩",
|
||||||
|
]),
|
||||||
|
("其他", [
|
||||||
|
"/unban <时间> 解黑屋(测试)",
|
||||||
|
"/lock <类型> <itemID> 解锁物品",
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
# ====== 绘制标题 ======
|
||||||
|
title = "乌蒙DX神秘功能帮助"
|
||||||
|
bbox = draw.textbbox((0, 0), title, font=title_font)
|
||||||
|
tw = bbox[2] - bbox[0]
|
||||||
|
th = bbox[3] - bbox[1]
|
||||||
|
draw.text(((W - tw) // 2, 80), title, font=title_font, fill=(0, 0, 0))
|
||||||
|
|
||||||
|
# 左右列区域
|
||||||
|
left_x = 160
|
||||||
|
right_x = W // 2 + 60
|
||||||
|
start_y = 200
|
||||||
|
line_gap = 65
|
||||||
|
block_gap = 80
|
||||||
|
|
||||||
|
# ====== 绘制列函数 ======
|
||||||
|
def draw_column(sections, x, y):
|
||||||
|
for sec_title, items in sections:
|
||||||
|
# 标题(加粗效果:描边)
|
||||||
|
draw.text((x - 2, y), sec_title, font=text_font, fill=(0, 0, 0))
|
||||||
|
draw.text((x + 2, y), sec_title, font=text_font, fill=(0, 0, 0))
|
||||||
|
draw.text((x, y - 2), sec_title, font=text_font, fill=(0, 0, 0))
|
||||||
|
draw.text((x, y + 2), sec_title, font=text_font, fill=(0, 0, 0))
|
||||||
|
draw.text((x, y), sec_title, font=text_font, fill=(0, 0, 0))
|
||||||
|
y += line_gap
|
||||||
|
|
||||||
|
# 内容行
|
||||||
|
for line in items:
|
||||||
|
draw.text((x + 40, y), line, font=text_font, fill=(0, 0, 0))
|
||||||
|
y += line_gap
|
||||||
|
|
||||||
|
y += block_gap
|
||||||
|
return y
|
||||||
|
|
||||||
|
# 绘制左右列
|
||||||
|
draw_column(sections_left, left_x, start_y)
|
||||||
|
draw_column(sections_right, right_x, start_y)
|
||||||
|
|
||||||
|
# 输出
|
||||||
|
buf = io.BytesIO()
|
||||||
|
bg.convert("RGB").save(buf, "PNG")
|
||||||
|
buf.seek(0)
|
||||||
|
return buf.getvalue()
|
||||||
|
|
||||||
|
# -------------------- HELP 指令 --------------------
|
||||||
|
help_cmd = on_command("maihelp", aliases={"help", "/help"}, priority=5, block=True)
|
||||||
|
|
||||||
|
@help_cmd.handle()
|
||||||
|
async def _help(event: MessageEvent):
|
||||||
|
try:
|
||||||
|
bg = await fetch_background_bytes()
|
||||||
|
img = render_help_image(bg)
|
||||||
|
await help_cmd.send(MessageSegment.image(img))
|
||||||
|
except Exception as e:
|
||||||
|
await help_cmd.send(f"生成帮助图失败:{e}")
|
||||||
|
|
||||||
|
|
||||||
|
async def call_api(name: str, qq: str, params=None, timeout=20):
|
||||||
|
if params is None:
|
||||||
|
params = {}
|
||||||
|
params["user_qq"] = qq
|
||||||
|
|
||||||
|
url = f"{API_BASE}/{name}"
|
||||||
|
|
||||||
|
# ========= 日志(请求前) =========
|
||||||
|
logger.info(f"[API-REQ] → {name}")
|
||||||
|
logger.info(f"[API-REQ] URL: {url}")
|
||||||
|
logger.info(f"[API-REQ] Params: {params}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
async with httpx.AsyncClient(timeout=timeout, verify=False) as client:
|
||||||
|
r = await client.post(url, json=params)
|
||||||
|
|
||||||
|
# ========= 日志(响应) =========
|
||||||
|
logger.info(f"[API-RESP] {name} status={r.status_code}")
|
||||||
|
logger.info(f"[API-RESP] Raw: {r.text}")
|
||||||
|
|
||||||
|
data = r.json()
|
||||||
|
return data
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[API-ERR] {name} 调用异常: {e}")
|
||||||
|
return {"success": False, "message": f"服务器连接失败:{e}"}
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------- info --------------------
|
||||||
|
info_cmd = on_command("/info", priority=5, block=True)
|
||||||
|
|
||||||
|
@info_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.get_user_id()
|
||||||
|
r = await call_api("info", qq)
|
||||||
|
if not r.get("success"):
|
||||||
|
await info_cmd.send(r.get("message", "未知错误"))
|
||||||
|
return
|
||||||
|
ui = r.get("user_info")
|
||||||
|
if isinstance(ui, dict):
|
||||||
|
lines = [f"{k}: {v}" for k, v in ui.items()]
|
||||||
|
await info_cmd.send("\n".join(lines))
|
||||||
|
else:
|
||||||
|
await info_cmd.send(str(ui))
|
||||||
|
|
||||||
|
# -------------------- 上传成绩 --------------------
|
||||||
|
upload_cmd = on_command("/up", priority=5, block=True)
|
||||||
|
|
||||||
|
@upload_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.get_user_id()
|
||||||
|
r = await call_api("up", qq, {}, timeout=120)
|
||||||
|
await upload_cmd.send(r.get("message", "返回异常"))
|
||||||
|
|
||||||
|
# -------------------- fbind / funbind --------------------
|
||||||
|
fbind_cmd = on_command("/fbind", priority=5, block=True)
|
||||||
|
|
||||||
|
@fbind_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.get_user_id()
|
||||||
|
parts = str(event.get_message()).split()
|
||||||
|
if len(parts) < 2:
|
||||||
|
await fbind_cmd.send("用法:/fbind <token>")
|
||||||
|
return
|
||||||
|
token = parts[1]
|
||||||
|
r = await call_api("fbind", qq, {"token": token})
|
||||||
|
await fbind_cmd.send(r.get("message", "返回异常"))
|
||||||
|
|
||||||
|
funbind_cmd = on_command("/funbind", priority=5, block=True)
|
||||||
|
|
||||||
|
@funbind_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.get_user_id()
|
||||||
|
r = await call_api("funbind", qq)
|
||||||
|
await funbind_cmd.send(r.get("message", "返回异常"))
|
||||||
|
|
||||||
|
# -------------------- del 删除成绩 --------------------
|
||||||
|
del_cmd = on_command("/del", priority=5, block=True)
|
||||||
|
|
||||||
|
@del_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.get_user_id()
|
||||||
|
p = str(event.get_message()).split()
|
||||||
|
if len(p) < 2:
|
||||||
|
await del_cmd.send("用法:/del <musicID>")
|
||||||
|
return
|
||||||
|
# 如果需要 level_id,可后续扩展
|
||||||
|
r = await call_api("delete", qq, {"music_id": p[1]})
|
||||||
|
await del_cmd.send(r.get("message", "返回异常"))
|
||||||
|
|
||||||
|
# -------------------- lock 解锁 --------------------
|
||||||
|
lock_cmd = on_command("/lock", priority=5, block=True)
|
||||||
|
|
||||||
|
@lock_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.get_user_id()
|
||||||
|
p = str(event.get_message()).split()
|
||||||
|
if len(p) < 3:
|
||||||
|
await lock_cmd.send("用法:/lock <类型> <itemID>")
|
||||||
|
return
|
||||||
|
r = await call_api("lock", qq, {"item_type": p[1], "item_id": p[2]})
|
||||||
|
await lock_cmd.send(r.get("message", "返回异常"))
|
||||||
|
|
||||||
|
# -------------------- unban --------------------
|
||||||
|
unban_cmd = on_command("/黑屋", priority=5, block=True)
|
||||||
|
|
||||||
|
@unban_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.get_user_id()
|
||||||
|
p = str(event.get_message()).split()
|
||||||
|
if len(p) < 2:
|
||||||
|
await unban_cmd.send("用法:/unban <时间>(例如 16:30)")
|
||||||
|
return
|
||||||
|
r = await call_api("mai_unban", qq, {"login_time": p[1]})
|
||||||
|
await unban_cmd.send(r.get("message", "开始解黑屋失败"))
|
||||||
|
|
||||||
|
# -------------------- account (list / switch) --------------------
|
||||||
|
acc_cmd = on_command("/acc", priority=5, block=True)
|
||||||
|
|
||||||
|
@acc_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.get_user_id()
|
||||||
|
p = str(event.get_message()).split()
|
||||||
|
if len(p) < 2:
|
||||||
|
await acc_cmd.send("用法:/acc list | switch <index>")
|
||||||
|
return
|
||||||
|
action = p[1]
|
||||||
|
if action == "list":
|
||||||
|
r = await call_api("account", qq, {"action": "list"})
|
||||||
|
if not r.get("success"):
|
||||||
|
await acc_cmd.send(r.get("message", "查询失败"))
|
||||||
|
return
|
||||||
|
|
||||||
|
accounts = r.get("accounts") or r.get("result", {}).get("accounts")
|
||||||
|
active = r.get("active")
|
||||||
|
|
||||||
|
if not accounts:
|
||||||
|
await acc_cmd.send("未绑定任何账号")
|
||||||
|
return
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for i, a in enumerate(accounts):
|
||||||
|
username = a.get("username") or a.get("name") or ""
|
||||||
|
user_id = a.get("user_id")
|
||||||
|
is_active = (str(user_id) == str(active)) if active is not None else False
|
||||||
|
|
||||||
|
if is_active:
|
||||||
|
lines.append(f"*{i+1}.{username}")
|
||||||
|
else:
|
||||||
|
lines.append(f"{i+1}.{username}")
|
||||||
|
|
||||||
|
await acc_cmd.send("\n".join(lines))
|
||||||
|
elif action == "switch":
|
||||||
|
if len(p) < 3 or not p[2].isdigit():
|
||||||
|
await acc_cmd.send("用法:/acc switch <编号>")
|
||||||
|
return
|
||||||
|
idx = int(p[2])
|
||||||
|
r = await call_api("account", qq, {"action": "switch", "index": idx})
|
||||||
|
await acc_cmd.send(r.get("message", "切换返回异常"))
|
||||||
|
else:
|
||||||
|
await acc_cmd.send("未知操作,请使用 list 或 switch")
|
||||||
|
|
||||||
|
# -------------------- user --------------------
|
||||||
|
user_cmd = on_command("/user", priority=5, block=True)
|
||||||
|
|
||||||
|
@user_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.get_user_id()
|
||||||
|
r = await call_api("user", qq)
|
||||||
|
|
||||||
|
if not r.get("success"):
|
||||||
|
await user_cmd.send(r.get("message", "查询失败"))
|
||||||
|
return
|
||||||
|
|
||||||
|
data = r.get("user_info")
|
||||||
|
|
||||||
|
if isinstance(data, dict):
|
||||||
|
msg = "\n".join([f"{k}: {v}" for k, v in data.items()])
|
||||||
|
else:
|
||||||
|
msg = str(data)
|
||||||
|
|
||||||
|
await user_cmd.send(msg)
|
||||||
|
|
||||||
|
sp_cmd = on_command("/sp", priority=5, block=True)
|
||||||
|
|
||||||
|
@sp_cmd.handle()
|
||||||
|
async def _(event: MessageEvent):
|
||||||
|
qq = event.user_id
|
||||||
|
parts = str(event.get_message()).split()
|
||||||
|
|
||||||
|
superusers = get_driver().config.superusers or []
|
||||||
|
is_true_admin = str(qq) in superusers
|
||||||
|
|
||||||
|
# ========== 1. 查询自己 ==========
|
||||||
|
if len(parts) == 1:
|
||||||
|
r = await call_api("permission", qq, {"action": "get"})
|
||||||
|
if not r.get("success"):
|
||||||
|
await sp_cmd.send(r.get("message"))
|
||||||
|
return
|
||||||
|
|
||||||
|
perms = r.get("permissions") or {}
|
||||||
|
enabled = [k for k, v in perms.items() if v == 1]
|
||||||
|
|
||||||
|
if not enabled:
|
||||||
|
await sp_cmd.send("你没有任何权限")
|
||||||
|
else:
|
||||||
|
await sp_cmd.send("拥有以下权限:\n" + "\n".join(enabled))
|
||||||
|
return
|
||||||
|
|
||||||
|
# ========== 2. 查询别人 ==========
|
||||||
|
if len(parts) == 2 and parts[1].isdigit():
|
||||||
|
target = parts[1]
|
||||||
|
r = await call_api("permission", qq, {"action": "get", "user_qq": target})
|
||||||
|
|
||||||
|
if not r.get("success"):
|
||||||
|
await sp_cmd.send(r.get("message"))
|
||||||
|
return
|
||||||
|
|
||||||
|
perms = r.get("permissions") or {}
|
||||||
|
enabled = [k for k, v in perms.items() if v == 1]
|
||||||
|
|
||||||
|
if not enabled:
|
||||||
|
await sp_cmd.send(f"{target} 没有任何权限")
|
||||||
|
else:
|
||||||
|
await sp_cmd.send(f"{target} 拥有以下权限:\n" + "\n".join(enabled))
|
||||||
|
return
|
||||||
|
|
||||||
|
# ========== 3. 修改权限 ==========
|
||||||
|
if len(parts) == 4:
|
||||||
|
op = parts[1]
|
||||||
|
perm = parts[2]
|
||||||
|
target = parts[3]
|
||||||
|
|
||||||
|
if not is_true_admin:
|
||||||
|
await sp_cmd.send("❌ 只有 Bot 超级管理员可以修改权限")
|
||||||
|
return
|
||||||
|
|
||||||
|
if op not in ("add", "del"):
|
||||||
|
await sp_cmd.send("用法:/sp add|del <权限> <QQ>")
|
||||||
|
return
|
||||||
|
|
||||||
|
if perm.lower() == "all" and op == "add":
|
||||||
|
r = await call_api("permission", qq, {
|
||||||
|
"action": "set",
|
||||||
|
"user_qq": target,
|
||||||
|
"perms": {"all": 1}
|
||||||
|
})
|
||||||
|
await sp_cmd.send("已赋予 all 权限" if r.get("success") else r.get("message"))
|
||||||
|
return
|
||||||
|
|
||||||
|
if perm not in ("upload", "up", "del", "unlock", "unban", "charge", "all"):
|
||||||
|
await sp_cmd.send("权限名无效")
|
||||||
|
return
|
||||||
|
|
||||||
|
value = 1 if op == "add" else 0
|
||||||
|
r = await call_api("permission", qq, {
|
||||||
|
"action": "set",
|
||||||
|
"user_qq": target,
|
||||||
|
"perms": {perm: value}
|
||||||
|
})
|
||||||
|
|
||||||
|
await sp_cmd.send("操作成功" if r.get("success") else r.get("message"))
|
||||||
|
return
|
||||||
|
|
||||||
|
await sp_cmd.send("用法:/sp | /sp <QQ> | /sp add|del <权限> <QQ> | /sp add all <QQ>")
|
||||||
|
|
||||||
|
# -------------------- 状态 --------------------
|
||||||
|
site_status_cmd = on_command("网站状态", aliases={"/网站状态"}, priority=5, block=True)
|
||||||
|
|
||||||
|
@site_status_cmd.handle()
|
||||||
|
async def _(event: Event):
|
||||||
|
try:
|
||||||
|
async with async_playwright() as p:
|
||||||
|
browser = await p.chromium.launch()
|
||||||
|
page = await browser.new_page()
|
||||||
|
await page.set_viewport_size({"width": 1280, "height": 720})
|
||||||
|
await page.goto(STATUS_URL_XIN, wait_until="networkidle")
|
||||||
|
await page.wait_for_selector("#app", timeout=10000)
|
||||||
|
full_h = await page.evaluate("document.body.scrollHeight")
|
||||||
|
await page.set_viewport_size({"width": 1280, "height": full_h})
|
||||||
|
img = await page.screenshot(full_page=True)
|
||||||
|
await browser.close()
|
||||||
|
await site_status_cmd.send(MessageSegment.image(img))
|
||||||
|
except Exception as e:
|
||||||
|
await site_status_cmd.send(f"获取网站状态失败:{e}\n{traceback.format_exc()}")
|
||||||
|
|
||||||
|
mai_status_cmd = on_command("舞萌状态", aliases={"/舞萌状态"}, priority=5, block=True)
|
||||||
|
|
||||||
|
@mai_status_cmd.handle()
|
||||||
|
async def _(event: Event):
|
||||||
|
try:
|
||||||
|
async with async_playwright() as p:
|
||||||
|
browser = await p.chromium.launch()
|
||||||
|
page = await browser.new_page()
|
||||||
|
await page.set_viewport_size({"width": 1280, "height": 720})
|
||||||
|
await page.goto(STATUS_URL_SBGA, wait_until="networkidle")
|
||||||
|
await page.wait_for_selector("#app", timeout=10000)
|
||||||
|
full_h = await page.evaluate("document.body.scrollHeight")
|
||||||
|
await page.set_viewport_size({"width": 1280, "height": full_h})
|
||||||
|
img = await page.screenshot(full_page=True)
|
||||||
|
await browser.close()
|
||||||
|
await mai_status_cmd.send(MessageSegment.image(img))
|
||||||
|
except Exception as e:
|
||||||
|
await mai_status_cmd.send(f"获取舞萌状态失败:{e}\n{traceback.format_exc()}")
|
||||||
|
|
||||||
|
# -------------------- 回调路由 --------------------
|
||||||
|
driver = get_driver()
|
||||||
|
app = driver.server_app
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/maimai/callback")
|
||||||
|
async def callback_endpoint(req: Request):
|
||||||
|
try:
|
||||||
|
data = await req.json()
|
||||||
|
except Exception:
|
||||||
|
return {"success": False, "message": "无法解析 JSON"}
|
||||||
|
|
||||||
|
user_qq = data.get("user_qq")
|
||||||
|
message = data.get("message")
|
||||||
|
channel = data.get("channel", "private")
|
||||||
|
group_id = data.get("group_id")
|
||||||
|
|
||||||
|
if not user_qq or not message:
|
||||||
|
return {"success": False, "message": "缺少 user_qq 或 message"}
|
||||||
|
|
||||||
|
bots = nonebot.get_bots().values()
|
||||||
|
sent_any = False
|
||||||
|
for b in bots:
|
||||||
|
try:
|
||||||
|
if channel == "group" and group_id:
|
||||||
|
await b.call_api("send_group_msg", {"group_id": int(group_id), "message": message})
|
||||||
|
else:
|
||||||
|
await b.call_api("send_private_msg", {"user_id": str(user_qq), "message": message})
|
||||||
|
sent_any = True
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not sent_any:
|
||||||
|
return {"success": False, "message": "未能向任何机器人发送消息"}
|
||||||
|
|
||||||
|
return {"success": True}
|
||||||
|
|
||||||
|
app.include_router(router)
|
||||||
Reference in New Issue
Block a user