Compare commits

...
22 Commits
Author SHA1 Message Date
HibiKier ae5df38c21 🐛 修复图片模板方法 2024-11-16 17:59:15 +08:00
HibiKier 545f6fd7f9 🎨 入群检测代码优化 2024-11-14 18:56:53 +08:00
HibiKier 4c7c223b2c 🐛 修复我的信息at用户时头像不正确 2024-11-14 15:27:17 +08:00
HibiKier 14b983cfa0 💬 修改md 2024-11-09 13:53:38 +08:00
HibiKier 229908207b 💬 更新md 2024-11-09 13:53:16 +08:00
HibiKier cfe7dfd6b5 💬 修改md 2024-11-08 21:00:48 +08:00
HibiKier b2da0a902d 🎨 playwright添加cookie参数 2024-11-07 13:38:20 +08:00
HibiKier 3f06131c34 💬 修改md 2024-11-07 00:29:31 +08:00
HibiKier 24f1a1ca9a 💬 修改测试url 2024-11-07 00:28:41 +08:00
HibiKier 54a74cdd91 🎨 更新md 2024-11-05 20:45:11 +08:00
HibiKier 7ca4c18e1c 🎨 修改md 2024-11-05 15:54:53 +08:00
HibiKier a2b7980ae2 💬 修改版本号 2024-11-05 15:51:19 +08:00
HibiKier e75a56fe08 🐛 修复自定义pixiv反向代理无法对涩图生效 2024-11-05 15:47:59 +08:00
HibiKier abd8b9b705 ✨ 添加用户消息撤回命令 (#1719) 2024-11-05 15:34:45 +08:00
HibiKier 54d2ba1df4 🐛 修复邀请群组强制退出 2024-11-05 14:47:07 +08:00
HibiKier dbfeeac313 Merge branch 'dev' of https://github.com/HibiKier/zhenxun_bot into dev 2024-10-29 08:27:02 +08:00
HibiKier 93316be5fe 🎨 工具代码优化 2024-10-29 08:26:41 +08:00
AkashiCoin 60b78a9f1c 🎉 chore(version): Update version to v0.2.4-6359ba6 (#1692) 2024-10-28 09:41:35 +08:00
HibiKier 6359ba63f9 💬 更新权限检查日志提示 2024-10-24 16:27:37 +08:00
HibiKier 2853a2feaa ✨ ban限制依赖类型插件 2024-10-24 11:09:01 +08:00
HibiKier c9b864ca54 🐛 修复合并转发在bytes传输下图片丢失 2024-10-23 15:21:53 +08:00
梦璃雨落 6519b1cad4 🐞 fix: 更新货物未找到异常的信息处理方式 (#1713) 2024-10-23 13:19:47 +08:00
35 changed files with 282 additions and 188 deletions
+2 -1
View File
@@ -25,7 +25,8 @@
"ujson",
"unban",
"userinfo",
"zhenxun"
"zhenxun",
"jsdelivr"
],
"python.analysis.autoImportCompletions": true,
"python.testing.pytestArgs": ["tests"],
+53 -114
View File
@@ -60,7 +60,7 @@
<img width="350" height="350" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/help.png"/>
<img width="250" height="500" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/html_help.png"/>
<img width="180" height="450" src="https://github.com/HibiKier/zhenxun_bot/blob/dev/docs_image/zhenxun_help.png"/>
<img width="180" height="450" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/zhenxun_help.png"/>
</div>
@@ -68,11 +68,11 @@
### 1. 体验一下?
这是一个免费的,版本为 dev 的 zhenxun,你可以通过 napcat 或拉格朗日等直接连接用于体验与测试
这是一个免费的,版本为 dev 的 zhenxun,你可以通过 [napcat](https://github.com/NapNeko/NapCatQQ) 或 [拉格朗日](https://github.com/LagrangeDev/Lagrange.Core) 以及 [matcha](https://github.com/A-kirami/matcha) 等直接连接用于体验与测试
(球球了测试君!)
```
Url: 43.143.112.57:11451/onebot/v11/ws
Url: ws://test.zhenxun.org:8080/onebot/v11/ws
AccessToken: PUBLIC_ZHENXUN_TEST
注:你无法获得超级用户权限
@@ -95,13 +95,14 @@ AccessToken: PUBLIC_ZHENXUN_TEST
<details>
<summary> <strong> WebUI </strong>后台示例图 </summary>
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui1.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui2.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui3.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui4.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui5.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui6.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui7.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui00.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui01.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui02.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui03.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui04.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui05.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui06.png)
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/webui07.png)
</details>
@@ -111,7 +112,8 @@ AccessToken: PUBLIC_ZHENXUN_TEST
## ~~来点优点?~~ 可爱难道还不够吗
- 实现了许多功能,且提供了大量功能管理命令
- 实现了许多功能,且提供了大量功能管理命令,进行了多平台适配,兼容 nb2 商店插件
- 拥有完善可用的 webui
- 通过 Config 配置项将所有插件配置统计保存至 config.yaml,利于统一用户修改
- 方便增删插件,原生 nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
- 提供了 cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`PluginCdBlock` 等
@@ -165,161 +167,97 @@ python bot.py
```
<!-- ## 功能列表 (旧版列表)
## 功能列表
<details>
<summary>已实现的功能</summary>
<summary>内置功能</summary>
### 已实现的常用功能
**真寻原 `plugins` 插件文件夹已迁移至其他仓库,当前内置仅保留必要的功能**
- [x] 昵称系统(群与群与私聊分开.)
### 基础功能
- [x] 图灵 AI(会把'你'等关键字替换为你的昵称),且带有 [AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus),够味
- [x] 昵称系统(群与群与私聊分开)
- [x] 签到/我的签到/好感度排行/好感度总排行(影响色图概率和开箱次数,支持配置)
- [x] 发送某文件夹下的随机图片(支持自定义,默认:美图,萝莉,壁纸)
- [x] 色图(这不是基础功能嘛喂)
- [x] coser
- [x] 黑白草图生成器
- [x] 鸡汤/语录
- [x] 骂我(钉宫语音)
- [x] 戳一戳(概率发送美图,钉宫语音或者戳回去)
- [x] 模拟开箱/我的开箱/群开箱统计/我的金色/设置 cookie(csgo,内置爬虫脚本,需要提前抓取数据和图片,需要 session,可能需要代理,阿里云服务器等 ip 也许已经被 ban 了(我无代理访问失败),如果访问太多账号 API 调用可能被禁止访问 api!)
- [x] 鲁迅说过
- [x] 构造假消息(自定义的分享链接)
- [x] 商店/我的金币/购买道具/使用道具
- [x] 8 种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
- [x] 我有一个朋友想问问..(借鉴 pcrbot 插件)
- [x] 原神黄历
- [x] 原神今日素材
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 原神便笺查询
- [x] 原神玩家查询
- [x] 原神树脂提醒
- [x] 原神签到/自动签到
- [x] 金币红包
- [x] 微博热搜
- [x] B 站主播/UP/番剧订阅
- [x] pil 对图片的一些操作
- [x] BUFF 饰品底价查询(需要 session)
- [x] 天气查询
- [x] 疫情查询
- [x] bt 磁力搜索(咳咳,这功能我想 dddd)
- [x] reimu 搜索(上车) (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
- [x] 靠图识番 (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
- [x] 以图搜图 (使用[nonebot_plugin_picsearcher](https://github.com/synodriver/nonebot_plugin_picsearcher)插件)
- [x] 搜番
- [x] 点歌 [nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)插件(删除了选歌和评论)
- [x] epic 免费游戏
- [x] p 站排行榜
- [x] p 站搜图
- [x] 翻译(日英韩)
- [x] pix 图库(一个自己的图库,含有增删查改,黑名单等命令)
- [x] 商店/我的金币/购买道具/使用道具/金币排行(完整的商店添加/购买/使用流程)
- [x] 查看当前群欢迎消息
- [x] 查看该群自己的权限
- [x] 我的信息(只是为了看看什么时候入群)
- [x] 更新信息(如果继续更新的话)
- [x] go-cqhttp 最新版下载和上传(不需要请删除)
- [x] 撤回
- [x] 滴滴滴-(用户对超级用户发送消息)
- [x] 金币红包/金币排行
- [x] 俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
- [x] 网易云热评
- [x] 念首古诗
- [x] 获取 b 站视频封面
- [x] 通过 PID 获取图片
- [x] 个人信息查看(群组内权限,聊天频率等)
- [x] 消息撤回
- [x] 功能统计可视化
- [x] 词云
- [x] 关于
- [x] 三种样式的帮助菜单
### 已实现的管理员功能
### 管理员功能
- [x] 管理员帮助
- [x] 更新群组成员信息
- [x] 95%的群功能开关
- [x] 查看群内被动技能状态
- [x] 自定义群欢迎消息(是真寻的不是管家的!)
- [x] .ban/.unban(支持设置 ban 时长)= 黑白名单
- [x] 刷屏禁言相关:刷屏检测设置/设置禁言时长/设置检测次数
- [x] 上传图片/连续上传图片 (上传图片至指定图库)
- [x] 移动图片 (同上)
- [x] 删除图片 (同上)
- [x] 群内 B 站订阅
- [x] 词条设置
- [x] 休息吧/醒来
- [x] ban/unban(支持设置 ban 时长)= 群组及用户的黑名单
- [x] 休息吧/醒来(群组内真寻状态)
### 已实现的超级用户功能
### 超级用户功能
- [x] 超级用户帮助
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
- [x] 开启/关闭指定群的广播通知
- [x] 群组管理,退群指令等
- [x] 广播
- [x] 自检(检查系统状态)
- [x] 所有群组/所有好友
- [x] 退出指定群
- [x] 更新好友信息/更新群信息
- [x] /t(对用户进行回复或发送消息)
- [x] 上传/删除/修改商品(需要编写对应的商品功能)
- [x] 节日红包发送
- [x] 修改群权限
- [x] ban
- [x] 更新色图
- [x] 更新价格/更加图片(csgo 开箱)
- [x] 重载原神/方舟/赛马娘/坎公骑冠剑卡池
- [x] 更新原神今日素材/更新原神资源信息
- [x] PIX 相关操作
- [x] 检查更新真寻
- [x] 检查更新
- [x] 重启
- [x] 添加/删除/查看群白名单
- [x] 功能开关(更多设置)
- [x] 功能状态
- [x] b 了
- [x] 执行 sql
- [x] 执行 SQL
- [x] 重载配置
- [x] 清理临时数据
- [x] 增删群认证
- [x] 同意/拒绝好友/群聊请求
- [x] 配置重载
- [x] 添加/移除/更新插件/插件商店(plugins 库以及扩展库)
- [x] WebUI API(对真寻前端的支持)
#### 超级用户的被动技能
- [x] 邀请入群提醒(别人邀请真寻入群)
- [x] 邀请入群提醒(别人邀请真寻入群,可配置自动同意)
- [x] 添加好友提醒(别人添加真寻好友)
- [x] 添加好友提醒(别人添加真寻好友,可配置自动同意)
### 已实现的被动技能
- [x] 进群欢迎消息
### 被动技能
- [x] 群早晚安
- [x] 每日开箱重置提醒
- [x] b 站转发解析(解析 b 站分享信息,支持 bv,bilibili 链接,b 站手机端转发卡片,cv,b23.tv),且 5 分钟内不解析相同 url
- [x] 丢人爬(爬表情包)
- [x] epic 通知(每日发送 epic 免费游戏链接)
- [x] 原神黄历提醒
- [x] 复读
### 已实现的看不见的技能
- [x] 刷屏禁言检测
### 看不见的技能
- [x] 功能调用统计
- [x] 聊天记录统计
- [x] 检测恶意触发命令(将被最高权限 ban 掉 30 分钟,只有最高权限(9 级)可以进行 unban)
- [x] 自动同意好友请求,加群请求将会提醒管理员,退群提示,加群欢迎等等
- [x] 群聊时间检测(当群聊最后一人发言时间大于当前 36 小时后将关闭该群所有通知(即被动技能))
- [x] 自动同意好友/群组请求,加群请求将会提醒管理员,退群提示,加群欢迎等等
- [x] 群聊时间检测(当群聊最后一人发言时间大于当前 48 小时后将关闭该群所有通知(即被动技能))
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
- [x] 群权限系统
- [x] 定时更新权限
- [x] 自动配置重载
- [x] 强制入群保护
- [x] 自定备份(可配置)
- [x] 笨蛋检测(当使用功能名称当指令时真寻会跳出来狠狠嘲笑并帮助)
</details> -->
### 更多插件...
## [爱发电](https://afdian.net/@HibiKier)
- [更多插件](https://github.com/zhenxun-org/zhenxun_bot_plugins)
- [第三方插件索引库](https://github.com/zhenxun-org/zhenxun_bot_plugins_index)
</details>
## [爱发电](https://afdian.com/a/HibiKier)
<details>
<summary>爱发电 以及 感谢投喂 </summary>
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
<img width="365px" height="450px" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/afd.jpg">
### 感谢名单
@@ -369,6 +307,7 @@ python bot.py
[哇](https://afdian.net/u/9b266244f23911eca19052540025c377)
[yajiwa](https://github.com/yajiwa)
[爆金币](https://afdian.net/u/0d78879ef23711ecb22452540025c377)
...
</details>
+1 -1
View File
@@ -1 +1 @@
__version__: v0.2.4-fix1
__version__: v0.2.4-fix2
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

@@ -235,7 +235,10 @@ class AuthChecker:
return
if plugin := await PluginInfo.get_or_none(module_path=module_path):
if plugin.plugin_type == PluginType.HIDDEN:
logger.debug("插件为HIDDEN,已跳过...")
logger.debug(
f"插件: {plugin.name}:{plugin.module} "
"为HIDDEN,已跳过权限检查..."
)
return
try:
cost_gold = await self.auth_cost(user, plugin, session)
+1 -1
View File
@@ -32,7 +32,7 @@ async def _(
if plugin := matcher.plugin:
if metadata := plugin.metadata:
extra = metadata.extra
if extra.get("plugin_type") in [PluginType.HIDDEN, PluginType.DEPENDANT]:
if extra.get("plugin_type") in [PluginType.HIDDEN]:
return
user_id = session.id1
group_id = session.id3 or session.id2
@@ -0,0 +1,23 @@
from typing import Any
from nonebot.adapters import Bot
from zhenxun.services.log import logger
from zhenxun.utils.manager.message_manager import MessageManager
@Bot.on_called_api
async def handle_api_result(
bot: Bot, exception: Exception | None, api: str, data: dict[str, Any], result: Any
):
if not exception and api == "send_msg":
try:
if (uid := data.get("user_id")) and (msg_id := result.get("message_id")):
MessageManager.add(str(uid), str(msg_id))
logger.debug(
f"收集消息id,user_id: {uid}, msg_id: {msg_id}", "msg_hook"
)
except Exception as e:
logger.warning(
f"收集消息id发生错误...data: {data}, result: {result}", "msg_hook", e=e
)
+1 -1
View File
@@ -46,7 +46,7 @@ async def _(
nickname = user_id
try:
result = await get_user_info(
session, bot, user_id, session.group.id if session.group else None, nickname
session, user_id, session.group.id if session.group else None, nickname
)
await MessageUtils.build_message(result).send(at_sender=True)
logger.info("获取用户信息", arparma.header_result, session=session)
+3 -4
View File
@@ -1,7 +1,6 @@
import random
from datetime import datetime, timedelta
from nonebot.adapters import Bot
from tortoise.functions import Count
from tortoise.expressions import RawSQL
from nonebot_plugin_uninfo import Uninfo
@@ -131,7 +130,7 @@ async def get_chat_history(
async def get_user_info(
session: Uninfo, bot: Bot, user_id: str, group_id: str | None, nickname: str
session: Uninfo, user_id: str, group_id: str | None, nickname: str
) -> bytes:
"""获取用户个人信息
@@ -145,7 +144,7 @@ async def get_user_info(
返回:
bytes: 图片数据
"""
platform = PlatformUtils.get_platform(bot) or ""
platform = PlatformUtils.get_platform(session) or "qq"
ava_url = PlatformUtils.get_user_avatar_url(user_id, platform)
user = await UserConsole.get_user(user_id, platform)
level = await LevelUser.get_user_level(user_id, group_id)
@@ -164,7 +163,7 @@ async def get_user_info(
data = {
"date": now.date(),
"weather": weather,
"ava_url": session.user.avatar,
"ava_url": ava_url,
"nickname": nickname,
"title": "勇 者",
"race": random.choice(RACE),
+22 -24
View File
@@ -1,30 +1,31 @@
import random
from typing import Any, List
from typing import Any
from nonebot import on_regex
from nonebot.adapters import Bot
from nonebot.params import Depends, RegexGroup
from nonebot.plugin import PluginMetadata
from nonebot.rule import to_me
from nonebot_plugin_alconna import Alconna, Option, on_alconna, store_true
from nonebot.adapters import Bot
from nonebot.plugin import PluginMetadata
from nonebot.params import Depends, RegexGroup
from nonebot_plugin_session import EventSession
from nonebot_plugin_userinfo import EventUserInfo, UserInfo
from nonebot_plugin_userinfo import UserInfo, EventUserInfo
from nonebot_plugin_alconna import Option, Alconna, on_alconna, store_true
from zhenxun.configs.config import BotConfig, Config
from zhenxun.configs.utils import PluginExtraData, RegisterConfig
from zhenxun.services.log import logger
from zhenxun.utils.enum import PluginType
from zhenxun.utils.depends import UserName
from zhenxun.utils.message import MessageUtils
from zhenxun.models.ban_console import BanConsole
from zhenxun.models.friend_user import FriendUser
from zhenxun.configs.config import Config, BotConfig
from zhenxun.models.group_member_info import GroupInfoUser
from zhenxun.services.log import logger
from zhenxun.utils.depends import UserName
from zhenxun.utils.enum import PluginType
from zhenxun.utils.message import MessageUtils
from zhenxun.configs.utils import RegisterConfig, PluginExtraData
__plugin_meta__ = PluginMetadata(
name="昵称系统",
description="区区昵称,才不想叫呢!",
usage=f"""
个人昵称,将替换{BotConfig.self_nickname}称呼你的名称,群聊 与 私聊 昵称相互独立,全局昵称设置将更改您目前所有群聊中及私聊的昵称
个人昵称,将替换{BotConfig.self_nickname}称呼你的名称,群聊 与 私聊 昵称相互独立,
全局昵称设置将更改您目前所有群聊中及私聊的昵称
指令:
以后叫我 [昵称]: 设置当前群聊/私聊的昵称
全局昵称设置 [昵称]: 设置当前所有群聊和私聊的昵称
@@ -39,9 +40,10 @@ __plugin_meta__ = PluginMetadata(
RegisterConfig(
key="BLACK_WORD",
value=["爸", "爹", "爷", "父"],
help="昵称所屏蔽的关键词,已设置的昵称会被替换为 *,未设置的昵称会在设置时提示",
help="昵称所屏蔽的关键词,已设置的昵称会被替换为 *,"
"未设置的昵称会在设置时提示",
default_value=None,
type=List[str],
type=list[str],
)
],
).dict(),
@@ -167,9 +169,8 @@ async def _(
):
if session.id1:
(name,) = reg_group
if len(name) < 5:
if random.random() < 0.3:
name = "~".join(name)
if len(name) < 5 and random.random() < 0.3:
name = "~".join(name)
if gid := session.id3 or session.id2:
await GroupInfoUser.set_user_nickname(
session.id1,
@@ -181,9 +182,6 @@ async def _(
session.platform,
)
logger.info(f"设置群昵称成功: {name}", "昵称设置", session=session)
await MessageUtils.build_message(
random.choice(CALL_NAME).format(name)
).finish(reply_to=True)
else:
await FriendUser.set_user_nickname(
session.id1,
@@ -194,9 +192,9 @@ async def _(
session.platform,
)
logger.info(f"设置私聊昵称成功: {name}", "昵称设置", session=session)
await MessageUtils.build_message(
random.choice(CALL_NAME).format(name)
).finish(reply_to=True)
await MessageUtils.build_message(random.choice(CALL_NAME).format(name)).finish(
reply_to=True
)
await MessageUtils.build_message("用户id为空...").send()
@@ -49,9 +49,8 @@ class GroupManager:
group: GroupConsole
"""
if group:
await GroupConsole.filter(
group_id=group_id, channel_id__isnull=True
).update(group_flag=1)
group.group_flag = 1
await group.save(update_fields=["group_flag"])
else:
block_plugin = ""
if plugin_list := await PluginInfo.filter(default_status=False).all():
@@ -113,7 +112,7 @@ class GroupManager:
@classmethod
async def add_bot(
cls, bot: Bot, operator_id: str, group_id: str, group: GroupConsole | None
cls, bot: Bot, operator_id: str, group_id: str, group: GroupConsole
):
"""拉入bot
@@ -123,7 +122,11 @@ class GroupManager:
group_id: 群组id
group: GroupConsole
"""
if base_config.get("flag") and operator_id not in bot.config.superusers:
if (
base_config.get("flag")
and operator_id not in bot.config.superusers
and group.group_flag != 1
):
"""退出群组"""
try:
if result_msg := base_config.get("message"):
+1 -1
View File
@@ -184,7 +184,7 @@ async def _(
elif isinstance(result, UniMessage):
await result.finish(reply_to=True)
except GoodsNotFound:
await MessageUtils.build_message(f"没有找到道具 {name} 或道具数量不足...").send(
await MessageUtils.build_message(f"没有找到道具 {name.result} 或道具数量不足...").send(
reply_to=True
)
+61
View File
@@ -0,0 +1,61 @@
from nonebot.rule import Rule
from nonebot.adapters import Bot, Event
from nonebot_plugin_uninfo import Uninfo
from nonebot.plugin import PluginMetadata
from nonebot_plugin_alconna.uniseg.tools import reply_fetch
from nonebot_plugin_alconna import Alconna, Arparma, on_alconna
from zhenxun.services.log import logger
from zhenxun.utils.message import MessageUtils
from zhenxun.utils.platform import PlatformUtils
from zhenxun.configs.utils import PluginExtraData
from zhenxun.utils.manager.message_manager import MessageManager
__plugin_meta__ = PluginMetadata(
name="消息撤回",
description="撤回自己触发的消息撤回,不允许撤回其他人触发消息的撤回哦",
usage="""
引用消息 撤回
""".strip(),
extra=PluginExtraData(author="HibiKier", version="0.1", menu_type="其他").dict(),
)
def reply_check() -> Rule:
"""
检查是否存在回复消息
返回:
Rule: Rule
"""
async def _rule(bot: Bot, event: Event, session: Uninfo):
if event.get_type() == "message":
return (
bool(await reply_fetch(event, bot))
and PlatformUtils.get_platform(session) == "qq"
)
return False
return Rule(_rule)
_matcher = on_alconna(Alconna("撤回"), priority=5, block=True, rule=reply_check())
@_matcher.handle()
async def _(bot: Bot, event: Event, session: Uninfo, arparma: Arparma):
if reply := await reply_fetch(event, bot):
if (
MessageManager.check(session.user.id, reply.id)
or session.user.id in bot.config.superusers
):
try:
await bot.delete_msg(message_id=reply.id)
logger.info("撤回消息", arparma.header_result, session=session)
except Exception:
await MessageUtils.build_message("撤回失败,可能消息已过期...").send()
else:
await MessageUtils.build_message(
"权限不足,不是你触发的消息不要胡乱撤回哦..."
).send()
+6 -13
View File
@@ -288,13 +288,6 @@ class ConfigsManager:
config.value = value
config.default_value = default_value
else:
_module = None
if ":" in module:
module_split = module.split(":")
if len(module_split) < 2:
raise ValueError(f"module: {module} 填写错误")
_module = module_split[-1]
module = module_split[0]
key = key.upper()
if not self._data.get(module):
self._data[module] = ConfigGroup(module=module)
@@ -311,7 +304,6 @@ class ConfigsManager:
key: str,
value: Any,
auto_save: bool = False,
save_simple_data: bool = True,
):
"""设置配置值
@@ -320,15 +312,16 @@ class ConfigsManager:
key: 配置名称
value: 值
auto_save: 自动保存.
save_simple_data: 保存至config.yaml.
"""
key = key.upper()
if module in self._data:
data = self._data[module].configs.get(key)
if data and data != value:
if self._data[module].configs.get(key):
self._data[module].configs[key].value = value
self._simple_data[module][key] = value
else:
self.add_plugin_config(module, key, value)
self._simple_data[module][key] = value
if auto_save:
self.save(save_simple_data=save_simple_data)
self.save(save_simple_data=True)
def get_config(self, module: str, key: str, default: Any = None) -> Any:
"""获取指定配置值
+5 -7
View File
@@ -1,5 +1,5 @@
from datetime import datetime, timedelta
from typing import Literal, Tuple
from typing import Literal
from tortoise import fields
from tortoise.functions import Count
@@ -27,7 +27,7 @@ class ChatHistory(Model):
platform = fields.CharField(255, null=True)
"""平台"""
class Meta:
class Meta: # type: ignore
table = "chat_history"
table_description = "聊天记录数据表"
@@ -53,7 +53,7 @@ class ChatHistory(Model):
query = query.filter(create_time__range=date_scope)
return list(
await query.annotate(count=Count("user_id"))
.order_by(o + "count")
.order_by(f"{o}count")
.group_by("user_id")
.limit(limit)
.values_list("user_id", "count")
@@ -74,9 +74,7 @@ class ChatHistory(Model):
)
else:
message = await cls.all().order_by("create_time").first()
if message:
return message.create_time
return None
return message.create_time if message else None
@classmethod
async def get_message(
@@ -85,7 +83,7 @@ class ChatHistory(Model):
gid: str,
type_: Literal["user", "group"],
msg_type: Literal["private", "group"] | None = None,
days: int | Tuple[datetime, datetime] | None = None,
days: int | tuple[datetime, datetime] | None = None,
) -> list[Self]:
"""获取消息查询query
+9 -11
View File
@@ -10,7 +10,6 @@ from ._build_image import BuildImage
class RowStyle(BaseModel):
font: FreeTypeFont | str | Path | None = "HYWenHei-85W.ttf"
"""字体"""
font_size: int = 20
@@ -23,7 +22,6 @@ class RowStyle(BaseModel):
class ImageTemplate:
color_list = ["#C2CEFE", "#FFA94C", "#3FE6A0", "#D1D4F5"] # noqa: RUF012
@classmethod
@@ -88,7 +86,7 @@ class ImageTemplate:
head_text: str,
tip_text: str | None,
column_name: list[str],
data_list: list[list[str | tuple[Path | BuildImage, int, int]]],
data_list: list[list[str | int | tuple[Path | BuildImage, int, int]]],
row_space: int = 35,
column_space: int = 30,
padding: int = 5,
@@ -137,7 +135,7 @@ class ImageTemplate:
async def table(
cls,
column_name: list[str],
data_list: list[list[str | tuple[Path | BuildImage, int, int]]],
data_list: list[list[str | int | tuple[Path | BuildImage, int, int]]],
row_space: int = 25,
column_space: int = 10,
padding: int = 5,
@@ -161,9 +159,11 @@ class ImageTemplate:
column_data = []
for i in range(len(column_name)):
c = []
for lst in data_list:
if len(lst) > i:
c.append(lst[i])
for item in data_list:
if len(item) > i:
c.append(
item[i] if isinstance(item[i], tuple | list) else str(item[i])
)
else:
c.append("")
column_data.append(c)
@@ -176,7 +176,7 @@ class ImageTemplate:
if isinstance(s, tuple):
w = s[1]
else:
w, _ = BuildImage.get_text_size(s, font)
w, _ = BuildImage.get_text_size(str(s), font)
if w > _temp["width"]:
_temp["width"] = w
build_data_list.append(_temp)
@@ -199,7 +199,7 @@ class ImageTemplate:
style = RowStyle(font=font)
if text_style:
style = text_style(column_name[i], item)
if isinstance(item, tuple):
if isinstance(item, tuple | list):
"""图片"""
data, width, height = item
image_ = None
@@ -221,8 +221,6 @@ class ImageTemplate:
)
cur_h += base_h + row_space
column_image_list.append(background)
# height = max([bk.height for bk in column_image_list])
# width = sum([bk.width for bk in column_image_list])
return await BuildImage.auto_paste(
column_image_list, len(column_image_list), column_space
)
+12 -2
View File
@@ -431,14 +431,20 @@ class AsyncHttpx:
class AsyncPlaywright:
@classmethod
@asynccontextmanager
async def new_page(cls, **kwargs) -> AsyncGenerator[Page, None]:
async def new_page(
cls, cookies: list[dict[str, Any]] | dict[str, Any] | None = None, **kwargs
) -> AsyncGenerator[Page, None]:
"""获取一个新页面
参数:
user_agent: 请求头
cookies: cookies
"""
browser = await get_browser()
ctx = await browser.new_context(**kwargs)
if cookies:
if isinstance(cookies, dict):
cookies = [cookies]
await ctx.add_cookies(cookies) # type: ignore
page = await ctx.new_page()
try:
yield page
@@ -461,6 +467,7 @@ class AsyncPlaywright:
timeout: float | None = None,
type_: Literal["jpeg", "png"] | None = None,
user_agent: str | None = None,
cookies: list[dict[str, Any]] | dict[str, Any] | None = None,
**kwargs,
) -> UniMessage | None:
"""截图,该方法仅用于简单快捷截图,复杂截图请操作 page
@@ -474,6 +481,8 @@ class AsyncPlaywright:
wait_until: 等待类型
timeout: 超时限制
type_: 保存类型
user_agent: user_agent
cookies: cookies
"""
if viewport_size is None:
viewport_size = {"width": 2560, "height": 1080}
@@ -482,6 +491,7 @@ class AsyncPlaywright:
wait_time = wait_time * 1000 if wait_time else None
element_list = [element] if isinstance(element, str) else element
async with cls.new_page(
cookies,
viewport=viewport_size,
user_agent=user_agent,
**kwargs,
+27
View File
@@ -0,0 +1,27 @@
from typing import ClassVar
class MessageManager:
data: ClassVar[dict[str, list[str]]] = {}
@classmethod
def add(cls, uid: str, msg_id: str):
if uid not in cls.data:
cls.data[uid] = []
cls.data[uid].append(msg_id)
cls.remove_check(uid)
@classmethod
def check(cls, uid: str, msg_id: str) -> bool:
return msg_id in cls.data.get(uid, [])
@classmethod
def remove_check(cls, uid: str):
if len(cls.data[uid]) > 200:
cls.data[uid] = cls.data[uid][100:]
@classmethod
def get(cls, uid: str) -> list[str]:
if uid in cls.data:
return cls.data[uid]
return []
+42 -2
View File
@@ -4,7 +4,17 @@ from pathlib import Path
import nonebot
from pydantic import BaseModel
from nonebot.adapters.onebot.v11 import Message, MessageSegment
from nonebot_plugin_alconna import At, Text, AtAll, Image, Video, Voice, UniMessage
from nonebot_plugin_alconna import (
At,
Text,
AtAll,
Image,
Video,
Voice,
Reference,
CustomNode,
UniMessage,
)
from zhenxun.services.log import logger
from zhenxun.configs.config import BotConfig
@@ -89,6 +99,36 @@ class MessageUtils:
message_list += cls.__build_message(_data) # type: ignore
return UniMessage(message_list)
@classmethod
def alc_forward_msg(
cls,
msg_list: list,
uin: str,
name: str,
) -> UniMessage:
"""生成自定义合并消息
参数:
msg_list: 消息列表
uin: 发送者 QQ
name: 自定义名称
返回:
list[dict]: 转发消息
"""
node_list = []
for _message in msg_list:
if isinstance(_message, list):
for i in range(len(_message.copy())):
if isinstance(_message[i], Path):
_message[i] = Image(
raw=BuildImage.open(_message[i]).pic2bytes()
)
node_list.append(
CustomNode(uid=uin, name=name, content=UniMessage(_message))
)
return UniMessage(Reference(nodes=node_list))
@classmethod
def custom_forward_msg(
cls,
@@ -138,7 +178,7 @@ class MessageUtils:
if isinstance(r, Text):
s += str(r)
elif isinstance(r, Image):
if v := r.url or r.path:
if v := r.url or r.path or r.raw:
s += MessageSegment.image(v)
elif isinstance(r_list, Image):
if v := r_list.url or r_list.path:
+1
View File
@@ -189,6 +189,7 @@ def change_pixiv_image_links(
url = (
url.replace("i.pximg.net", nginx_url)
.replace("i.pixiv.cat", nginx_url)
.replace("i.pixiv.re", nginx_url)
.replace("_webp", "")
)
return url