From f4ce789ffc89f9007235f9f7f6853b22d748ba8e Mon Sep 17 00:00:00 2001
From: HibiKier <775757368@qq.com>
Date: Sun, 11 Aug 2024 20:52:06 +0800
Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=8E=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
zhenxun/builtin_plugins/platform/qq/group_handle.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/zhenxun/builtin_plugins/platform/qq/group_handle.py b/zhenxun/builtin_plugins/platform/qq/group_handle.py
index e04f8e5a..262a67f1 100644
--- a/zhenxun/builtin_plugins/platform/qq/group_handle.py
+++ b/zhenxun/builtin_plugins/platform/qq/group_handle.py
@@ -231,7 +231,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent
"""群欢迎消息"""
_flmt.start_cd(group_id)
path = DATA_PATH / "welcome_message" / "qq" / f"{group_id}"
- data = json.load((path / "text.json").open())
+ data = json.load((path / "text.json").open(encoding="utf-8"))
message = data["message"]
msg_split = re.split(r"\[image:\d+\]", message)
msg_list = []
From 5f0797e3ed6acde45310d6894fc7aa1591f8e6cb Mon Sep 17 00:00:00 2001
From: HibiKier <775757368@qq.com>
Date: Sun, 11 Aug 2024 21:04:08 +0800
Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=8E=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 246 +++++++++++++++++++++++++-----------------------------
1 file changed, 116 insertions(+), 130 deletions(-)
diff --git a/README.md b/README.md
index 36399c2e..abd2f589 100644
--- a/README.md
+++ b/README.md
@@ -1,77 +1,76 @@
-

