mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-07 04:40:00 +08:00
✨ 使用道具允许at目标用户 (#1877)
* ✨ 使用道具允许at目标用户 * ✨ 修改帮助配置项默认值 * ✨ 修改帮助配置项默认值 * 🎨 优化广播方法 * 💡 添加广播方法注释
This commit is contained in:
@@ -37,8 +37,8 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
configs=[
|
configs=[
|
||||||
RegisterConfig(
|
RegisterConfig(
|
||||||
key="type",
|
key="type",
|
||||||
value="normal",
|
value="zhenxun",
|
||||||
help="帮助图片样式 ['normal', 'HTML', 'zhenxun']",
|
help="帮助图片样式 [normal, HTML, zhenxun]",
|
||||||
default_value="zhenxun",
|
default_value="zhenxun",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ from nonebot_plugin_alconna import (
|
|||||||
AlconnaQuery,
|
AlconnaQuery,
|
||||||
Args,
|
Args,
|
||||||
Arparma,
|
Arparma,
|
||||||
|
At,
|
||||||
Match,
|
Match,
|
||||||
|
MultiVar,
|
||||||
Option,
|
Option,
|
||||||
Query,
|
Query,
|
||||||
Subcommand,
|
Subcommand,
|
||||||
@@ -47,6 +49,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
plugin_type=PluginType.NORMAL,
|
plugin_type=PluginType.NORMAL,
|
||||||
menu_type="商店",
|
menu_type="商店",
|
||||||
commands=[
|
commands=[
|
||||||
|
Command(command="商店"),
|
||||||
Command(command="我的金币"),
|
Command(command="我的金币"),
|
||||||
Command(command="我的道具"),
|
Command(command="我的道具"),
|
||||||
Command(command="购买道具"),
|
Command(command="购买道具"),
|
||||||
@@ -75,13 +78,21 @@ _matcher = on_alconna(
|
|||||||
Subcommand("my-cost", help_text="我的金币"),
|
Subcommand("my-cost", help_text="我的金币"),
|
||||||
Subcommand("my-props", help_text="我的道具"),
|
Subcommand("my-props", help_text="我的道具"),
|
||||||
Subcommand("buy", Args["name?", str]["num?", int], help_text="购买道具"),
|
Subcommand("buy", Args["name?", str]["num?", int], help_text="购买道具"),
|
||||||
Subcommand("use", Args["name?", str]["num?", int], help_text="使用道具"),
|
|
||||||
Subcommand("gold-list", Args["num?", int], help_text="金币排行"),
|
Subcommand("gold-list", Args["num?", int], help_text="金币排行"),
|
||||||
),
|
),
|
||||||
priority=5,
|
priority=5,
|
||||||
block=True,
|
block=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_use_matcher = on_alconna(
|
||||||
|
Alconna(
|
||||||
|
"使用道具",
|
||||||
|
Args["name?", str]["num?", int]["at_users?", MultiVar(At)],
|
||||||
|
),
|
||||||
|
priority=5,
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
_matcher.shortcut(
|
_matcher.shortcut(
|
||||||
"我的金币",
|
"我的金币",
|
||||||
command="商店",
|
command="商店",
|
||||||
@@ -103,13 +114,6 @@ _matcher.shortcut(
|
|||||||
prefix=True,
|
prefix=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
_matcher.shortcut(
|
|
||||||
"使用道具(?P<name>.*?)",
|
|
||||||
command="商店",
|
|
||||||
arguments=["use", "{name}"],
|
|
||||||
prefix=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
_matcher.shortcut(
|
_matcher.shortcut(
|
||||||
"金币排行",
|
"金币排行",
|
||||||
command="商店",
|
command="商店",
|
||||||
@@ -173,7 +177,7 @@ async def _(
|
|||||||
await MessageUtils.build_message(result).send(reply_to=True)
|
await MessageUtils.build_message(result).send(reply_to=True)
|
||||||
|
|
||||||
|
|
||||||
@_matcher.assign("use")
|
@_use_matcher.handle()
|
||||||
async def _(
|
async def _(
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
event: Event,
|
event: Event,
|
||||||
@@ -182,6 +186,7 @@ async def _(
|
|||||||
arparma: Arparma,
|
arparma: Arparma,
|
||||||
name: Match[str],
|
name: Match[str],
|
||||||
num: Query[int] = AlconnaQuery("num", 1),
|
num: Query[int] = AlconnaQuery("num", 1),
|
||||||
|
at_users: Query[list[At]] = AlconnaQuery("at_users", []),
|
||||||
):
|
):
|
||||||
if not name.available:
|
if not name.available:
|
||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
@@ -189,7 +194,7 @@ async def _(
|
|||||||
).finish(reply_to=True)
|
).finish(reply_to=True)
|
||||||
try:
|
try:
|
||||||
result = await ShopManage.use(
|
result = await ShopManage.use(
|
||||||
bot, event, session, message, name.result, num.result, ""
|
bot, event, session, message, name.result, num.result, "", at_users.result
|
||||||
)
|
)
|
||||||
logger.info(
|
logger.info(
|
||||||
f"使用道具 {name.result}, 数量: {num.result}",
|
f"使用道具 {name.result}, 数量: {num.result}",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from typing import Any, Literal
|
|||||||
|
|
||||||
from nonebot.adapters import Bot, Event
|
from nonebot.adapters import Bot, Event
|
||||||
from nonebot.compat import model_dump
|
from nonebot.compat import model_dump
|
||||||
from nonebot_plugin_alconna import UniMessage, UniMsg
|
from nonebot_plugin_alconna import At, UniMessage, UniMsg
|
||||||
from nonebot_plugin_uninfo import Uninfo
|
from nonebot_plugin_uninfo import Uninfo
|
||||||
from pydantic import BaseModel, Field, create_model
|
from pydantic import BaseModel, Field, create_model
|
||||||
from tortoise.expressions import Q
|
from tortoise.expressions import Q
|
||||||
@@ -48,6 +48,10 @@ class Goods(BaseModel):
|
|||||||
"""model"""
|
"""model"""
|
||||||
session: Uninfo | None = None
|
session: Uninfo | None = None
|
||||||
"""Uninfo"""
|
"""Uninfo"""
|
||||||
|
at_user: str | None = None
|
||||||
|
"""At对象"""
|
||||||
|
at_users: list[str] = []
|
||||||
|
"""At对象列表"""
|
||||||
|
|
||||||
|
|
||||||
class ShopParam(BaseModel):
|
class ShopParam(BaseModel):
|
||||||
@@ -73,6 +77,10 @@ class ShopParam(BaseModel):
|
|||||||
"""Uninfo"""
|
"""Uninfo"""
|
||||||
message: UniMsg
|
message: UniMsg
|
||||||
"""UniMessage"""
|
"""UniMessage"""
|
||||||
|
at_user: str | None = None
|
||||||
|
"""At对象"""
|
||||||
|
at_users: list[str] = []
|
||||||
|
"""At对象列表"""
|
||||||
extra_data: dict[str, Any] = Field(default_factory=dict)
|
extra_data: dict[str, Any] = Field(default_factory=dict)
|
||||||
"""额外数据"""
|
"""额外数据"""
|
||||||
|
|
||||||
@@ -156,6 +164,7 @@ class ShopManage:
|
|||||||
goods: Goods,
|
goods: Goods,
|
||||||
num: int,
|
num: int,
|
||||||
text: str,
|
text: str,
|
||||||
|
at_users: list[str] = [],
|
||||||
) -> tuple[ShopParam, dict[str, Any]]:
|
) -> tuple[ShopParam, dict[str, Any]]:
|
||||||
"""构造参数
|
"""构造参数
|
||||||
|
|
||||||
@@ -165,6 +174,7 @@ class ShopManage:
|
|||||||
goods_name: 商品名称
|
goods_name: 商品名称
|
||||||
num: 数量
|
num: 数量
|
||||||
text: 其他信息
|
text: 其他信息
|
||||||
|
at_users: at用户
|
||||||
"""
|
"""
|
||||||
group_id = None
|
group_id = None
|
||||||
if session.group:
|
if session.group:
|
||||||
@@ -172,6 +182,7 @@ class ShopManage:
|
|||||||
session.group.parent.id if session.group.parent else session.group.id
|
session.group.parent.id if session.group.parent else session.group.id
|
||||||
)
|
)
|
||||||
_kwargs = goods.params
|
_kwargs = goods.params
|
||||||
|
at_user = at_users[0] if at_users else None
|
||||||
model = goods.model(
|
model = goods.model(
|
||||||
**{
|
**{
|
||||||
"goods_name": goods.name,
|
"goods_name": goods.name,
|
||||||
@@ -183,6 +194,8 @@ class ShopManage:
|
|||||||
"text": text,
|
"text": text,
|
||||||
"session": session,
|
"session": session,
|
||||||
"message": message,
|
"message": message,
|
||||||
|
"at_user": at_user,
|
||||||
|
"at_users": at_users,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return model, {
|
return model, {
|
||||||
@@ -194,6 +207,8 @@ class ShopManage:
|
|||||||
"num": num,
|
"num": num,
|
||||||
"text": text,
|
"text": text,
|
||||||
"goods_name": goods.name,
|
"goods_name": goods.name,
|
||||||
|
"at_user": at_user,
|
||||||
|
"at_users": at_users,
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -223,6 +238,7 @@ class ShopManage:
|
|||||||
**param.extra_data,
|
**param.extra_data,
|
||||||
"session": session,
|
"session": session,
|
||||||
"message": message,
|
"message": message,
|
||||||
|
"shop_param": ShopParam,
|
||||||
}
|
}
|
||||||
for key in list(param_json.keys()):
|
for key in list(param_json.keys()):
|
||||||
if key not in args:
|
if key not in args:
|
||||||
@@ -308,6 +324,7 @@ class ShopManage:
|
|||||||
goods_name: str,
|
goods_name: str,
|
||||||
num: int,
|
num: int,
|
||||||
text: str,
|
text: str,
|
||||||
|
at_users: list[At] = [],
|
||||||
) -> str | UniMessage | None:
|
) -> str | UniMessage | None:
|
||||||
"""使用道具
|
"""使用道具
|
||||||
|
|
||||||
@@ -319,6 +336,7 @@ class ShopManage:
|
|||||||
goods_name: 商品名称
|
goods_name: 商品名称
|
||||||
num: 使用数量
|
num: 使用数量
|
||||||
text: 其他信息
|
text: 其他信息
|
||||||
|
at_users: at用户
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
str | MessageFactory | None: 使用完成后返回信息
|
str | MessageFactory | None: 使用完成后返回信息
|
||||||
@@ -339,8 +357,9 @@ class ShopManage:
|
|||||||
goods = cls.uuid2goods.get(goods_info.uuid)
|
goods = cls.uuid2goods.get(goods_info.uuid)
|
||||||
if not goods or not goods.func:
|
if not goods or not goods.func:
|
||||||
return f"{goods_info.goods_name} 未注册使用函数, 无法使用..."
|
return f"{goods_info.goods_name} 未注册使用函数, 无法使用..."
|
||||||
|
at_user_ids = [at.target for at in at_users]
|
||||||
param, kwargs = cls.__build_params(
|
param, kwargs = cls.__build_params(
|
||||||
bot, event, session, message, goods, num, text
|
bot, event, session, message, goods, num, text, at_user_ids
|
||||||
)
|
)
|
||||||
if num > param.max_num_limit:
|
if num > param.max_num_limit:
|
||||||
return f"{goods_info.goods_name} 单次使用最大数量为{param.max_num_limit}..."
|
return f"{goods_info.goods_name} 单次使用最大数量为{param.max_num_limit}..."
|
||||||
@@ -480,10 +499,13 @@ class ShopManage:
|
|||||||
if not user.props:
|
if not user.props:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
user.props = {uuid: count for uuid, count in user.props.items() if count > 0}
|
|
||||||
|
|
||||||
goods_list = await GoodsInfo.filter(uuid__in=user.props.keys()).all()
|
goods_list = await GoodsInfo.filter(uuid__in=user.props.keys()).all()
|
||||||
goods_by_uuid = {item.uuid: item for item in goods_list}
|
goods_by_uuid = {item.uuid: item for item in goods_list}
|
||||||
|
user.props = {
|
||||||
|
uuid: count
|
||||||
|
for uuid, count in user.props.items()
|
||||||
|
if count > 0 and goods_by_uuid.get(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
table_rows = []
|
table_rows = []
|
||||||
for i, prop_uuid in enumerate(user.props):
|
for i, prop_uuid in enumerate(user.props):
|
||||||
|
|||||||
+137
-81
@@ -1,7 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
import random
|
import random
|
||||||
from typing import Literal
|
from typing import cast
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import nonebot
|
import nonebot
|
||||||
@@ -486,15 +486,134 @@ class PlatformUtils:
|
|||||||
return target
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
class BroadcastEngine:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
message: str | UniMessage,
|
||||||
|
bot: Bot | list[Bot] | None = None,
|
||||||
|
bot_id: str | set[str] | None = None,
|
||||||
|
ignore_group: list[str] | None = None,
|
||||||
|
check_func: Callable[[Bot, str], Awaitable] | None = None,
|
||||||
|
log_cmd: str | None = None,
|
||||||
|
platform: str | None = None,
|
||||||
|
):
|
||||||
|
"""广播引擎
|
||||||
|
|
||||||
|
参数:
|
||||||
|
message: 广播消息内容
|
||||||
|
bot: 指定bot对象.
|
||||||
|
bot_id: 指定bot id.
|
||||||
|
ignore_group: 忽略群聊列表.
|
||||||
|
check_func: 发送前对群聊检测方法,判断是否发送.
|
||||||
|
log_cmd: 日志标记.
|
||||||
|
platform: 指定平台.
|
||||||
|
|
||||||
|
异常:
|
||||||
|
ValueError: 没有可用的Bot对象
|
||||||
|
"""
|
||||||
|
if ignore_group is None:
|
||||||
|
ignore_group = []
|
||||||
|
self.message = MessageUtils.build_message(message)
|
||||||
|
self.ignore_group = ignore_group
|
||||||
|
self.check_func = check_func
|
||||||
|
self.log_cmd = log_cmd
|
||||||
|
self.platform = platform
|
||||||
|
self.bot_list = []
|
||||||
|
self.count = 0
|
||||||
|
if bot:
|
||||||
|
self.bot_list = [bot] if isinstance(bot, Bot) else bot
|
||||||
|
if isinstance(bot_id, str):
|
||||||
|
bot_id = set(bot_id)
|
||||||
|
if bot_id:
|
||||||
|
for i in bot_id:
|
||||||
|
try:
|
||||||
|
self.bot_list.append(nonebot.get_bot(i))
|
||||||
|
except KeyError:
|
||||||
|
logger.warning(f"Bot:{i} 对象未连接或不存在")
|
||||||
|
if not self.bot_list:
|
||||||
|
raise ValueError("当前没有可用的Bot对象...", log_cmd)
|
||||||
|
|
||||||
|
async def call_check(self, bot: Bot, group_id: str) -> bool:
|
||||||
|
"""运行发送检测函数
|
||||||
|
|
||||||
|
参数:
|
||||||
|
bot: Bot
|
||||||
|
group_id: 群组id
|
||||||
|
|
||||||
|
返回:
|
||||||
|
bool: 是否发送
|
||||||
|
"""
|
||||||
|
if not self.check_func:
|
||||||
|
return True
|
||||||
|
if is_coroutine_callable(self.check_func):
|
||||||
|
is_run = await self.check_func(bot, group_id)
|
||||||
|
else:
|
||||||
|
is_run = self.check_func(bot, group_id)
|
||||||
|
return cast(bool, is_run)
|
||||||
|
|
||||||
|
async def __send_message(self, bot: Bot, group: GroupConsole):
|
||||||
|
"""群组发送消息
|
||||||
|
|
||||||
|
参数:
|
||||||
|
bot: Bot
|
||||||
|
group: GroupConsole
|
||||||
|
"""
|
||||||
|
key = f"{group.group_id}:{group.channel_id}"
|
||||||
|
if not await self.call_check(bot, group.group_id):
|
||||||
|
logger.debug(
|
||||||
|
"广播方法检测运行方法为 False, 已跳过该群组...",
|
||||||
|
self.log_cmd,
|
||||||
|
group_id=group.group_id,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
if target := PlatformUtils.get_target(
|
||||||
|
group_id=group.group_id,
|
||||||
|
channel_id=group.channel_id,
|
||||||
|
):
|
||||||
|
self.ignore_group.append(key)
|
||||||
|
await MessageUtils.build_message(self.message).send(target, bot)
|
||||||
|
logger.debug("广播消息发送成功...", self.log_cmd, target=key)
|
||||||
|
else:
|
||||||
|
logger.warning("广播消息获取Target失败...", self.log_cmd, target=key)
|
||||||
|
|
||||||
|
async def broadcast(self) -> int:
|
||||||
|
"""广播消息
|
||||||
|
|
||||||
|
返回:
|
||||||
|
int: 成功发送次数
|
||||||
|
"""
|
||||||
|
for bot in self.bot_list:
|
||||||
|
if self.platform and self.platform != PlatformUtils.get_platform(bot):
|
||||||
|
continue
|
||||||
|
group_list, _ = await PlatformUtils.get_group_list(bot)
|
||||||
|
if not group_list:
|
||||||
|
continue
|
||||||
|
for group in group_list:
|
||||||
|
if (
|
||||||
|
group.group_id in self.ignore_group
|
||||||
|
or group.channel_id in self.ignore_group
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
await self.__send_message(bot, group)
|
||||||
|
await asyncio.sleep(random.randint(1, 3))
|
||||||
|
self.count += 1
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(
|
||||||
|
"广播消息发送失败", self.log_cmd, target=group.group_id, e=e
|
||||||
|
)
|
||||||
|
return self.count
|
||||||
|
|
||||||
|
|
||||||
async def broadcast_group(
|
async def broadcast_group(
|
||||||
message: str | UniMessage,
|
message: str | UniMessage,
|
||||||
bot: Bot | list[Bot] | None = None,
|
bot: Bot | list[Bot] | None = None,
|
||||||
bot_id: str | set[str] | None = None,
|
bot_id: str | set[str] | None = None,
|
||||||
ignore_group: set[int] | None = None,
|
ignore_group: list[str] = [],
|
||||||
check_func: Callable[[Bot, str], Awaitable] | None = None,
|
check_func: Callable[[Bot, str], Awaitable] | None = None,
|
||||||
log_cmd: str | None = None,
|
log_cmd: str | None = None,
|
||||||
platform: Literal["qq", "dodo", "kaiheila"] | None = None,
|
platform: str | None = None,
|
||||||
):
|
) -> int:
|
||||||
"""获取所有Bot或指定Bot对象广播群聊
|
"""获取所有Bot或指定Bot对象广播群聊
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
@@ -505,81 +624,18 @@ async def broadcast_group(
|
|||||||
check_func: 发送前对群聊检测方法,判断是否发送.
|
check_func: 发送前对群聊检测方法,判断是否发送.
|
||||||
log_cmd: 日志标记.
|
log_cmd: 日志标记.
|
||||||
platform: 指定平台
|
platform: 指定平台
|
||||||
|
|
||||||
|
返回:
|
||||||
|
int: 成功发送次数
|
||||||
"""
|
"""
|
||||||
if platform and platform not in ["qq", "dodo", "kaiheila"]:
|
if not message.strip():
|
||||||
raise ValueError("指定平台不支持")
|
raise ValueError("群聊广播消息不能为空...")
|
||||||
if not message:
|
return await BroadcastEngine(
|
||||||
raise ValueError("群聊广播消息不能为空")
|
message=message,
|
||||||
bot_dict = nonebot.get_bots()
|
bot=bot,
|
||||||
bot_list: list[Bot] = []
|
bot_id=bot_id,
|
||||||
if bot:
|
ignore_group=ignore_group,
|
||||||
if isinstance(bot, list):
|
check_func=check_func,
|
||||||
bot_list = bot
|
log_cmd=log_cmd,
|
||||||
else:
|
platform=platform,
|
||||||
bot_list.append(bot)
|
).broadcast()
|
||||||
elif bot_id:
|
|
||||||
_bot_id_list = bot_id
|
|
||||||
if isinstance(bot_id, str):
|
|
||||||
_bot_id_list = [bot_id]
|
|
||||||
for id_ in _bot_id_list:
|
|
||||||
if bot_id in bot_dict:
|
|
||||||
bot_list.append(bot_dict[bot_id])
|
|
||||||
else:
|
|
||||||
logger.warning(f"Bot:{id_} 对象未连接或不存在")
|
|
||||||
else:
|
|
||||||
bot_list = list(bot_dict.values())
|
|
||||||
_used_group = []
|
|
||||||
for _bot in bot_list:
|
|
||||||
try:
|
|
||||||
if platform and platform != PlatformUtils.get_platform(_bot):
|
|
||||||
continue
|
|
||||||
group_list, _ = await PlatformUtils.get_group_list(_bot)
|
|
||||||
if group_list:
|
|
||||||
for group in group_list:
|
|
||||||
key = f"{group.group_id}:{group.channel_id}"
|
|
||||||
try:
|
|
||||||
if (
|
|
||||||
ignore_group
|
|
||||||
and (
|
|
||||||
group.group_id in ignore_group
|
|
||||||
or group.channel_id in ignore_group
|
|
||||||
)
|
|
||||||
) or key in _used_group:
|
|
||||||
logger.debug(
|
|
||||||
"广播方法群组重复, 已跳过...",
|
|
||||||
log_cmd,
|
|
||||||
group_id=group.group_id,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
is_run = False
|
|
||||||
if check_func:
|
|
||||||
if is_coroutine_callable(check_func):
|
|
||||||
is_run = await check_func(_bot, group.group_id)
|
|
||||||
else:
|
|
||||||
is_run = check_func(_bot, group.group_id)
|
|
||||||
if not is_run:
|
|
||||||
logger.debug(
|
|
||||||
"广播方法检测运行方法为 False, 已跳过...",
|
|
||||||
log_cmd,
|
|
||||||
group_id=group.group_id,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
target = PlatformUtils.get_target(
|
|
||||||
user_id=None,
|
|
||||||
group_id=group.group_id,
|
|
||||||
channel_id=group.channel_id,
|
|
||||||
)
|
|
||||||
if target:
|
|
||||||
_used_group.append(key)
|
|
||||||
message_list = message
|
|
||||||
await MessageUtils.build_message(message_list).send(
|
|
||||||
target, _bot
|
|
||||||
)
|
|
||||||
logger.debug("发送成功", log_cmd, target=key)
|
|
||||||
await asyncio.sleep(random.randint(1, 3))
|
|
||||||
else:
|
|
||||||
logger.warning("target为空", log_cmd, target=key)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error("发送失败", log_cmd, target=key, e=e)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Bot: {_bot.self_id} 获取群聊列表失败", command=log_cmd, e=e)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user