mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 06:12:53 +08:00
🐛 修复添加插件依赖更新 (#1837)
* 🐛 修复添加插件依赖更新 * 🔧 修改插件依赖安装命令为使用poetry运行pip * 🐛 修复群组入群与退群提示 * 🐛 修复群组踢出用户提醒 * 🎨 代码优化 * 🎨 群欢迎迁移优化 * 🩹 精确webui调用统计 * 🚨 auto fix by pre-commit hooks * 🐛 修复测试 * 🎨 fix pre-commit.ci * 🎨 fix pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
d6fd5f170a
commit
4ed1791b30
28
poetry.lock
generated
28
poetry.lock
generated
@ -2226,13 +2226,13 @@ reference = "aliyun"
|
||||
|
||||
[[package]]
|
||||
name = "nonebot-plugin-uninfo"
|
||||
version = "0.4.1"
|
||||
version = "0.6.8"
|
||||
description = "Universal Information Model for Nonebot2"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "nonebot_plugin_uninfo-0.4.1-py3-none-any.whl", hash = "sha256:2075874a540f27cb650ff5e64482324121c39e4374b850df323482744910beac"},
|
||||
{file = "nonebot_plugin_uninfo-0.4.1.tar.gz", hash = "sha256:8c36d62684029d813dd01acd2cc759f07163923b8274935250dcd3e9293ef560"},
|
||||
{file = "nonebot_plugin_uninfo-0.6.8-py3-none-any.whl", hash = "sha256:0adc7e731885883bfcb873ec715c69cff75b878092884d28c7d6ff314940ad6b"},
|
||||
{file = "nonebot_plugin_uninfo-0.6.8.tar.gz", hash = "sha256:0a30b500b1172fa15cc175b370c7a5935eb2f0515d188a2c73bf8e8ed7ae81d1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -4131,6 +4131,26 @@ type = "legacy"
|
||||
url = "https://mirrors.aliyun.com/pypi/simple"
|
||||
reference = "aliyun"
|
||||
|
||||
[[package]]
|
||||
name = "tenacity"
|
||||
version = "9.0.0"
|
||||
description = "Retry code until it succeeds"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"},
|
||||
{file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
doc = ["reno", "sphinx"]
|
||||
test = ["pytest", "tornado (>=4.5)", "typeguard"]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://mirrors.aliyun.com/pypi/simple"
|
||||
reference = "aliyun"
|
||||
|
||||
[[package]]
|
||||
name = "text-unidecode"
|
||||
version = "1.3"
|
||||
@ -4883,4 +4903,4 @@ reference = "aliyun"
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "69299e37ab69af7e3a020cc383fc2f2706300cf869a92dc7b76fe133288c405d"
|
||||
content-hash = "2fc15734ee6edc0a9b2b2f025375e7f41204bc21970745b65d5bc445eed897c7"
|
||||
|
||||
@ -41,8 +41,9 @@ python-jose = { extras = ["cryptography"], version = "^3.3.0" }
|
||||
python-multipart = "^0.0.9"
|
||||
aiocache = "^0.12.2"
|
||||
py-cpuinfo = "^9.0.0"
|
||||
nonebot-plugin-uninfo = "^0.4.1"
|
||||
nonebot-plugin-alconna = "^0.54.0"
|
||||
tenacity = "^9.0.0"
|
||||
nonebot-plugin-uninfo = ">0.4.1"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
nonebug = "^0.4"
|
||||
|
||||
@ -12,7 +12,7 @@ from pytest_asyncio import is_async_test
|
||||
from pytest_mock import MockerFixture
|
||||
from respx import MockRouter
|
||||
|
||||
from tests.config import BotId, UserId
|
||||
from tests.config import BotId, GroupId, UserId
|
||||
|
||||
nonebot.load_plugin("nonebot_plugin_session")
|
||||
|
||||
@ -64,6 +64,37 @@ def _init_bot(nonebug_init: None):
|
||||
nonebot.load_plugins("zhenxun/builtin_plugins")
|
||||
nonebot.load_plugins("zhenxun/plugins")
|
||||
|
||||
# 手动缓存 uninfo 所需信息
|
||||
from nonebot_plugin_uninfo import (
|
||||
Scene,
|
||||
SceneType,
|
||||
Session,
|
||||
SupportAdapter,
|
||||
SupportScope,
|
||||
User,
|
||||
)
|
||||
from nonebot_plugin_uninfo.adapters.onebot11.main import fetcher as onebot11_fetcher
|
||||
from nonebot_plugin_uninfo.adapters.onebot12.main import fetcher as onebot12_fetcher
|
||||
|
||||
onebot11_fetcher.session_cache = {
|
||||
f"group_{GroupId.GROUP_ID_LEVEL_5}_{UserId.SUPERUSER}": Session(
|
||||
self_id="test",
|
||||
adapter=SupportAdapter.onebot11,
|
||||
scope=SupportScope.qq_client,
|
||||
scene=Scene(str(GroupId.GROUP_ID_LEVEL_0), SceneType.GROUP),
|
||||
user=User(str(UserId.SUPERUSER)),
|
||||
),
|
||||
}
|
||||
onebot12_fetcher.session_cache = {
|
||||
f"group_{GroupId.GROUP_ID_LEVEL_5}_{UserId.SUPERUSER}": Session(
|
||||
self_id="test",
|
||||
adapter=SupportAdapter.onebot12,
|
||||
scope=SupportScope.qq_client,
|
||||
scene=Scene(str(GroupId.GROUP_ID_LEVEL_0), SceneType.GROUP),
|
||||
user=User(str(UserId.SUPERUSER)),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def app(app: App, tmp_path: Path, mocker: MockerFixture):
|
||||
|
||||
@ -54,6 +54,8 @@ def migrate(path: Path):
|
||||
path: 路径
|
||||
"""
|
||||
text_file = path / "text.json"
|
||||
if not text_file.exists():
|
||||
return
|
||||
with text_file.open(encoding="utf8") as f:
|
||||
json_data = json.load(f)
|
||||
new_data = {}
|
||||
|
||||
@ -103,7 +103,7 @@ group_increase_handle = on_notice(
|
||||
group_decrease_handle = on_notice(
|
||||
priority=1,
|
||||
block=False,
|
||||
rule=notice_rule([GroupMemberDecreaseEvent, GroupMemberIncreaseEvent]),
|
||||
rule=notice_rule([GroupMemberDecreaseEvent, GroupDecreaseNoticeEvent]),
|
||||
)
|
||||
"""群员减少处理"""
|
||||
add_group = on_request(priority=1, block=False)
|
||||
@ -116,19 +116,19 @@ async def _(
|
||||
session: Uninfo,
|
||||
event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent,
|
||||
):
|
||||
user_id = str(event.user_id)
|
||||
group_id = str(event.group_id)
|
||||
if user_id == bot.self_id:
|
||||
if session.user.id == bot.self_id:
|
||||
"""新成员为bot本身"""
|
||||
group, _ = await GroupConsole.get_or_create(
|
||||
group_id=group_id, channel_id__isnull=True
|
||||
group_id=str(event.group_id), channel_id__isnull=True
|
||||
)
|
||||
try:
|
||||
await GroupManager.add_bot(bot, str(event.operator_id), group_id, group)
|
||||
await GroupManager.add_bot(
|
||||
bot, str(event.operator_id), str(event.group_id), group
|
||||
)
|
||||
except ForceAddGroupError as e:
|
||||
await PlatformUtils.send_superuser(bot, e.get_info())
|
||||
else:
|
||||
await GroupManager.add_user(session, bot, user_id, group_id)
|
||||
await GroupManager.add_user(session, bot)
|
||||
|
||||
|
||||
@group_decrease_handle.handle()
|
||||
|
||||
@ -4,6 +4,7 @@ from pathlib import Path
|
||||
import random
|
||||
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.exception import ActionFailed
|
||||
from nonebot_plugin_alconna import At, UniMessage
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
import ujson as json
|
||||
@ -54,7 +55,7 @@ class GroupManager:
|
||||
if plugin_list := await PluginInfo.filter(default_status=False).all():
|
||||
for plugin in plugin_list:
|
||||
block_plugin += f"<{plugin.module},"
|
||||
group_info = await bot.get_group_info(group_id=group_id)
|
||||
group_info = await bot.get_group_info(group_id=group_id, no_cache=True)
|
||||
await GroupConsole.create(
|
||||
group_id=group_info["group_id"],
|
||||
group_name=group_info["group_name"],
|
||||
@ -215,33 +216,45 @@ class GroupManager:
|
||||
msg_list.insert(0, At("user", user_id))
|
||||
logger.info("发送群欢迎消息...", "入群检测", session=session)
|
||||
if msg_list:
|
||||
await MessageUtils.build_message(msg_list).send() # type: ignore
|
||||
else:
|
||||
image = DEFAULT_IMAGE_PATH / random.choice(
|
||||
os.listdir(DEFAULT_IMAGE_PATH)
|
||||
)
|
||||
await MessageUtils.build_message(
|
||||
[
|
||||
"新人快跑啊!!本群现状↓(快使用自定义群欢迎消息!)",
|
||||
image,
|
||||
]
|
||||
).send()
|
||||
await MessageUtils.build_message(msg_list).finish() # type: ignore
|
||||
image = DEFAULT_IMAGE_PATH / random.choice(os.listdir(DEFAULT_IMAGE_PATH))
|
||||
await MessageUtils.build_message(
|
||||
[
|
||||
"新人快跑啊!!本群现状↓(快使用自定义群欢迎消息!)",
|
||||
image,
|
||||
]
|
||||
).send()
|
||||
|
||||
@classmethod
|
||||
async def add_user(cls, session: Uninfo, bot: Bot, user_id: str, group_id: str):
|
||||
async def add_user(cls, session: Uninfo, bot: Bot):
|
||||
"""拉入用户
|
||||
|
||||
参数:
|
||||
session: Uninfo
|
||||
bot: Bot
|
||||
user_id: 用户id
|
||||
group_id: 群组id
|
||||
"""
|
||||
user_id = session.user.id
|
||||
group_id = ""
|
||||
if session.group:
|
||||
if session.group.parent:
|
||||
group_id = session.group.parent.id
|
||||
else:
|
||||
group_id = session.group.id
|
||||
join_time = datetime.now()
|
||||
user_info = await bot.get_group_member_info(group_id=group_id, user_id=user_id)
|
||||
try:
|
||||
user_info = await bot.get_group_member_info(
|
||||
group_id=int(group_id), user_id=int(user_id), no_cache=True
|
||||
)
|
||||
except ActionFailed as e:
|
||||
logger.warning("获取用户信息识别...", e=e)
|
||||
user_info = {"user_id": user_id, "group_id": group_id, "nickname": ""}
|
||||
await GroupInfoUser.update_or_create(
|
||||
user_id=str(user_info["user_id"]),
|
||||
group_id=str(user_info["group_id"]),
|
||||
defaults={"user_name": user_info["nickname"], "user_join_time": join_time},
|
||||
defaults={
|
||||
"user_name": user_info["nickname"],
|
||||
"user_join_time": join_time,
|
||||
},
|
||||
)
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
if not await CommonUtils.task_is_block(
|
||||
@ -310,10 +323,13 @@ class GroupManager:
|
||||
group_id=group_id,
|
||||
)
|
||||
if sub_type == "kick":
|
||||
operator = await bot.get_group_member_info(
|
||||
user_id=int(operator_id), group_id=int(group_id)
|
||||
)
|
||||
operator_name = operator["card"] or operator["nickname"]
|
||||
if operator_id != "0":
|
||||
operator = await bot.get_group_member_info(
|
||||
user_id=int(operator_id), group_id=int(group_id)
|
||||
)
|
||||
operator_name = operator["card"] or operator["nickname"]
|
||||
else:
|
||||
operator_name = ""
|
||||
return f"{user_name} 被 {operator_name} 送走了."
|
||||
elif sub_type == "leave":
|
||||
return f"{user_name}离开了我们..."
|
||||
|
||||
@ -44,14 +44,14 @@ _matcher = on_alconna(
|
||||
)
|
||||
|
||||
_matcher.shortcut(
|
||||
r"添加插件",
|
||||
r"(添加|安装)插件",
|
||||
command="插件商店",
|
||||
arguments=["add", "{%0}"],
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
_matcher.shortcut(
|
||||
r"移除插件",
|
||||
r"(移除|卸载)插件",
|
||||
command="插件商店",
|
||||
arguments=["remove", "{%0}"],
|
||||
prefix=True,
|
||||
|
||||
@ -51,7 +51,7 @@ def install_requirement(plugin_path: Path):
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["pip", "install", "-r", str(existing_requirements)],
|
||||
["poetry", "run", "pip", "install", "-r", str(existing_requirements)],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
@ -232,8 +232,9 @@ class ShopManage:
|
||||
raise ValueError("所有API获取插件文件失败,请检查网络连接")
|
||||
if module_path == ".":
|
||||
module_path = ""
|
||||
replace_module_path = module_path.replace(".", "/")
|
||||
files = repo_api.get_files(
|
||||
module_path=module_path.replace(".", "/") + ("" if is_dir else ".py"),
|
||||
module_path=replace_module_path + ("" if is_dir else ".py"),
|
||||
is_dir=is_dir,
|
||||
)
|
||||
download_urls = [await repo_info.get_raw_download_urls(file) for file in files]
|
||||
@ -248,25 +249,32 @@ class ShopManage:
|
||||
else:
|
||||
# 安装依赖
|
||||
plugin_path = base_path / "/".join(module_path.split("."))
|
||||
req_files = repo_api.get_files(REQ_TXT_FILE_STRING, False)
|
||||
req_files.extend(repo_api.get_files("requirement.txt", False))
|
||||
logger.debug(f"获取插件依赖文件列表: {req_files}", "插件管理")
|
||||
req_download_urls = [
|
||||
await repo_info.get_raw_download_urls(file) for file in req_files
|
||||
]
|
||||
req_paths: list[Path | str] = [plugin_path / file for file in req_files]
|
||||
logger.debug(f"插件依赖文件下载路径: {req_paths}", "插件管理")
|
||||
if req_files:
|
||||
result = await AsyncHttpx.gather_download_file(
|
||||
req_download_urls, req_paths
|
||||
try:
|
||||
req_files = repo_api.get_files(
|
||||
f"{replace_module_path}/{REQ_TXT_FILE_STRING}", False
|
||||
)
|
||||
for success in result:
|
||||
if not success:
|
||||
raise Exception("插件依赖文件下载失败")
|
||||
logger.debug(f"插件依赖文件列表: {req_paths}", "插件管理")
|
||||
install_requirement(plugin_path)
|
||||
req_files.extend(
|
||||
repo_api.get_files(f"{replace_module_path}/requirement.txt", False)
|
||||
)
|
||||
logger.debug(f"获取插件依赖文件列表: {req_files}", "插件管理")
|
||||
req_download_urls = [
|
||||
await repo_info.get_raw_download_urls(file) for file in req_files
|
||||
]
|
||||
req_paths: list[Path | str] = [plugin_path / file for file in req_files]
|
||||
logger.debug(f"插件依赖文件下载路径: {req_paths}", "插件管理")
|
||||
if req_files:
|
||||
result = await AsyncHttpx.gather_download_file(
|
||||
req_download_urls, req_paths
|
||||
)
|
||||
for success in result:
|
||||
if not success:
|
||||
raise Exception("插件依赖文件下载失败")
|
||||
logger.debug(f"插件依赖文件列表: {req_paths}", "插件管理")
|
||||
install_requirement(plugin_path)
|
||||
except ValueError as e:
|
||||
logger.warning("未获取到依赖文件路径...", e=e)
|
||||
return True
|
||||
raise Exception("插件下载失败")
|
||||
raise Exception("插件下载失败...")
|
||||
|
||||
@classmethod
|
||||
async def remove_plugin(cls, plugin_id: str) -> str:
|
||||
|
||||
@ -16,6 +16,7 @@ from zhenxun.models.sign_log import SignLog
|
||||
from zhenxun.models.sign_user import SignUser
|
||||
from zhenxun.utils.http_utils import AsyncHttpx
|
||||
from zhenxun.utils.image_utils import BuildImage
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
|
||||
from .config import (
|
||||
SIGN_BACKGROUND_PATH,
|
||||
@ -430,7 +431,9 @@ async def _generate_html_card(
|
||||
)
|
||||
now = datetime.now()
|
||||
data = {
|
||||
"ava_url": session.user.avatar,
|
||||
"ava_url": PlatformUtils.get_user_avatar_url(
|
||||
user.user_id, PlatformUtils.get_platform(session), session.self_id
|
||||
),
|
||||
"name": nickname,
|
||||
"uid": uid,
|
||||
"sign_count": f"{user.sign_count}",
|
||||
|
||||
@ -248,13 +248,31 @@ class ApiDataSource:
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
if date_type == QueryDateType.DAY:
|
||||
query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
|
||||
query = query.filter(
|
||||
create_time__gte=now
|
||||
- timedelta(hours=now.hour, minutes=now.minute, seconds=now.second)
|
||||
)
|
||||
if date_type == QueryDateType.WEEK:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=7))
|
||||
query = query.filter(
|
||||
create_time__gte=now
|
||||
- timedelta(
|
||||
days=7, hours=now.hour, minutes=now.minute, seconds=now.second
|
||||
)
|
||||
)
|
||||
if date_type == QueryDateType.MONTH:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=30))
|
||||
query = query.filter(
|
||||
create_time__gte=now
|
||||
- timedelta(
|
||||
days=30, hours=now.hour, minutes=now.minute, seconds=now.second
|
||||
)
|
||||
)
|
||||
if date_type == QueryDateType.YEAR:
|
||||
query = query.filter(create_time__gte=now - timedelta(days=365))
|
||||
query = query.filter(
|
||||
create_time__gte=now
|
||||
- timedelta(
|
||||
days=365, hours=now.hour, minutes=now.minute, seconds=now.second
|
||||
)
|
||||
)
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
|
||||
@ -6,6 +6,8 @@ from pydantic import BaseModel
|
||||
|
||||
from .utils import ConfigsManager
|
||||
|
||||
__all__ = ["BotConfig", "Config"]
|
||||
|
||||
|
||||
class BotSetting(BaseModel):
|
||||
self_nickname: str = ""
|
||||
|
||||
16
zhenxun/utils/decorator/retry.py
Normal file
16
zhenxun/utils/decorator/retry.py
Normal file
@ -0,0 +1,16 @@
|
||||
from httpx import ConnectError, HTTPStatusError, TimeoutException
|
||||
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed
|
||||
|
||||
|
||||
class Retry:
|
||||
@staticmethod
|
||||
def api():
|
||||
"""接口调用重试"""
|
||||
return retry(
|
||||
reraise=True,
|
||||
stop=stop_after_attempt(3),
|
||||
wait=wait_fixed(1),
|
||||
retry=retry_if_exception_type(
|
||||
(TimeoutException, ConnectError, HTTPStatusError)
|
||||
),
|
||||
)
|
||||
@ -7,6 +7,7 @@ import time
|
||||
from typing import Any, ClassVar, Literal
|
||||
|
||||
import aiofiles
|
||||
from anyio import EndOfStream
|
||||
import httpx
|
||||
from httpx import ConnectTimeout, HTTPStatusError, Response
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
@ -41,7 +42,7 @@ class AsyncHttpx:
|
||||
verify: bool = True,
|
||||
use_proxy: bool = True,
|
||||
proxy: dict[str, str] | None = None,
|
||||
timeout: int = 30,
|
||||
timeout: int = 30, # noqa: ASYNC109
|
||||
**kwargs,
|
||||
) -> Response:
|
||||
"""Get
|
||||
@ -96,7 +97,7 @@ class AsyncHttpx:
|
||||
verify: bool = True,
|
||||
use_proxy: bool = True,
|
||||
proxy: dict[str, str] | None = None,
|
||||
timeout: int = 30,
|
||||
timeout: int = 30, # noqa: ASYNC109
|
||||
**kwargs,
|
||||
) -> Response:
|
||||
if not headers:
|
||||
@ -123,7 +124,7 @@ class AsyncHttpx:
|
||||
verify: bool = True,
|
||||
use_proxy: bool = True,
|
||||
proxy: dict[str, str] | None = None,
|
||||
timeout: int = 30,
|
||||
timeout: int = 30, # noqa: ASYNC109
|
||||
**kwargs,
|
||||
) -> Response:
|
||||
"""Get
|
||||
@ -166,7 +167,7 @@ class AsyncHttpx:
|
||||
params: dict[str, str] | None = None,
|
||||
headers: dict[str, str] | None = None,
|
||||
cookies: dict[str, str] | None = None,
|
||||
timeout: int = 30,
|
||||
timeout: int = 30, # noqa: ASYNC109
|
||||
**kwargs,
|
||||
) -> Response:
|
||||
"""
|
||||
@ -219,7 +220,7 @@ class AsyncHttpx:
|
||||
proxy: dict[str, str] | None = None,
|
||||
headers: dict[str, str] | None = None,
|
||||
cookies: dict[str, str] | None = None,
|
||||
timeout: int = 30,
|
||||
timeout: int = 30, # noqa: ASYNC109
|
||||
stream: bool = False,
|
||||
follow_redirects: bool = True,
|
||||
**kwargs,
|
||||
@ -311,12 +312,17 @@ class AsyncHttpx:
|
||||
completed=response.num_bytes_downloaded,
|
||||
)
|
||||
logger.info(
|
||||
f"下载 {u} 成功.. "
|
||||
f"Path:{path.absolute()}"
|
||||
f"下载 {u} 成功.. Path:{path.absolute()}"
|
||||
)
|
||||
return True
|
||||
except (TimeoutError, ConnectTimeout, HTTPStatusError):
|
||||
logger.warning(f"下载 {u} 失败.. 尝试下一个地址..")
|
||||
except EndOfStream as e:
|
||||
logger.warning(
|
||||
f"下载 {url} EndOfStream 异常 Path:{path.absolute()}", e=e
|
||||
)
|
||||
if path.exists():
|
||||
return True
|
||||
logger.error(f"下载 {url} 下载超时.. Path:{path.absolute()}")
|
||||
except Exception as e:
|
||||
logger.error(f"下载 {url} 错误 Path:{path.absolute()}", e=e)
|
||||
@ -334,7 +340,7 @@ class AsyncHttpx:
|
||||
proxy: dict[str, str] | None = None,
|
||||
headers: dict[str, str] | None = None,
|
||||
cookies: dict[str, str] | None = None,
|
||||
timeout: int = 30,
|
||||
timeout: int = 30, # noqa: ASYNC109
|
||||
**kwargs,
|
||||
) -> list[bool]:
|
||||
"""分组同时下载文件
|
||||
@ -374,22 +380,22 @@ class AsyncHttpx:
|
||||
tasks = []
|
||||
result_ = []
|
||||
for x, y in zip(_split_url_list, _split_path_list):
|
||||
for url, path in zip(x, y):
|
||||
tasks.append(
|
||||
asyncio.create_task(
|
||||
cls.download_file(
|
||||
url,
|
||||
path,
|
||||
params=params,
|
||||
headers=headers,
|
||||
cookies=cookies,
|
||||
use_proxy=use_proxy,
|
||||
timeout=timeout,
|
||||
proxy=proxy,
|
||||
**kwargs,
|
||||
)
|
||||
tasks.extend(
|
||||
asyncio.create_task(
|
||||
cls.download_file(
|
||||
url,
|
||||
path,
|
||||
params=params,
|
||||
headers=headers,
|
||||
cookies=cookies,
|
||||
use_proxy=use_proxy,
|
||||
timeout=timeout,
|
||||
proxy=proxy,
|
||||
**kwargs,
|
||||
)
|
||||
)
|
||||
for url, path in zip(x, y)
|
||||
)
|
||||
_x = await asyncio.gather(*tasks)
|
||||
result_ = result_ + list(_x)
|
||||
tasks.clear()
|
||||
@ -465,7 +471,7 @@ class AsyncPlaywright:
|
||||
wait_until: (
|
||||
Literal["domcontentloaded", "load", "networkidle"] | None
|
||||
) = "networkidle",
|
||||
timeout: float | None = None,
|
||||
timeout: float | None = None, # noqa: ASYNC109
|
||||
type_: Literal["jpeg", "png"] | None = None,
|
||||
user_agent: str | None = None,
|
||||
cookies: list[dict[str, Any]] | dict[str, Any] | None = None,
|
||||
|
||||
@ -17,6 +17,7 @@ from nonebot_plugin_alconna import (
|
||||
Voice,
|
||||
)
|
||||
from pydantic import BaseModel
|
||||
import ujson as json
|
||||
|
||||
from zhenxun.configs.config import BotConfig
|
||||
from zhenxun.services.log import logger
|
||||
@ -141,6 +142,21 @@ class MessageUtils:
|
||||
)
|
||||
return UniMessage(Reference(nodes=node_list))
|
||||
|
||||
@classmethod
|
||||
def markdown(cls, content: dict) -> Message:
|
||||
"""markdown格式消息
|
||||
|
||||
参数:
|
||||
content: 消息内容
|
||||
|
||||
返回:
|
||||
Message: 构造完成的消息
|
||||
"""
|
||||
content_data = base64.b64encode(json.dumps(content).encode("utf-8")).decode(
|
||||
"utf-8"
|
||||
)
|
||||
return Message(f"[CQ:markdown,data=base64://{content_data}]")
|
||||
|
||||
@classmethod
|
||||
def custom_forward_msg(
|
||||
cls,
|
||||
|
||||
@ -55,6 +55,8 @@ class PlatformUtils:
|
||||
"""
|
||||
if isinstance(session, Bot):
|
||||
return bool(BotConfig.get_qbot_uid(session.self_id))
|
||||
if BotConfig.get_qbot_uid(session.self_id):
|
||||
return True
|
||||
return session.scope == SupportScope.qq_api
|
||||
|
||||
@classmethod
|
||||
@ -354,32 +356,30 @@ class PlatformUtils:
|
||||
返回:
|
||||
tuple[list[GroupConsole], str]: 群组列表, 平台
|
||||
"""
|
||||
if interface := get_interface(bot):
|
||||
platform = cls.get_platform(bot)
|
||||
result_list = []
|
||||
scenes = await interface.get_scenes(SceneType.GROUP)
|
||||
for scene in scenes:
|
||||
group_id = scene.id
|
||||
result_list.append(
|
||||
GroupConsole(
|
||||
group_id=scene.id,
|
||||
group_name=scene.name,
|
||||
)
|
||||
if not (interface := get_interface(bot)):
|
||||
return [], ""
|
||||
platform = cls.get_platform(bot)
|
||||
result_list = []
|
||||
scenes = await interface.get_scenes(SceneType.GROUP)
|
||||
for scene in scenes:
|
||||
group_id = scene.id
|
||||
result_list.append(
|
||||
GroupConsole(
|
||||
group_id=scene.id,
|
||||
group_name=scene.name,
|
||||
)
|
||||
if not only_group and platform != "qq":
|
||||
if channel_list := await interface.get_scenes(
|
||||
parent_scene_id=group_id
|
||||
):
|
||||
for channel in channel_list:
|
||||
result_list.append(
|
||||
GroupConsole(
|
||||
group_id=scene.id,
|
||||
group_name=channel.name,
|
||||
channel_id=channel.id,
|
||||
)
|
||||
)
|
||||
return result_list, platform
|
||||
return [], ""
|
||||
)
|
||||
if not only_group and platform != "qq":
|
||||
if channel_list := await interface.get_scenes(parent_scene_id=group_id):
|
||||
result_list.extend(
|
||||
GroupConsole(
|
||||
group_id=scene.id,
|
||||
group_name=channel.name,
|
||||
channel_id=channel.id,
|
||||
)
|
||||
for channel in channel_list
|
||||
)
|
||||
return result_list, platform
|
||||
|
||||
@classmethod
|
||||
async def update_friend(cls, bot: Bot) -> int:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user