-
-
-
+
-# 绪山真寻Bot
+
+
+
+
+
+
+
+
+
+[](https://github.com/HibiKier/zhenxun_bot/blob/main/LICENSE)
+[](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ)
+[](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ)
+
+
+
+
+
+
+[文档](https://hibikier.github.io/zhenxun_bot/)
+
+
+
+
+
+## 绪山真寻Bot
-****
“真寻是[椛椛](https://github.com/FloatTech/ZeroBot-Plugin)的好朋友!”
+:tada:喜欢真寻,于是真寻就来了!:tada:
+
+本项目符合 [OneBot](https://github.com/howmanybots/onebot) 标准,可基于以下项目与机器人框架/平台进行交互
+| 项目地址 | 平台 | 核心作者 | 备注 |
+| :---: | :---: | :---: | :---: |
+| [LLOneBot](https://github.com/LLOneBot/LLOneBot) | NTQQ | linyuchen | 可用 |
+| [Napcat](https://github.com/NapNeko/NapCatQQ) | NTQQ | NapNeko | 可用 |
+| [Lagrange.Core](https://github.com/LagrangeDev/Lagrange.Core) | ? | LagrangeDev/Linwenxuan04 | 可用
+
-****
-
-## 关于
-
-用爱发电,某些功能学习借鉴了大佬们的代码,因为绪山真寻实在太可爱了因此开发了
-绪山真寻bot,实现了一些对群友的娱乐功能和实用功能(大概)。
-
-如果该项目的图片等等侵犯猫豆腐老师权益请联系我删除!
-
-讨论插件开发,nonebot2开发,或者有 安装使用问题 或 开发建议,可以发送issues或加入[ [真寻酱的技术群](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) ] (在这里请不要吹水!)
-
-希望有个地方讨论绪山真寻Bot,渴望吹水聊天,可以加入[ [是真寻酱哒(萌新版)](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) ]
-
-
-## 声明
-
-此项目仅用于学习交流,请勿用于非法用途
-
-
-# Nonebot2
-
-

-
-非常 [ **[NICE](https://github.com/nonebot/nonebot2)** ] 的OneBot框架
+
-## 未完成的文档
+## 真寻觉得你需要帮助
-# [传送门](https://hibikier.github.io/zhenxun_bot/)
+
-## 真寻的帮助
-
-请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
-
-## 普通帮助图片
-
-
-
-## HTML版帮助图片
-
-
+

+

+
## 这是一份扩展
-### 0. 体验一下?
+### 1. 体验一下?
-提供dev版本的zhenxun
+这是一个免费的,版本为dev的zhenxun,你可以通过napcat或拉格朗日等直接连接用于体验与测试
+(球球了测试君!)
```
Url: 43.143.112.57:11451/onebot/v11/ws
AccessToken: PUBLIC_ZHENXUN_TEST
@@ -79,12 +78,23 @@ AccessToken: PUBLIC_ZHENXUN_TEST
注:你无法获得超级用户权限
```
-### 1. Web UI
+### 2. 额外扩展
-项目地址: [Web UI](https://github.com/HibiKier/zhenxun_bot_webui)
+
+
+“不要害怕,你的背后还有千千万万的 伙伴 啊!”
+
+| 项目名称 | 主要用途 | 仓库作者 | 备注 |
+| :---: | :---: | :---: | :---: |
+| [WebUi](https://github.com/HibiKier/zhenxun_bot_webui) | 管理 | [hibikier](https://github.com/HibiKier) | 基于真寻WebApi的webui实现
+| [一键安装](https://github.com/zhenxun-org/zhenxun_bot-deploy) | 安装 | [AkashiCoin](https://github.com/AkashiCoin) | 新版本未测试
+| [Docker单机版](https://github.com/Sakuracio/zhenxun_bot_docker) | 安装 | [zhenxun-org](https://github.com/zhenxun-org) | 新版本未测试
+| [Docker全量版](https://shields.io/badge/GITHUB-SinKy--Yan-4476AF?logo=github&style=for-the-badge) | 安装 | [zhenxun-org](https://github.com/zhenxun-org) | 包含 真寻Bot PostgreSQL数据库 go-cqhttp webui等(新版本未测试)
+
+PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能无法正常启动全量版容器**
-后台示例图
+ WebUI 后台示例图


@@ -96,16 +106,11 @@ AccessToken: PUBLIC_ZHENXUN_TEST
+
-### 一键安装脚本(新版未测试)
+
-[zhenxun_bot-deploy](https://github.com/AkashiCoin/zhenxun_bot-deploy)
-
-### 提供符合真寻标准的插件仓库(旧版)
-
-[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
-
-## 来点优点?
+## ~~来点优点?~~ 可爱难道还不够吗
* 实现了许多功能,且提供了大量功能管理命令
* 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改
@@ -113,7 +118,61 @@ AccessToken: PUBLIC_ZHENXUN_TEST
* 提供了cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`PluginCdBlock` 等
* **..... 更多详细请通过`传送门`查看文档!**
-## 功能列表
+## 简单部署
+
+```
+# 获取代码
+git clone https://github.com/HibiKier/zhenxun.git
+
+# 进入目录
+cd zhenxun_bot
+
+# 安装依赖
+pip install poetry # 安装 poetry
+poetry install # 安装依赖
+
+# 开始运行
+poetry shell # 进入虚拟环境
+python bot.py
+
+# 首次后会在data目录下生成database.json和config.yaml文件
+# database.json用户配置数据库信息
+# config.yaml用户配置插件
+```
+
+## 简单配置
+
+```
+1.在.env.dev文件中
+
+ SUPERUSERS = [""] # 填写你的QQ
+
+ PLATFORM_SUPERUSERS = '
+ {
+ "qq": [""], # 在此处填写你的qq
+ "dodo": [],
+ "kaiheila": [],
+ "discord": []
+ }
+'
+
+2.在data/database.json文件中修改数据库配置
+{
+ "bind": "",
+ "sql_name": "postgres",
+ "user": "", # 用户们
+ "password": "", # 密码
+ "address": "", # 数据库地址ip
+ "port": "", # 数据库端口
+ "database": "" # 数据库名称
+}
+
+3.在configs/config.yaml文件中 # 该文件需要启动一次后生成
+ * 修改插件配置项
+
+```
+
+## 功能列表 (旧版列表)
已实现的功能
@@ -263,79 +322,6 @@ AccessToken: PUBLIC_ZHENXUN_TEST
-## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
-
-## 简单部署
-
-```
-
-# 使用napcat或拉格朗日
-
-# 获取代码
-git clone https://github.com/HibiKier/zhenxun.git
-
-# 进入目录
-cd zhenxun_bot
-
-# 安装依赖
-pip install poetry # 安装 poetry
-poetry install # 安装依赖
-
-# 进行基础配置
-####请查看 配置 部分####
-
-# 开始运行
-poetry shell # 进入虚拟环境
-python bot.py
-
-# 运行后会在data目录下生成database.json文件,请根据自身数据库配置修改
-# 其他插件配置在data/config.yaml文件中(需要运行一次)
-```
-
-## 简单配置
-
-```
-1.在.env.dev文件中
-
- SUPERUSERS = [""] # 填写你的QQ
-
- PLATFORM_SUPERUSERS = '
- {
- "qq": [""], # 在此处填写你的qq
- "dodo": [],
- "kaiheila": [],
- "discord": []
- }
-'
-
-2.在data/database.json文件中修改数据库配置
-{
- "bind": "",
- "sql_name": "postgres",
- "user": "", # 用户们
- "password": "", # 密码
- "address": "", # 数据库地址ip
- "port": "", # 数据库端口
- "database": "" # 数据库名称
-}
-
-3.在configs/config.yaml文件中 # 该文件需要启动一次后生成
- * 修改插件配置项
-
-```
-
-## 使用Docker (新版未测试过)
-
-**Docker 单机版(仅真寻Bot)**
-**点击下方的 GitHub 徽标查看教程**
-[](https://github.com/Sakuracio/zhenxun_bot_docker)
-[](https://hub.docker.com/r/hibikier/zhenxun_bot)
-**Docker 全量版(包含 真寻Bot PostgreSQL数据库 go-cqhttp webui等)**
-[](https://github.com/SinKy-Yan/zhenxunbot-docker)
-[](https://hub.docker.com/r/jyishit/zhenxun_bot)
-**点击上方的 GitHub 徽标查看教程**
-PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能无法正常启动全量版容器**
-
## [爱发电](https://afdian.net/@HibiKier)
From da595b8c8eaf55e70dd2d527582a27b6707fc049 Mon Sep 17 00:00:00 2001
From: HibiKier <775757368@qq.com>
Date: Mon, 12 Aug 2024 00:09:38 +0800
Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=8E=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
zhenxun/builtin_plugins/shop/_data_source.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/zhenxun/builtin_plugins/shop/_data_source.py b/zhenxun/builtin_plugins/shop/_data_source.py
index c7b5c68b..38ee3ddb 100644
--- a/zhenxun/builtin_plugins/shop/_data_source.py
+++ b/zhenxun/builtin_plugins/shop/_data_source.py
@@ -297,9 +297,8 @@ class ShopManage:
raise ValueError("该商品使用函数已被注册!")
kwargs["send_success_msg"] = send_success_msg
kwargs["max_num_limit"] = max_num_limit
- # TODO: create_model(f"{uuid}_model", __base__=ShopParam, **kwargs)
cls.uuid2goods[uuid] = Goods(
- model=None,# create_model(f"{uuid}_model", __base__=ShopParam, **kwargs),
+ model=create_model(f"{uuid}_model", __base__=ShopParam, **kwargs),
params=kwargs,
before_handle=before_handle,
after_handle=after_handle,
From b6fc114a14b1856c1f6b014debf9090c01d83cc3 Mon Sep 17 00:00:00 2001
From: BalconyJH
Date: Mon, 12 Aug 2024 15:38:37 +0800
Subject: [PATCH 4/5] =?UTF-8?q?:children=5Fcrossing:=20=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20Chromium=20=E5=AE=89=E8=A3=85=E9=80=BB=E8=BE=91,=20=E6=B7=BB?=
=?UTF-8?q?=E5=8A=A0=20Playwright=20=E4=BE=9D=E8=B5=96=E6=A3=80=E6=9F=A5?=
=?UTF-8?q?=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
zhenxun/utils/browser.py | 59 +++++++++++++++++++++++++++++++++++-----
1 file changed, 52 insertions(+), 7 deletions(-)
diff --git a/zhenxun/utils/browser.py b/zhenxun/utils/browser.py
index c7d89727..432c28ed 100644
--- a/zhenxun/utils/browser.py
+++ b/zhenxun/utils/browser.py
@@ -1,5 +1,10 @@
+import os
+import sys
+
from nonebot import get_driver
+from playwright.__main__ import main
from playwright.async_api import Browser, Playwright, async_playwright
+from zhenxun.configs.config import SYSTEM_PROXY
from zhenxun.services.log import logger
@@ -13,6 +18,8 @@ _browser: Browser | None = None
async def start_browser():
global _playwright
global _browser
+ install()
+ await check_playwright_env()
_playwright = await async_playwright().start()
_browser = await _playwright.chromium.launch()
@@ -33,13 +40,51 @@ def get_browser() -> Browser:
def install():
"""自动安装、更新 Chromium"""
- logger.info("正在检查 Chromium 更新")
- import sys
- from playwright.__main__ import main
+ def set_env_variables():
+ os.environ[
+ "PLAYWRIGHT_DOWNLOAD_HOST"] = "https://npmmirror.com/mirrors/playwright/"
+ if SYSTEM_PROXY:
+ os.environ["HTTPS_PROXY"] = SYSTEM_PROXY
- sys.argv = ["", "install", "chromium"]
+ def restore_env_variables():
+ os.environ.pop("PLAYWRIGHT_DOWNLOAD_HOST", None)
+ if SYSTEM_PROXY:
+ os.environ.pop("HTTPS_PROXY", None)
+ if original_proxy is not None:
+ os.environ["HTTPS_PROXY"] = original_proxy
+
+ def try_install_chromium():
+ try:
+ sys.argv = ["", "install", "chromium"]
+ main()
+ except SystemExit as e:
+ return e.code == 0
+ return False
+
+ logger.info("检查 Chromium 更新")
+
+ original_proxy = os.environ.get("HTTPS_PROXY")
+ set_env_variables()
+
+ success = try_install_chromium()
+
+ if not success:
+ logger.info("Chromium 更新失败,尝试从原始仓库下载,速度较慢")
+ os.environ["PLAYWRIGHT_DOWNLOAD_HOST"] = ""
+ success = try_install_chromium()
+
+ restore_env_variables()
+
+ if not success:
+ raise RuntimeError("未知错误,Chromium 下载失败")
+
+
+async def check_playwright_env():
+ """检查 Playwright 依赖"""
+ logger.info("检查 Playwright 依赖")
try:
- main()
- except SystemExit:
- pass
+ async with async_playwright() as p:
+ await p.chromium.launch()
+ except Exception as e:
+ raise ImportError("加载失败,Playwright 依赖不全,") from e
From 18f97b9bd5c5b496902cae7035c6a156e6fa81c7 Mon Sep 17 00:00:00 2001
From: HibiKier <775757368@qq.com>
Date: Mon, 12 Aug 2024 22:26:13 +0800
Subject: [PATCH 5/5] =?UTF-8?q?=E2=9C=A8=20=E6=B7=BB=E5=8A=A0=E6=9B=B4?=
=?UTF-8?q?=E6=96=B0=E5=A5=BD=E5=8F=8B=E7=BE=A4=E7=BB=84=E4=B8=8E=E4=BF=AE?=
=?UTF-8?q?=E5=A4=8D=E5=85=B6=E4=BB=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../admin/group_member_update/__init__.py | 34 ++-
.../builtin_plugins/hooks/_auth_checker.py | 3 +
zhenxun/builtin_plugins/init/__init__.py | 8 +-
.../scheduler/auto_update_group.py | 6 +-
zhenxun/plugins/one_friend/__init__.py | 8 +-
zhenxun/plugins/parse_bilibili/__init__.py | 86 ++++----
zhenxun/plugins/parse_bilibili/get_image.py | 18 +-
.../parse_bilibili/information_container.py | 9 +-
zhenxun/plugins/restart/__init__.py | 96 +++++++++
.../web_ui/api/tabs/manage/__init__.py | 19 +-
.../plugins/web_ui/api/tabs/manage/model.py | 10 +
.../web_ui/api/tabs/system/__init__.py | 201 +++++++++++-------
.../plugins/web_ui/api/tabs/system/model.py | 81 ++++---
zhenxun/plugins/word_bank/_model.py | 7 +-
14 files changed, 384 insertions(+), 202 deletions(-)
create mode 100644 zhenxun/plugins/restart/__init__.py
diff --git a/zhenxun/builtin_plugins/admin/group_member_update/__init__.py b/zhenxun/builtin_plugins/admin/group_member_update/__init__.py
index c7036cc8..48508b21 100644
--- a/zhenxun/builtin_plugins/admin/group_member_update/__init__.py
+++ b/zhenxun/builtin_plugins/admin/group_member_update/__init__.py
@@ -1,8 +1,10 @@
+import nonebot
from nonebot import on_notice
from nonebot.adapters import Bot
from nonebot.adapters.onebot.v11 import GroupIncreaseNoticeEvent
from nonebot.plugin import PluginMetadata
from nonebot_plugin_alconna import Alconna, Arparma, on_alconna
+from nonebot_plugin_apscheduler import scheduler
from nonebot_plugin_session import EventSession
from zhenxun.configs.config import NICKNAME
@@ -10,6 +12,7 @@ from zhenxun.configs.utils import PluginExtraData
from zhenxun.services.log import logger
from zhenxun.utils.enum import PluginType
from zhenxun.utils.message import MessageUtils
+from zhenxun.utils.platform import PlatformUtils
from zhenxun.utils.rules import admin_check, ensure_group
from ._data_source import MemberUpdateManage
@@ -39,6 +42,9 @@ _matcher = on_alconna(
)
+_notice = on_notice(priority=1, block=False)
+
+
@_matcher.handle()
async def _(bot: Bot, session: EventSession, arparma: Arparma):
if gid := session.id3 or session.id2:
@@ -50,9 +56,6 @@ async def _(bot: Bot, session: EventSession, arparma: Arparma):
await MessageUtils.build_message("群组id为空...").send()
-_notice = on_notice(priority=1, block=False)
-
-
@_notice.handle()
async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
# TODO: 其他适配器的加群自动更新群组成员信息
@@ -64,3 +67,28 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
session=event.user_id,
group_id=event.group_id,
)
+
+
+@scheduler.scheduled_job(
+ "interval",
+ minutes=5,
+)
+async def _():
+ for bot in nonebot.get_bots().values():
+ if PlatformUtils.get_platform(bot) == "qq":
+ try:
+ group_list, _ = await PlatformUtils.get_group_list(bot)
+ if group_list:
+ for group in group_list:
+ try:
+ await MemberUpdateManage.update(bot, group.group_id)
+ logger.debug("自动更新群组成员信息成功...")
+ except Exception as e:
+ logger.error(
+ f"Bot: {bot.self_id} 自动更新群组成员信息成功",
+ target=group.group_id,
+ e=e,
+ )
+ except Exception as e:
+ logger.error(f"Bot: {bot.self_id} 自动更新群组信息", e=e)
+ logger.debug(f"自动 Bot: {bot.self_id} 更新群组成员信息成功...")
diff --git a/zhenxun/builtin_plugins/hooks/_auth_checker.py b/zhenxun/builtin_plugins/hooks/_auth_checker.py
index 8a277165..e103cf95 100644
--- a/zhenxun/builtin_plugins/hooks/_auth_checker.py
+++ b/zhenxun/builtin_plugins/hooks/_auth_checker.py
@@ -236,6 +236,9 @@ class AuthChecker:
LimitManage.unblock(
matcher.plugin.name, user_id, group_id, channel_id
)
+ except AssertionError as e:
+ is_ignore = True
+ logger.debug("消息无法发送", session=session, e=e)
if cost_gold and user_id:
"""花费金币"""
try:
diff --git a/zhenxun/builtin_plugins/init/__init__.py b/zhenxun/builtin_plugins/init/__init__.py
index fa10c4d7..b3bab4db 100644
--- a/zhenxun/builtin_plugins/init/__init__.py
+++ b/zhenxun/builtin_plugins/init/__init__.py
@@ -23,13 +23,15 @@ async def _(bot: Bot):
if PlatformUtils.get_platform(bot) == "qq":
logger.debug(f"更新Bot: {bot.self_id} 的群认证...")
group_list, _ = await PlatformUtils.get_group_list(bot)
- gid_list = [g.group_id for g in group_list]
+ gid_list = [(g.group_id, g.group_name) for g in group_list]
db_group_list = await GroupConsole.all().values_list("group_id", flat=True)
create_list = []
update_id = []
- for gid in gid_list:
+ for gid, name in gid_list:
if gid not in db_group_list:
- create_list.append(GroupConsole(group_id=gid, group_flag=1))
+ create_list.append(
+ GroupConsole(group_id=gid, group_name=name, group_flag=1)
+ )
else:
update_id.append(gid)
if create_list:
diff --git a/zhenxun/builtin_plugins/scheduler/auto_update_group.py b/zhenxun/builtin_plugins/scheduler/auto_update_group.py
index 8e62bc69..dda1f3e3 100644
--- a/zhenxun/builtin_plugins/scheduler/auto_update_group.py
+++ b/zhenxun/builtin_plugins/scheduler/auto_update_group.py
@@ -17,7 +17,7 @@ async def _():
try:
await PlatformUtils.update_group(bot)
except Exception as e:
- logger.error(f"Bot: {bot.self_id} 自动更新群组信息", e=e)
+ logger.error(f"Bot: {bot.self_id} 自动更新群组信息", "自动更新群组", e=e)
logger.info("自动更新群组成员信息成功...")
@@ -33,5 +33,7 @@ async def _():
try:
await PlatformUtils.update_friend(bot)
except Exception as e:
- logger.error(f"自动更新好友信息错误", "自动更新好友", e=e)
+ logger.error(
+ f"Bot: {bot.self_id} 自动更新好友信息错误", "自动更新好友", e=e
+ )
logger.info("自动更新好友信息成功...")
diff --git a/zhenxun/plugins/one_friend/__init__.py b/zhenxun/plugins/one_friend/__init__.py
index 0191084f..7fa7c8bf 100644
--- a/zhenxun/plugins/one_friend/__init__.py
+++ b/zhenxun/plugins/one_friend/__init__.py
@@ -3,9 +3,7 @@ from io import BytesIO
from nonebot.adapters import Bot
from nonebot.plugin import PluginMetadata
-from nonebot_plugin_alconna import Alconna, Args
-from nonebot_plugin_alconna import At as alcAt
-from nonebot_plugin_alconna import Match, on_alconna
+from nonebot_plugin_alconna import Alconna, Args, At, Match, on_alconna
from nonebot_plugin_session import EventSession
from zhenxun.configs.utils import PluginExtraData
@@ -29,7 +27,7 @@ __plugin_meta__ = PluginMetadata(
)
_matcher = on_alconna(
- Alconna("one-friend", Args["text", str]["at?", alcAt]), priority=5, block=True
+ Alconna("one-friend", Args["text", str]["at?", At]), priority=5, block=True
)
_matcher.shortcut(
@@ -41,7 +39,7 @@ _matcher.shortcut(
@_matcher.handle()
-async def _(bot: Bot, text: str, at: Match[alcAt], session: EventSession):
+async def _(bot: Bot, text: str, at: Match[At], session: EventSession):
gid = session.id3 or session.id2
if not gid:
await MessageUtils.build_message("群组id为空...").finish()
diff --git a/zhenxun/plugins/parse_bilibili/__init__.py b/zhenxun/plugins/parse_bilibili/__init__.py
index 1d319093..3269a526 100644
--- a/zhenxun/plugins/parse_bilibili/__init__.py
+++ b/zhenxun/plugins/parse_bilibili/__init__.py
@@ -115,27 +115,28 @@ async def _(session: EventSession, message: UniMsg):
if get_url:
# 将链接统一发送给处理函数
- vd_info, live_info, vd_url, live_url, image_info, image_url = (
- await parse_bili_url(get_url, information_container)
- )
- if vd_info:
+ data = await parse_bili_url(get_url, information_container)
+ if data.vd_info:
# 判断一定时间内是否解析重复内容,或者是第一次解析
if (
- vd_url in _tmp.keys() and time.time() - _tmp[vd_url] > repet_second
- ) or vd_url not in _tmp.keys():
- pic = vd_info.get("pic", "") # 封面
- aid = vd_info.get("aid", "") # av号
- title = vd_info.get("title", "") # 标题
- author = vd_info.get("owner", {}).get("name", "") # UP主
- reply = vd_info.get("stat", {}).get("reply", "") # 回复
- favorite = vd_info.get("stat", {}).get("favorite", "") # 收藏
- coin = vd_info.get("stat", {}).get("coin", "") # 投币
- like = vd_info.get("stat", {}).get("like", "") # 点赞
- danmuku = vd_info.get("stat", {}).get("danmaku", "") # 弹幕
- ctime = vd_info["ctime"]
+ data.vd_url in _tmp.keys()
+ and time.time() - _tmp[data.vd_url] > repet_second
+ ) or data.vd_url not in _tmp.keys():
+ pic = data.vd_info.get("pic", "") # 封面
+ aid = data.vd_info.get("aid", "") # av号
+ title = data.vd_info.get("title", "") # 标题
+ author = data.vd_info.get("owner", {}).get("name", "") # UP主
+ reply = data.vd_info.get("stat", {}).get("reply", "") # 回复
+ favorite = data.vd_info.get("stat", {}).get("favorite", "") # 收藏
+ coin = data.vd_info.get("stat", {}).get("coin", "") # 投币
+ like = data.vd_info.get("stat", {}).get("like", "") # 点赞
+ danmuku = data.vd_info.get("stat", {}).get("danmaku", "") # 弹幕
+ ctime = data.vd_info["ctime"]
date = time.strftime("%Y-%m-%d", time.localtime(ctime))
- logger.info(f"解析bilibili转发 {vd_url}", "b站解析", session=session)
- _tmp[vd_url] = time.time()
+ logger.info(
+ f"解析bilibili转发 {data.vd_url}", "b站解析", session=session
+ )
+ _tmp[data.vd_url] = time.time()
_path = TEMP_PATH / f"{aid}.jpg"
await AsyncHttpx.download_file(pic, _path)
await MessageUtils.build_message(
@@ -145,33 +146,40 @@ async def _(session: EventSession, message: UniMsg):
]
).send()
- elif live_info:
+ elif data.live_info:
if (
- live_url in _tmp.keys() and time.time() - _tmp[live_url] > repet_second
- ) or live_url not in _tmp.keys():
- uid = live_info.get("uid", "") # 主播uid
- title = live_info.get("title", "") # 直播间标题
- description = live_info.get("description", "") # 简介,可能会出现标签
- user_cover = live_info.get("user_cover", "") # 封面
- keyframe = live_info.get("keyframe", "") # 关键帧画面
- live_time = live_info.get("live_time", "") # 开播时间
- area_name = live_info.get("area_name", "") # 分区
- parent_area_name = live_info.get("parent_area_name", "") # 父分区
- logger.info(f"解析bilibili转发 {live_url}", "b站解析", session=session)
- _tmp[live_url] = time.time()
+ data.live_url in _tmp.keys()
+ and time.time() - _tmp[data.live_url] > repet_second
+ ) or data.live_url not in _tmp.keys():
+ uid = data.live_info.get("uid", "") # 主播uid
+ title = data.live_info.get("title", "") # 直播间标题
+ description = data.live_info.get(
+ "description", ""
+ ) # 简介,可能会出现标签
+ user_cover = data.live_info.get("user_cover", "") # 封面
+ keyframe = data.live_info.get("keyframe", "") # 关键帧画面
+ live_time = data.live_info.get("live_time", "") # 开播时间
+ area_name = data.live_info.get("area_name", "") # 分区
+ parent_area_name = data.live_info.get("parent_area_name", "") # 父分区
+ logger.info(
+ f"解析bilibili转发 {data.live_url}", "b站解析", session=session
+ )
+ _tmp[data.live_url] = time.time()
await MessageUtils.build_message(
[
Image(url=user_cover),
f"开播用户:https://space.bilibili.com/{uid}\n开播时间:{live_time}\n直播分区:{parent_area_name}——>{area_name}\n标题:{title}\n简介:{description}\n直播截图:\n",
Image(url=keyframe),
- f"{live_url}",
+ f"{data.live_url}",
]
).send()
- elif image_info:
+ elif data.image_info:
if (
- image_url in _tmp.keys()
- and time.time() - _tmp[image_url] > repet_second
- ) or image_url not in _tmp.keys():
- logger.info(f"解析bilibili转发 {image_url}", "b站解析", session=session)
- _tmp[image_url] = time.time()
- await image_info.send()
+ data.image_url in _tmp.keys()
+ and time.time() - _tmp[data.image_url] > repet_second
+ ) or data.image_url not in _tmp.keys():
+ logger.info(
+ f"解析bilibili转发 {data.image_url}", "b站解析", session=session
+ )
+ _tmp[data.image_url] = time.time()
+ await data.image_info.send()
diff --git a/zhenxun/plugins/parse_bilibili/get_image.py b/zhenxun/plugins/parse_bilibili/get_image.py
index bbc005c5..3b8c70c8 100644
--- a/zhenxun/plugins/parse_bilibili/get_image.py
+++ b/zhenxun/plugins/parse_bilibili/get_image.py
@@ -1,5 +1,6 @@
import os
import re
+from pathlib import Path
from nonebot_plugin_alconna import UniMessage
@@ -11,14 +12,14 @@ from zhenxun.utils.message import MessageUtils
from zhenxun.utils.user_agent import get_user_agent_str
-async def resize(path: str):
+async def resize(path: Path):
"""调整图像大小的异步函数
参数:
path (str): 图像文件路径
"""
- A = BuildImage(background=path)
- await A.resize(0.5)
+ A = BuildImage.open(path)
+ await A.resize(0.8)
await A.save(path)
@@ -56,21 +57,18 @@ async def get_image(url) -> UniMessage | None:
# 根据编号构建保存路径
if cv_number:
- screenshot_path = f"{TEMP_PATH}/bilibili_cv_{cv_number}.png"
+ screenshot_path = TEMP_PATH / "bilibili_cv_{cv_number}.png"
elif opus_number:
- screenshot_path = f"{TEMP_PATH}/bilibili_opus_{opus_number}.png"
+ screenshot_path = TEMP_PATH / "bilibili_opus_{opus_number}.png"
elif t_opus_number:
- screenshot_path = f"{TEMP_PATH}/bilibili_opus_{t_opus_number}.png"
+ screenshot_path = TEMP_PATH / "bilibili_opus_{t_opus_number}.png"
# t.bilibili.com和https://www.bilibili.com/opus在内容上是一样的,为便于维护,调整url至https://www.bilibili.com/opus/
url = f"https://www.bilibili.com/opus/{t_opus_number}"
-
if screenshot_path:
try:
# 如果文件不存在,进行截图
- if not os.path.exists(screenshot_path):
+ if not screenshot_path.exists():
# 创建页面
- # random.choice(),从列表中随机抽取一个对象
- user_agent = get_user_agent_str()
try:
async with AsyncPlaywright.new_page() as page:
await page.set_viewport_size({"width": 5120, "height": 2560})
diff --git a/zhenxun/plugins/parse_bilibili/information_container.py b/zhenxun/plugins/parse_bilibili/information_container.py
index 1cbf651f..ddb685f8 100644
--- a/zhenxun/plugins/parse_bilibili/information_container.py
+++ b/zhenxun/plugins/parse_bilibili/information_container.py
@@ -50,11 +50,4 @@ class InformationContainer:
setattr(self, f"_{info_type}", new_value)
def get_information(self):
- return (
- self.vd_info,
- self.live_info,
- self.vd_url,
- self.live_url,
- self.image_info,
- self.image_url,
- )
+ return self
diff --git a/zhenxun/plugins/restart/__init__.py b/zhenxun/plugins/restart/__init__.py
new file mode 100644
index 00000000..eed6fa17
--- /dev/null
+++ b/zhenxun/plugins/restart/__init__.py
@@ -0,0 +1,96 @@
+import os
+import platform
+from pathlib import Path
+
+import nonebot
+from nonebot import on_command
+from nonebot.adapters import Bot
+from nonebot.params import ArgStr
+from nonebot.permission import SUPERUSER
+from nonebot.plugin import PluginMetadata
+from nonebot.rule import to_me
+from nonebot_plugin_session import EventSession
+
+from zhenxun.configs.config import NICKNAME
+from zhenxun.configs.utils import PluginExtraData
+from zhenxun.services.log import logger
+from zhenxun.utils.enum import PluginType
+from zhenxun.utils.message import MessageUtils
+from zhenxun.utils.platform import PlatformUtils
+
+__plugin_meta__ = PluginMetadata(
+ name="重启",
+ description="执行脚本重启真寻",
+ usage=f"""
+ 重启
+ """.strip(),
+ extra=PluginExtraData(
+ author="HibiKier", version="0.1", plugin_type=PluginType.SUPERUSER
+ ).dict(),
+)
+
+
+_matcher = on_command(
+ "重启",
+ permission=SUPERUSER,
+ rule=to_me(),
+ priority=1,
+ block=True,
+)
+
+driver = nonebot.get_driver()
+
+
+RESTART_MARK = Path() / "is_restart"
+
+RESTART_FILE = Path() / "restart.sh"
+
+
+@_matcher.got(
+ "flag",
+ prompt=f"确定是否重启{NICKNAME}?确定请回复[是|好|确定](重启失败咱们将失去联系,请谨慎!)",
+)
+async def _(bot: Bot, session: EventSession, flag: str = ArgStr("flag")):
+ if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
+ await MessageUtils.build_message(f"开始重启{NICKNAME}..请稍等...").send()
+ with open(RESTART_MARK, "w", encoding="utf8") as f:
+ f.write(f"{bot.self_id} {session.id1}")
+ logger.info("开始重启真寻...", "重启", session=session)
+ if str(platform.system()).lower() == "windows":
+ import sys
+
+ python = sys.executable
+ os.execl(python, python, *sys.argv)
+ else:
+ os.system("./restart.sh")
+ else:
+ await MessageUtils.build_message("已取消操作...").send()
+
+
+@driver.on_bot_connect
+async def _(bot: Bot):
+ if str(platform.system()).lower() != "windows":
+ if not RESTART_FILE.exists():
+ with open(RESTART_FILE, "w", encoding="utf8") as f:
+ f.write(
+ f"pid=$(netstat -tunlp | grep "
+ + str(bot.config.port)
+ + " | awk '{print $7}')\n"
+ "pid=${pid%/*}\n"
+ "kill -9 $pid\n"
+ "sleep 3\n"
+ "python3 bot.py"
+ )
+ os.system("chmod +x ./restart.sh")
+ logger.info(
+ "已自动生成 restart.sh(重启) 文件,请检查脚本是否与本地指令符合..."
+ )
+ if RESTART_MARK.exists():
+ with open(RESTART_MARK, "r", encoding="utf8") as f:
+ bot_id, session_id = f.read().split()
+ if bot := nonebot.get_bot(bot_id):
+ if target := PlatformUtils.get_target(bot, session_id):
+ await MessageUtils.build_message(f"{NICKNAME}已成功重启!").send(
+ target, bot=bot
+ )
+ RESTART_MARK.unlink()
diff --git a/zhenxun/plugins/web_ui/api/tabs/manage/__init__.py b/zhenxun/plugins/web_ui/api/tabs/manage/__init__.py
index 1067cfb8..683b3a71 100644
--- a/zhenxun/plugins/web_ui/api/tabs/manage/__init__.py
+++ b/zhenxun/plugins/web_ui/api/tabs/manage/__init__.py
@@ -27,6 +27,7 @@ from ....config import AVA_URL, GROUP_AVA_URL
from ....utils import authentication
from ...logs.log_manager import LOG_STORAGE
from .model import (
+ ClearRequest,
DeleteFriend,
Friend,
FriendRequestResult,
@@ -143,8 +144,12 @@ async def _(bot_id: str) -> Result:
"/get_request_count", dependencies=[authentication()], description="获取请求数量"
)
async def _() -> Result:
- f_count = await FgRequest.filter(request_type=RequestType.FRIEND).count()
- g_count = await FgRequest.filter(request_type=RequestType.GROUP).count()
+ f_count = await FgRequest.filter(
+ request_type=RequestType.FRIEND, handle_type__isnull=True
+ ).count()
+ g_count = await FgRequest.filter(
+ request_type=RequestType.GROUP, handle_type__isnull=True
+ ).count()
data = {
"friend_count": f_count,
"group_count": g_count,
@@ -196,13 +201,13 @@ async def _() -> Result:
return Result.ok(req_result, f"{NICKNAME}带来了最新的数据!")
-@router.delete(
+@router.post(
"/clear_request", dependencies=[authentication()], description="清空请求列表"
)
-async def _(request_type: Literal["private", "group"]) -> Result:
- await FgRequest.filter(handle_type__not_isnull=True).update(
- handle_type=RequestHandleType.IGNORE
- )
+async def _(cr: ClearRequest) -> Result:
+ await FgRequest.filter(
+ handle_type__isnull=True, request_type=cr.request_type
+ ).update(handle_type=RequestHandleType.IGNORE)
return Result.ok(info="成功清除了数据!")
diff --git a/zhenxun/plugins/web_ui/api/tabs/manage/model.py b/zhenxun/plugins/web_ui/api/tabs/manage/model.py
index 8df5a6cd..64b64e8e 100644
--- a/zhenxun/plugins/web_ui/api/tabs/manage/model.py
+++ b/zhenxun/plugins/web_ui/api/tabs/manage/model.py
@@ -2,6 +2,8 @@ from typing import Literal
from pydantic import BaseModel
+from zhenxun.utils.enum import RequestType
+
class Group(BaseModel):
"""
@@ -123,6 +125,14 @@ class GroupRequestResult(FriendRequestResult):
"""群聊名称"""
+class ClearRequest(BaseModel):
+ """
+ 清空请求
+ """
+
+ request_type: RequestType
+
+
class HandleRequest(BaseModel):
"""
操作请求接收数据
diff --git a/zhenxun/plugins/web_ui/api/tabs/system/__init__.py b/zhenxun/plugins/web_ui/api/tabs/system/__init__.py
index 61430144..55c56764 100644
--- a/zhenxun/plugins/web_ui/api/tabs/system/__init__.py
+++ b/zhenxun/plugins/web_ui/api/tabs/system/__init__.py
@@ -5,117 +5,158 @@ from typing import List, Optional
from fastapi import APIRouter
+from zhenxun.utils._build_image import BuildImage
+
from ....base_model import Result
from ....utils import authentication, get_system_disk
from .model import AddFile, DeleteFile, DirFile, RenameFile, SaveFile
router = APIRouter(prefix="/system")
+IMAGE_TYPE = ["jpg", "jpeg", "png", "gif", "bmp", "webp", "svg"]
-@router.get("/get_dir_list", dependencies=[authentication()], description="获取文件列表")
+@router.get(
+ "/get_dir_list", dependencies=[authentication()], description="获取文件列表"
+)
async def _(path: Optional[str] = None) -> Result:
- base_path = Path(path) if path else Path()
- data_list = []
- for file in os.listdir(base_path):
- data_list.append(DirFile(is_file=not (base_path / file).is_dir(), name=file, parent=path))
- return Result.ok(data_list)
+ base_path = Path(path) if path else Path()
+ data_list = []
+ for file in os.listdir(base_path):
+ file_path = base_path / file
+ is_image = False
+ for t in IMAGE_TYPE:
+ if file.endswith(f".{t}"):
+ is_image = True
+ break
+ data_list.append(
+ DirFile(
+ is_file=not file_path.is_dir(),
+ is_image=is_image,
+ name=file,
+ parent=path,
+ )
+ )
+ return Result.ok(data_list)
-@router.get("/get_resources_size", dependencies=[authentication()], description="获取文件列表")
+@router.get(
+ "/get_resources_size", dependencies=[authentication()], description="获取文件列表"
+)
async def _(full_path: Optional[str] = None) -> Result:
- return Result.ok(await get_system_disk(full_path))
+ return Result.ok(await get_system_disk(full_path))
@router.post("/delete_file", dependencies=[authentication()], description="删除文件")
async def _(param: DeleteFile) -> Result:
- path = Path(param.full_path)
- if not path or not path.exists():
- return Result.warning_("文件不存在...")
- try:
- path.unlink()
- return Result.ok('删除成功!')
- except Exception as e:
- return Result.warning_('删除失败: ' + str(e))
-
-@router.post("/delete_folder", dependencies=[authentication()], description="删除文件夹")
+ path = Path(param.full_path)
+ if not path or not path.exists():
+ return Result.warning_("文件不存在...")
+ try:
+ path.unlink()
+ return Result.ok("删除成功!")
+ except Exception as e:
+ return Result.warning_("删除失败: " + str(e))
+
+
+@router.post(
+ "/delete_folder", dependencies=[authentication()], description="删除文件夹"
+)
async def _(param: DeleteFile) -> Result:
- path = Path(param.full_path)
- if not path or not path.exists() or path.is_file():
- return Result.warning_("文件夹不存在...")
- try:
- shutil.rmtree(path.absolute())
- return Result.ok('删除成功!')
- except Exception as e:
- return Result.warning_('删除失败: ' + str(e))
-
+ path = Path(param.full_path)
+ if not path or not path.exists() or path.is_file():
+ return Result.warning_("文件夹不存在...")
+ try:
+ shutil.rmtree(path.absolute())
+ return Result.ok("删除成功!")
+ except Exception as e:
+ return Result.warning_("删除失败: " + str(e))
+
@router.post("/rename_file", dependencies=[authentication()], description="重命名文件")
async def _(param: RenameFile) -> Result:
- path = (Path(param.parent) / param.old_name) if param.parent else Path(param.old_name)
- if not path or not path.exists():
- return Result.warning_("文件不存在...")
- try:
- path.rename(path.parent / param.name)
- return Result.ok('重命名成功!')
- except Exception as e:
- return Result.warning_('重命名失败: ' + str(e))
-
+ path = (
+ (Path(param.parent) / param.old_name) if param.parent else Path(param.old_name)
+ )
+ if not path or not path.exists():
+ return Result.warning_("文件不存在...")
+ try:
+ path.rename(path.parent / param.name)
+ return Result.ok("重命名成功!")
+ except Exception as e:
+ return Result.warning_("重命名失败: " + str(e))
-@router.post("/rename_folder", dependencies=[authentication()], description="重命名文件夹")
+
+@router.post(
+ "/rename_folder", dependencies=[authentication()], description="重命名文件夹"
+)
async def _(param: RenameFile) -> Result:
- path = (Path(param.parent) / param.old_name) if param.parent else Path(param.old_name)
- if not path or not path.exists() or path.is_file():
- return Result.warning_("文件夹不存在...")
- try:
- new_path = path.parent / param.name
- shutil.move(path.absolute(), new_path.absolute())
- return Result.ok('重命名成功!')
- except Exception as e:
- return Result.warning_('重命名失败: ' + str(e))
-
+ path = (
+ (Path(param.parent) / param.old_name) if param.parent else Path(param.old_name)
+ )
+ if not path or not path.exists() or path.is_file():
+ return Result.warning_("文件夹不存在...")
+ try:
+ new_path = path.parent / param.name
+ shutil.move(path.absolute(), new_path.absolute())
+ return Result.ok("重命名成功!")
+ except Exception as e:
+ return Result.warning_("重命名失败: " + str(e))
+
@router.post("/add_file", dependencies=[authentication()], description="新建文件")
async def _(param: AddFile) -> Result:
- path = (Path(param.parent) / param.name) if param.parent else Path(param.name)
- if path.exists():
- return Result.warning_("文件已存在...")
- try:
- path.open('w')
- return Result.ok('新建文件成功!')
- except Exception as e:
- return Result.warning_('新建文件失败: ' + str(e))
-
+ path = (Path(param.parent) / param.name) if param.parent else Path(param.name)
+ if path.exists():
+ return Result.warning_("文件已存在...")
+ try:
+ path.open("w")
+ return Result.ok("新建文件成功!")
+ except Exception as e:
+ return Result.warning_("新建文件失败: " + str(e))
+
@router.post("/add_folder", dependencies=[authentication()], description="新建文件夹")
async def _(param: AddFile) -> Result:
- path = (Path(param.parent) / param.name) if param.parent else Path(param.name)
- if path.exists():
- return Result.warning_("文件夹已存在...")
- try:
- path.mkdir()
- return Result.ok('新建文件夹成功!')
- except Exception as e:
- return Result.warning_('新建文件夹失败: ' + str(e))
+ path = (Path(param.parent) / param.name) if param.parent else Path(param.name)
+ if path.exists():
+ return Result.warning_("文件夹已存在...")
+ try:
+ path.mkdir()
+ return Result.ok("新建文件夹成功!")
+ except Exception as e:
+ return Result.warning_("新建文件夹失败: " + str(e))
@router.get("/read_file", dependencies=[authentication()], description="读取文件")
async def _(full_path: str) -> Result:
- path = Path(full_path)
- if not path.exists():
- return Result.warning_("文件不存在...")
- try:
- text = path.read_text(encoding='utf-8')
- return Result.ok(text)
- except Exception as e:
- return Result.warning_('新建文件夹失败: ' + str(e))
-
+ path = Path(full_path)
+ if not path.exists():
+ return Result.warning_("文件不存在...")
+ try:
+ text = path.read_text(encoding="utf-8")
+ return Result.ok(text)
+ except Exception as e:
+ return Result.warning_("读取文件失败: " + str(e))
+
+
@router.post("/save_file", dependencies=[authentication()], description="读取文件")
async def _(param: SaveFile) -> Result:
- path = Path(param.full_path)
- try:
- with path.open('w') as f:
- f.write(param.content)
- return Result.ok("更新成功!")
- except Exception as e:
- return Result.warning_('新建文件夹失败: ' + str(e))
\ No newline at end of file
+ path = Path(param.full_path)
+ try:
+ with path.open("w") as f:
+ f.write(param.content)
+ return Result.ok("更新成功!")
+ except Exception as e:
+ return Result.warning_("保存文件失败: " + str(e))
+
+
+@router.get("/get_image", dependencies=[authentication()], description="读取图片base64")
+async def _(full_path: str) -> Result:
+ path = Path(full_path)
+ if not path.exists():
+ return Result.warning_("文件不存在...")
+ try:
+ return Result.ok(BuildImage.open(path).pic2bs4())
+ except Exception as e:
+ return Result.warning_("获取图片失败: " + str(e))
diff --git a/zhenxun/plugins/web_ui/api/tabs/system/model.py b/zhenxun/plugins/web_ui/api/tabs/system/model.py
index b3b5a45f..7cabc86a 100644
--- a/zhenxun/plugins/web_ui/api/tabs/system/model.py
+++ b/zhenxun/plugins/web_ui/api/tabs/system/model.py
@@ -1,6 +1,3 @@
-
-
-
from datetime import datetime
from typing import Literal, Optional
@@ -8,57 +5,59 @@ from pydantic import BaseModel
class DirFile(BaseModel):
+ """
+ 文件或文件夹
+ """
- """
- 文件或文件夹
- """
+ is_file: bool
+ """是否为文件"""
+ is_image: bool
+ """是否为图片"""
+ name: str
+ """文件夹或文件名称"""
+ parent: Optional[str] = None
+ """父级"""
- is_file: bool
- """是否为文件"""
- name: str
- """文件夹或文件名称"""
- parent: Optional[str] = None
- """父级"""
class DeleteFile(BaseModel):
+ """
+ 删除文件
+ """
- """
- 删除文件
- """
+ full_path: str
+ """文件全路径"""
- full_path: str
- """文件全路径"""
class RenameFile(BaseModel):
+ """
+ 删除文件
+ """
- """
- 删除文件
- """
- parent: Optional[str]
- """父路径"""
- old_name: str
- """旧名称"""
- name: str
- """新名称"""
+ parent: Optional[str]
+ """父路径"""
+ old_name: str
+ """旧名称"""
+ name: str
+ """新名称"""
class AddFile(BaseModel):
+ """
+ 新建文件
+ """
- """
- 新建文件
- """
- parent: Optional[str]
- """父路径"""
- name: str
- """新名称"""
+ parent: Optional[str]
+ """父路径"""
+ name: str
+ """新名称"""
class SaveFile(BaseModel):
-
- """
- 保存文件
- """
- full_path: str
- """全路径"""
- content: str
- """内容"""
+ """
+ 保存文件
+ """
+
+ full_path: str
+ """全路径"""
+ content: str
+ """内容"""
diff --git a/zhenxun/plugins/word_bank/_model.py b/zhenxun/plugins/word_bank/_model.py
index abf03779..f31620a2 100644
--- a/zhenxun/plugins/word_bank/_model.py
+++ b/zhenxun/plugins/word_bank/_model.py
@@ -123,13 +123,12 @@ class WordBank(Model):
# 对图片做额外处理
image_path = None
if word_type == 3:
- _file = (
- path / "problem" / f"{group_id}" / f"{user_id}_{int(time.time())}.jpg"
- )
+ _uuid = uuid.uuid1()
+ _file = path / "problem" / f"{group_id}" / f"{user_id}_{_uuid}.jpg"
_file.parent.mkdir(exist_ok=True, parents=True)
await AsyncHttpx.download_file(problem, _file)
problem = get_img_hash(_file)
- image_path = f"problem/{group_id}/{user_id}_{int(time.time())}.jpg"
+ image_path = f"problem/{group_id}/{user_id}_{_uuid}.jpg"
new_answer, placeholder_list = await cls._answer2format(
answer, user_id, group_id
)