Compare commits

..
15 Commits
Author SHA1 Message Date
HibiKier d594d17bf6 版本更新 2024-10-20 21:11:16 +08:00
4e33bf3a50 版本更新 (#1666)
* ✨ 父级插件加载

* ✅ 添加测试:更新与添加插件 (#1594)

* ✅ 测试更新与添加插件

* ✅ Sourcery建议

* 👷 添加pytest

* 🎨 优化代码

* 🐛 bug修复

* 🐛修复添加插件返回403的问题 (#1595)

* 完善测试方法
* vscode测试配置
* 重构插件安装过程

* 🎨 修改readme

* Update README.md

* 🐛 修改bug与版本锁定

* 🐛 修复超级用户对群组功能开关

* 🐛 修复插件商店检查插件更新问题 (#1597)

* 🐛 修复插件商店检查插件更新问题

* 🐛 恶意命令检测问题

* 🐛 增加插件状态检查 (#1598)

* ✅ 优化测试用例

* 🐛 更改插件更新与安装逻辑

* 🐛 修复更新群组成员信息

* 🎨 代码优化

* 🚀 更新Dockerfile (#1599)

* 🎨 更新requirements

* ➕ 添加依赖aiocache

* ⚡ 添加github镜像

* ✨ 添加仓库目录多获取渠道

* 🐛 修复测试用例

* ✨ 添加API缓存

* 🎨 采取Sourcery建议

* 🐛 文件下载逻辑修改

* 🎨 优化代码

* 🐛 修复插件开关有时出现错误

* ✨ 重构自检ui

* 🐛 自检html修正

* 修复签到逻辑bug,并使代码更灵活以适应签到好感度等级配置 (#1606)

* 修复签到功能已知问题

* 修复签到功能已知问题

* 修改参数名称

* 修改uid判断

---------

Co-authored-by: HibiKier <45528451+HibiKier@users.noreply.github.com>

* 🎨 代码结构优化

* 🐛 私聊时修改插件时删除私聊帮助

* 🐛 过滤父插件

* 🐛 修复自检在ARM上的问题 (#1607)

* 🐛 修复自检在ARM上的问题

* ✅ 优化测试

* ✨ 支持mysql,psql,sqlite随机函数

* 🔧 VSCode配置修改

* 🔧 VSCode配置修改

* ✨ 添加金币排行

Co-Authored-By: HibiKier <45528451+HibiKier@users.noreply.github.com>

* 📝 修改README

Co-Authored-By: HibiKier <45528451+HibiKier@users.noreply.github.com>

* 🔨 提取GitHub相关操作 (#1609)

* 🔨 提取GitHub相关操作

* 🔨 重构API策略

* ✨ 签到/金币排行限制最大数量 (#1616)

* ✨ 签到/金币排行限制最大数量

* 🐛 修复超级用户id获取问题

* 🐛 修复路径解压与挂载 (#1619)

* 🐛 修复功能少时zhenxun帮助图片排序问题 (#1620)

* 🐛 签到文本适应 (#1622)

* 🐛 好感度排行提供默认值 (#1624)

* 🎈 优先使用github api (#1625)

* ✨ 重构帮助,限制普通用户查询管理插件 (#1626)

* 🐛 修复群权限与插件等级匹配 (#1627)

* ✨ 当管理员尝试ban真寻时将被反杀 (#1628)

* ✨ 群组发言时间检测提供开关配置 (#1630)

* 🐳 chore: 支持自动修改版本号 (#1629)

* 🎈 perf(github_utils): 支持github url下载遍历 (#1632)

* 🎈 perf(github_utils): 支持github url下载遍历

* 🐞 fix(http_utils): 修复一些下载问题

* 🦄 refactor(http_utils): 部分重构

* chore(version): Update version to v0.2.2-e6f17c4

---------

Co-authored-by: AkashiCoin <AkashiCoin@users.noreply.github.com>

* 🧪 test(auto_update): 修复测试用例 (#1633)

* 🐛 修复商店商品为空时报错 (#1634)

* 🐛 修复群权限与插件等级匹配 (#1635)

* ✨ message_build支持AtAll (#1639)

* 🎈 perf: 使用commit号下载插件 (#1641)

* 🎈 perf: 使用commit号下载插件

* chore(version): Update version to v0.2.2-f9c7360

---------

Co-authored-by: AkashiCoin <AkashiCoin@users.noreply.github.com>

* 🐳 chore: 修改运行检查触发路径 (#1642)

* 🐳 chore: 修改运行检查触发路径

* 🐳 chore: 添加tests目录

* ✨ 重构qq群事件处理 (#1643)

* 🐛 签到名称自适应 (#1644)

* 🎨  更新README (#1645)

* 🐛 fix(http_utils): 流式下载Content-Length错误 (#1647)

* 🐛 修复群组中帮助功能状态显示问题 (#1650)

* 🐛 修复群欢迎消息设置 (#1651)

* 🐛 修复webui下载后首次启动错误 (#1652)

* 🐛 修复webui下载后首次启动错误

* chore(version): Update version to v0.2.2-4a8ef85

---------

Co-authored-by: HibiKier <HibiKier@users.noreply.github.com>

* ✨ 移除默认图片文件夹:爬 (#1653)

* ✨ 安装/移除插件提供插件安装/卸载方法用于插件初始化 (#1654)

* ✨ 新增超级用户与管理员帮助模板 (#1655)

* ✨ 新增个人信息命令 (#1657)

* ✨ 修改个人信息菜单名称 (#1658)

* ✨ 新增插件商店api (#1659)

* ✨ 新增插件商店api

* chore(version): Update version to v0.2.2-7e15f20

---------

Co-authored-by: HibiKier <HibiKier@users.noreply.github.com>

* ✨ 将cd,block,count限制复原配置文件 (#1662)

* 🎨 修改README (#1663)

* 🎨 修改版本号 (#1664)

* 🎨 修改requirements (#1665)

---------

Co-authored-by: AkashiCoin <l1040186796@gmail.com>
Co-authored-by: fanyinrumeng <42991257+fanyinrumeng@users.noreply.github.com>
Co-authored-by: AkashiCoin <i@loli.vet>
Co-authored-by: Elaga <1728903318@qq.com>
Co-authored-by: AkashiCoin <AkashiCoin@users.noreply.github.com>
Co-authored-by: HibiKier <HibiKier@users.noreply.github.com>
2024-10-01 00:42:23 +08:00
HibiKier daa40ae8b8 Merge pull request #1592 from HibiKier/dev
🐛 版本锁定
2024-08-30 23:15:09 +08:00
HibiKier 21bdb011e0 Merge pull request #1591 from HibiKier/dev
🎨 修改方法名称
2024-08-30 02:48:53 +08:00
HibiKier 47f3518b04 Merge pull request #1590 from HibiKier/dev
🎨 更新版本号
2024-08-29 23:22:50 +08:00
HibiKier 997ce52d69 Merge pull request #1589 from HibiKier/dev
🎨 添加__init__.py
2024-08-29 22:50:01 +08:00
HibiKier 4bc433f049 Merge pull request #1588 from HibiKier/dev
Dev
2024-08-29 22:41:58 +08:00
HibiKier 4d6013ca02 Merge pull request #1561 from HibiKier/dev
🐛 修复使用道具后未减去道具数量
2024-08-19 18:57:31 +08:00
HibiKier f09f2c3162 Merge pull request #1559 from HibiKier/dev
⚡️ 优化权限判断
2024-08-18 22:38:53 +08:00
HibiKier 67fdbb824b Merge pull request #1557 from HibiKier/dev
🎨 代码优化
2024-08-16 20:16:30 +08:00
HibiKier b4ccbb0f80 Merge pull request #1556 from HibiKier/dev
Dev
2024-08-15 23:54:50 +08:00
HibiKier 6326d888c8 Merge pull request #1555 from HibiKier/dev
Dev
2024-08-15 00:18:09 +08:00
HibiKier e32f3dd22a Merge pull request #1551 from HibiKier/dev
🐛 修改b站解析
2024-08-14 01:05:42 +08:00
HibiKier c7e073baea Merge pull request #1550 from HibiKier/dev
Dev
2024-08-13 22:40:03 +08:00
HibiKier 1be99ac64d Merge pull request #1549 from HibiKier/dev
Dev
2024-08-12 22:36:01 +08:00
46 changed files with 614 additions and 403 deletions
+1 -8
View File
@@ -8,19 +8,12 @@ NICKNAME=["真寻", "小真寻", "绪山真寻", "小寻子"]
SESSION_EXPIRE_TIMEOUT=30
ALCONNA_USE_COMMAND_START=True
# 全局图片统一使用bytes发送,当真寻与协议端不在同一服务器上时为True
IMAGE_TO_BYTES = True
IMAGE_TO_BYTES = False
# 回复消息时自称
SELF_NICKNAME="小真寻"
# 官bot appid:bot账号
QBOT_ID_DATA = '{
}'
# 数据库配置
# 示例: "postgres://user:password@127.0.0.1:5432/database"
# 示例: "mysql://user:password@127.0.0.1:3306/database"
+65
View File
@@ -0,0 +1,65 @@
name: Update Version
on:
pull_request_target:
paths:
- zhenxun/**
- resources/**
- bot.py
types:
- opened
- synchronize
branches:
- main
- dev
jobs:
update-version:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Read current version
id: read_version
run: |
version_line=$(grep '__version__' __version__)
version=$(echo $version_line | sed -E 's/__version__:\s*v([0-9]+\.[0-9]+\.[0-9]+)(-.+)?/\1/')
echo "Current version: $version"
echo "current_version=$version" >> $GITHUB_OUTPUT
- name: Check for version file changes
id: check_diff
run: |
if git diff --name-only HEAD~1 HEAD | grep -q '__version__'; then
echo "Version file has changes"
echo "version_changed=true" >> $GITHUB_OUTPUT
else
echo "Version file has no changes"
echo "version_changed=false" >> $GITHUB_OUTPUT
fi
- name: Get commit hash
id: get_commit_hash
run: echo "commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Update version file
if: steps.check_diff.outputs.version_changed == 'false'
run: |
current_version="${{ steps.read_version.outputs.current_version }}"
commit_hash="${{ steps.get_commit_hash.outputs.commit_hash }}"
new_version="v${current_version}-${commit_hash}"
echo "Updating version to: $new_version"
echo "__version__: $new_version" > __version__
git config --global user.name "${{ github.event.pull_request.user.login }}"
git config --global user.email "${{ github.event.pull_request.user.login }}@users.noreply.github.com"
git add __version__
git remote set-url origin https://github.com/${{ github.event.pull_request.head.repo.full_name }}.git
git commit -m "chore(version): Update version to $new_version"
git push origin HEAD:${{ github.event.pull_request.head.ref }}
- name: Check updated version
if: steps.check_diff.outputs.version_changed == 'false'
run: cat __version__
-2
View File
@@ -13,13 +13,11 @@
"getbbox",
"hibiapi",
"httpx",
"jsdelivr",
"kaiheila",
"lolicon",
"nonebot",
"onebot",
"pixiv",
"qbot",
"Setu",
"tobytes",
"ujson",
+114 -53
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://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/zhenxun_help.png"/>
<img width="180" height="450" src="https://github.com/HibiKier/zhenxun_bot/blob/dev/docs_image/zhenxun_help.png"/>
</div>
@@ -68,11 +68,11 @@
### 1. 体验一下?
这是一个免费的,版本为 dev 的 zhenxun,你可以通过 [napcat](https://github.com/NapNeko/NapCatQQ) 或 [拉格朗日](https://github.com/LagrangeDev/Lagrange.Core) 以及 [matcha](https://github.com/A-kirami/matcha) 等直接连接用于体验与测试
这是一个免费的,版本为 dev 的 zhenxun,你可以通过 napcat 或拉格朗日等直接连接用于体验与测试
(球球了测试君!)
```
Url: ws://test.zhenxun.org:8080/onebot/v11/ws
Url: 43.143.112.57:11451/onebot/v11/ws
AccessToken: PUBLIC_ZHENXUN_TEST
注:你无法获得超级用户权限
@@ -95,14 +95,13 @@ AccessToken: PUBLIC_ZHENXUN_TEST
<details>
<summary> <strong> WebUI </strong>后台示例图 </summary>
![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)
![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)
</details>
@@ -112,8 +111,7 @@ AccessToken: PUBLIC_ZHENXUN_TEST
## ~~来点优点?~~ 可爱难道还不够吗
- 实现了许多功能,且提供了大量功能管理命令,进行了多平台适配,兼容 nb2 商店插件
- 拥有完善可用的 webui
- 实现了许多功能,且提供了大量功能管理命令
- 通过 Config 配置项将所有插件配置统计保存至 config.yaml,利于统一用户修改
- 方便增删插件,原生 nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
- 提供了 cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`PluginCdBlock` 等
@@ -167,97 +165,161 @@ python bot.py
```
## 功能列表
<!-- ## 功能列表 (旧版列表)
<details>
<summary>内置功能</summary>
<summary>已实现的功能</summary>
**真寻原 `plugins` 插件文件夹已迁移至其他仓库,当前内置仅保留必要的功能**
### 已实现的常用功能
### 基础功能
- [x] 昵称系统(群与群与私聊分开.)
- [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] 更新信息(如果继续更新的话)
- [x] go-cqhttp 最新版下载和上传(不需要请删除)
- [x] 撤回
- [x] 滴滴滴-(用户对超级用户发送消息)
- [x] 金币红包/金币排行
- [x] 俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
- [x] 网易云热评
- [x] 念首古诗
- [x] 获取 b 站视频封面
- [x] 通过 PID 获取图片
- [x] 功能统计可视化
- [x] 词云
- [x] 关于
- [x] 三种样式的帮助菜单
### 管理员功能
### 已实现的管理员功能
- [x] 管理员帮助
- [x] 更新群组成员信息
- [x] 95%的群功能开关
- [x] 查看群内被动技能状态
- [x] 自定义群欢迎消息(是真寻的不是管家的!)
- [x] ban/unban(支持设置 ban 时长)= 群组及用户的黑名单
- [x] 休息吧/醒来(群组内真寻状态)
- [x] .ban/.unban(支持设置 ban 时长)= 黑白名单
- [x] 刷屏禁言相关:刷屏检测设置/设置禁言时长/设置检测次数
- [x] 上传图片/连续上传图片 (上传图片至指定图库)
- [x] 移动图片 (同上)
- [x] 删除图片 (同上)
- [x] 群内 B 站订阅
- [x] 词条设置
- [x] 休息吧/醒来
### 超级用户功能
### 已实现的超级用户功能
- [x] 超级用户帮助
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
- [x] 群组管理,退群指令等
- [x] 开启/关闭指定群的广播通知
- [x] 广播
- [x] 自检(检查系统状态)
- [x] 所有群组/所有好友
- [x] 退出指定群
- [x] 更新好友信息/更新群信息
- [x] /t(对用户进行回复或发送消息)
- [x] 上传/删除/修改商品(需要编写对应的商品功能)
- [x] 节日红包发送
- [x] 修改群权限
- [x] 检查更新
- [x] ban
- [x] 更新色图
- [x] 更新价格/更加图片(csgo 开箱)
- [x] 重载原神/方舟/赛马娘/坎公骑冠剑卡池
- [x] 更新原神今日素材/更新原神资源信息
- [x] PIX 相关操作
- [x] 检查更新真寻
- [x] 重启
- [x] 添加/删除/查看群白名单
- [x] 功能开关(更多设置)
- [x] 功能状态
- [x] 执行 SQL
- [x] b 了
- [x] 执行 sql
- [x] 重载配置
- [x] 清理临时数据
- [x] 增删群认证
- [x] 同意/拒绝好友/群聊请求
- [x] 添加/移除/更新插件/插件商店(plugins 库以及扩展库)
- [x] WebUI API(对真寻前端的支持)
- [x] 配置重载
#### 超级用户的被动技能
- [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] 群聊时间检测(当群聊最后一人发言时间大于当前 48 小时后将关闭该群所有通知(即被动技能))
- [x] 自动同意好友请求,加群请求将会提醒管理员,退群提示,加群欢迎等等
- [x] 群聊时间检测(当群聊最后一人发言时间大于当前 36 小时后将关闭该群所有通知(即被动技能))
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
- [x] 群权限系统
- [x] 定时更新权限
- [x] 自动配置重载
- [x] 强制入群保护
- [x] 自定备份(可配置)
- [x] 笨蛋检测(当使用功能名称当指令时真寻会跳出来狠狠嘲笑并帮助)
### 更多插件...
</details> -->
- [更多插件](https://github.com/zhenxun-org/zhenxun_bot_plugins)
- [第三方插件索引库](https://github.com/zhenxun-org/zhenxun_bot_plugins_index)
</details>
## [爱发电](https://afdian.com/a/HibiKier)
## [爱发电](https://afdian.net/@HibiKier)
<details>
<summary>爱发电 以及 感谢投喂 </summary>
<img width="365px" height="450px" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/afd.jpg">
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
### 感谢名单
@@ -307,7 +369,6 @@ 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-fix2
__version__: v0.2.4
Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
View File
Binary file not shown.
-6
View File
@@ -19,8 +19,6 @@ require("nonebot_plugin_htmlrender")
from zhenxun.services.log import logger
from zhenxun.models.sign_user import SignUser
from zhenxun.models.goods_info import GoodsInfo
from zhenxun.utils.platform import PlatformUtils
from zhenxun.models.bot_console import BotConsole
from zhenxun.models.user_console import UserConsole
from zhenxun.utils.decorator.shop import shop_register
from zhenxun.models.bot_connect_log import BotConnectLog
@@ -35,10 +33,6 @@ async def _(bot: Bot):
await BotConnectLog.create(
bot_id=bot.self_id, platform=bot.adapter, connect_time=datetime.now(), type=1
)
if not await BotConsole.exists(bot_id=bot.self_id):
await BotConsole.create(
bot_id=bot.self_id, platform=PlatformUtils.get_platform(bot)
)
@driver.on_bot_disconnect
+1 -16
View File
@@ -11,7 +11,6 @@ from zhenxun.services.log import logger
from zhenxun.configs.config import Config
from zhenxun.utils.message import MessageUtils
from zhenxun.models.level_user import LevelUser
from zhenxun.models.bot_console import BotConsole
from zhenxun.models.plugin_info import PluginInfo
from zhenxun.models.plugin_limit import PluginLimit
from zhenxun.models.user_console import UserConsole
@@ -235,10 +234,7 @@ class AuthChecker:
return
if plugin := await PluginInfo.get_or_none(module_path=module_path):
if plugin.plugin_type == PluginType.HIDDEN:
logger.debug(
f"插件: {plugin.name}:{plugin.module} "
"为HIDDEN,已跳过权限检查..."
)
logger.debug("插件为HIDDEN,已跳过...")
return
try:
cost_gold = await self.auth_cost(user, plugin, session)
@@ -248,7 +244,6 @@ class AuthChecker:
if not plugin.limit_superuser:
cost_gold = 0
raise IsSuperuserException()
await self.auth_bot(plugin, bot.self_id)
await self.auth_group(plugin, session, message)
await self.auth_admin(plugin, session)
await self.auth_plugin(plugin, session, event)
@@ -283,16 +278,6 @@ class AuthChecker:
if is_ignore:
raise IgnoredException("权限检测 ignore")
async def auth_bot(self, plugin: PluginInfo, bot_id: str):
"""机器人权限
参数:
plugin: PluginInfo
bot_id: bot_id
"""
if await BotConsole.is_block_plugin(plugin.module, bot_id):
raise IgnoredException("机器人权限检测 ignore")
async def auth_limit(self, plugin: PluginInfo, session: EventSession):
"""插件限制
+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]:
if extra.get("plugin_type") in [PluginType.HIDDEN, PluginType.DEPENDANT]:
return
user_id = session.id1
group_id = session.id3 or session.id2
@@ -1,23 +0,0 @@
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, user_id, session.group.id if session.group else None, nickname
session, bot, 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)
+4 -3
View File
@@ -1,6 +1,7 @@
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
@@ -130,7 +131,7 @@ async def get_chat_history(
async def get_user_info(
session: Uninfo, user_id: str, group_id: str | None, nickname: str
session: Uninfo, bot: Bot, user_id: str, group_id: str | None, nickname: str
) -> bytes:
"""获取用户个人信息
@@ -144,7 +145,7 @@ async def get_user_info(
返回:
bytes: 图片数据
"""
platform = PlatformUtils.get_platform(session) or "qq"
platform = PlatformUtils.get_platform(bot) or ""
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)
@@ -163,7 +164,7 @@ async def get_user_info(
data = {
"date": now.date(),
"weather": weather,
"ava_url": ava_url,
"ava_url": session.user.avatar,
"nickname": nickname,
"title": "勇 者",
"race": random.choice(RACE),
+23 -21
View File
@@ -1,31 +1,30 @@
import random
from typing import Any
from typing import Any, List
from nonebot import on_regex
from nonebot.rule import to_me
from nonebot.adapters import Bot
from nonebot.plugin import PluginMetadata
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_plugin_session import EventSession
from nonebot_plugin_userinfo import UserInfo, EventUserInfo
from nonebot_plugin_alconna import Option, Alconna, on_alconna, store_true
from nonebot_plugin_userinfo import EventUserInfo, UserInfo
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.configs.config import BotConfig, Config
from zhenxun.configs.utils import PluginExtraData, RegisterConfig
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.configs.utils import RegisterConfig, PluginExtraData
from zhenxun.services.log import logger
from zhenxun.utils.depends import UserName
from zhenxun.utils.enum import PluginType
from zhenxun.utils.message import MessageUtils
__plugin_meta__ = PluginMetadata(
name="昵称系统",
description="区区昵称,才不想叫呢!",
usage=f"""
个人昵称,将替换{BotConfig.self_nickname}称呼你的名称,群聊 与 私聊 昵称相互独立,
全局昵称设置将更改您目前所有群聊中及私聊的昵称
个人昵称,将替换{BotConfig.self_nickname}称呼你的名称,群聊 与 私聊 昵称相互独立,全局昵称设置将更改您目前所有群聊中及私聊的昵称
指令:
以后叫我 [昵称]: 设置当前群聊/私聊的昵称
全局昵称设置 [昵称]: 设置当前所有群聊和私聊的昵称
@@ -40,10 +39,9 @@ __plugin_meta__ = PluginMetadata(
RegisterConfig(
key="BLACK_WORD",
value=["爸", "爹", "爷", "父"],
help="昵称所屏蔽的关键词,已设置的昵称会被替换为 *,"
"未设置的昵称会在设置时提示",
help="昵称所屏蔽的关键词,已设置的昵称会被替换为 *,未设置的昵称会在设置时提示",
default_value=None,
type=list[str],
type=List[str],
)
],
).dict(),
@@ -169,8 +167,9 @@ async def _(
):
if session.id1:
(name,) = reg_group
if len(name) < 5 and random.random() < 0.3:
name = "~".join(name)
if len(name) < 5:
if random.random() < 0.3:
name = "~".join(name)
if gid := session.id3 or session.id2:
await GroupInfoUser.set_user_nickname(
session.id1,
@@ -182,6 +181,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)
else:
await FriendUser.set_user_nickname(
session.id1,
@@ -192,9 +194,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()
@@ -0,0 +1,321 @@
import os
import re
import random
from datetime import datetime
import ujson as json
from nonebot.adapters import Bot
from nonebot_plugin_alconna import At
from nonebot import on_notice, on_request
from nonebot.plugin import PluginMetadata
from nonebot.adapters.onebot.v11 import (
GroupDecreaseNoticeEvent,
GroupIncreaseNoticeEvent,
)
from nonebot.adapters.onebot.v12 import (
GroupMemberDecreaseEvent,
GroupMemberIncreaseEvent,
)
from zhenxun.services.log import logger
from zhenxun.utils.utils import FreqLimiter
from zhenxun.utils.message import MessageUtils
from zhenxun.models.fg_request import FgRequest
from zhenxun.models.level_user import LevelUser
from zhenxun.models.plugin_info import PluginInfo
from zhenxun.utils.common_utils import CommonUtils
from zhenxun.configs.config import Config, BotConfig
from zhenxun.models.group_console import GroupConsole
from zhenxun.models.group_member_info import GroupInfoUser
from zhenxun.utils.enum import PluginType, RequestHandleType
from zhenxun.configs.path_config import DATA_PATH, IMAGE_PATH
from zhenxun.configs.utils import Task, RegisterConfig, PluginExtraData
__plugin_meta__ = PluginMetadata(
name="QQ群事件处理",
description="群事件处理",
usage="",
extra=PluginExtraData(
author="HibiKier",
version="0.1",
plugin_type=PluginType.HIDDEN,
configs=[
RegisterConfig(
module="invite_manager",
key="message",
value=f"请不要未经同意就拉{BotConfig.self_nickname}入群!告辞!",
help="强制拉群后进群回复的内容",
),
RegisterConfig(
module="invite_manager",
key="flag",
value=True,
help="强制拉群后进群退出并回复内容",
default_value=True,
type=bool,
),
RegisterConfig(
module="invite_manager",
key="welcome_msg_cd",
value=5,
help="群欢迎消息cd",
default_value=5,
type=int,
),
RegisterConfig(
module="_task",
key="DEFAULT_GROUP_WELCOME",
value=True,
help="被动 进群欢迎 进群默认开关状态",
default_value=True,
type=bool,
),
RegisterConfig(
module="_task",
key="DEFAULT_REFUND_GROUP_REMIND",
value=True,
help="被动 退群提醒 进群默认开关状态",
default_value=True,
type=bool,
),
],
tasks=[
Task(module="group_welcome", name="进群欢迎"),
Task(module="refund_group_remind", name="退群提醒"),
],
).dict(),
)
base_config = Config.get("invite_manager")
limit_cd = base_config.get("welcome_msg_cd")
_flmt = FreqLimiter(limit_cd)
group_increase_handle = on_notice(priority=1, block=False)
"""群员增加处理"""
group_decrease_handle = on_notice(priority=1, block=False)
"""群员减少处理"""
add_group = on_request(priority=1, block=False)
"""加群同意请求"""
@group_increase_handle.handle()
async def _(bot: Bot, event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent):
superusers = BotConfig.get_superuser("qq")
user_id = str(event.user_id)
group_id = str(event.group_id)
if user_id == bot.self_id:
"""新成员为bot本身"""
group = await GroupConsole.get_or_none(
group_id=group_id, channel_id__isnull=True
)
if not group or group.group_flag == 0:
"""群聊不存在或被强制拉群"""
if base_config.get("flag"):
"""退出群组"""
try:
if result_msg := base_config.get("message"):
await bot.send_group_msg(
group_id=event.group_id, message=result_msg
)
await bot.set_group_leave(group_id=event.group_id)
if superusers:
await bot.send_private_msg(
user_id=int(superusers[0]),
message=f"触发强制入群保护,已成功退出群聊 {group_id}...",
)
logger.info(
"强制拉群或未有群信息,退出群聊成功",
"入群检测",
group_id=event.group_id,
)
if req := await FgRequest.get_or_none(
group_id=group_id, handle_type__isnull=True
):
req.handle_type = RequestHandleType.IGNORE
await req.save(update_fields=["handle_type"])
except Exception as e:
logger.error(
"强制拉群或未有群信息,退出群聊失败",
"入群检测",
group_id=event.group_id,
e=e,
)
if superusers:
await bot.send_private_msg(
user_id=int(superusers[0]),
message="触发强制入群保护,"
f"退出群聊 {event.group_id} 失败...",
)
await GroupConsole.filter(group_id=group_id).delete()
else:
"""允许群组并设置群认证,默认群功能开关"""
if group:
await GroupConsole.filter(
group_id=group_id, channel_id__isnull=True
).update(group_flag=1)
else:
block_plugin = ""
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=event.group_id)
await GroupConsole.create(
group_id=group_info["group_id"],
group_name=group_info["group_name"],
max_member_count=group_info["max_member_count"],
member_count=group_info["member_count"],
group_flag=1,
block_plugin=block_plugin,
platform="qq",
)
"""刷新群管理员权限"""
admin_default_auth = Config.get_config(
"admin_bot_manage", "ADMIN_DEFAULT_AUTH"
)
# 即刻刷新权限
for user_info in await bot.get_group_member_list(
group_id=event.group_id
):
"""即刻刷新权限"""
if (
user_info["role"]
in [
"owner",
"admin",
]
and not await LevelUser.is_group_flag(
user_info["user_id"], group_id
)
and admin_default_auth is not None
):
await LevelUser.set_level(
user_info["user_id"],
user_info["group_id"],
admin_default_auth,
)
logger.debug(
f"添加默认群管理员权限: {admin_default_auth}",
"入群检测",
session=user_info["user_id"],
group_id=user_info["group_id"],
)
if str(user_info["user_id"]) in bot.config.superusers:
await LevelUser.set_level(
user_info["user_id"], user_info["group_id"], 9
)
logger.debug(
"添加超级用户权限: 9",
"入群检测",
session=user_info["user_id"],
group_id=user_info["group_id"],
)
else:
join_time = datetime.now()
user_info = await bot.get_group_member_info(
group_id=event.group_id, user_id=event.user_id
)
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},
)
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
if _flmt.check(group_id):
"""群欢迎消息"""
_flmt.start_cd(group_id)
path = DATA_PATH / "welcome_message" / "qq" / f"{group_id}"
file = path / "text.json"
msg_list = []
if file.exists():
data = json.load((path / "text.json").open(encoding="utf-8"))
message = data["message"]
msg_split = re.split(r"\[image:\d+\]", message)
if data["at"]:
msg_list.append(At(flag="user", target=user_id))
for i, text in enumerate(msg_split):
msg_list.append(text)
img_file = path / f"{i}.png"
if img_file.exists():
msg_list.append(img_file)
if not await CommonUtils.task_is_block("group_welcome", group_id):
logger.info("发送群欢迎消息...", "入群检测", group_id=group_id)
if msg_list:
await MessageUtils.build_message(msg_list).send()
else:
image = (
IMAGE_PATH
/ "qxz"
/ random.choice(os.listdir(IMAGE_PATH / "qxz"))
)
await MessageUtils.build_message(
[
"新人快跑啊!!本群现状↓(快使用自定义!)",
image,
]
).send()
@group_decrease_handle.handle()
async def _(bot: Bot, event: GroupDecreaseNoticeEvent | GroupMemberDecreaseEvent):
if event.sub_type == "kick_me":
"""踢出Bot"""
group_id = event.group_id
operator_id = event.operator_id
if user := await GroupInfoUser.get_or_none(
user_id=str(event.operator_id), group_id=str(event.group_id)
):
operator_name = user.user_name
else:
operator_name = "None"
group = await GroupConsole.filter(group_id=str(group_id)).first()
group_name = group.group_name if group else ""
if superusers := BotConfig.get_superuser("qq"):
coffee = int(superusers[0])
await bot.send_private_msg(
user_id=coffee,
message=f"****呜..一份踢出报告****\n"
f"我被 {operator_name}({operator_id})\n"
f"踢出了 {group_name}({group_id})\n"
f"日期:{str(datetime.now()).split('.')[0]}",
)
if group:
await group.delete()
return
if str(event.user_id) == bot.self_id:
"""踢出Bot"""
await GroupConsole.filter(group_id=str(event.group_id)).delete()
return
if user := await GroupInfoUser.get_or_none(
user_id=str(event.user_id), group_id=str(event.group_id)
):
user_name = user.user_name
else:
user_name = f"{event.user_id}"
await GroupInfoUser.filter(
user_id=str(event.user_id), group_id=str(event.group_id)
).delete()
logger.info(
f"名称: {user_name} 退出群聊",
"group_decrease_handle",
session=event.user_id,
group_id=event.group_id,
)
result = ""
if event.sub_type == "leave":
result = f"{user_name}离开了我们..."
if event.sub_type == "kick":
operator = await bot.get_group_member_info(
user_id=event.operator_id, group_id=event.group_id
)
operator_name = operator["card"] or operator["nickname"]
result = f"{user_name} 被 {operator_name} 送走了."
if not await CommonUtils.task_is_block("refund_group_remind", str(event.group_id)):
await group_decrease_handle.send(f"{result}")
@@ -49,8 +49,9 @@ class GroupManager:
group: GroupConsole
"""
if group:
group.group_flag = 1
await group.save(update_fields=["group_flag"])
await GroupConsole.filter(
group_id=group_id, channel_id__isnull=True
).update(group_flag=1)
else:
block_plugin = ""
if plugin_list := await PluginInfo.filter(default_status=False).all():
@@ -112,7 +113,7 @@ class GroupManager:
@classmethod
async def add_bot(
cls, bot: Bot, operator_id: str, group_id: str, group: GroupConsole
cls, bot: Bot, operator_id: str, group_id: str, group: GroupConsole | None
):
"""拉入bot
@@ -122,11 +123,7 @@ class GroupManager:
group_id: 群组id
group: GroupConsole
"""
if (
base_config.get("flag")
and operator_id not in bot.config.superusers
and group.group_flag != 1
):
if base_config.get("flag") and operator_id not in bot.config.superusers:
"""退出群组"""
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.result} 或道具数量不足...").send(
await MessageUtils.build_message(f"没有找到道具 {name} 或道具数量不足...").send(
reply_to=True
)
@@ -1,30 +0,0 @@
import os
import time
from nonebot.rule import to_me
from nonebot.utils import run_sync
from nonebot.permission import SUPERUSER
from nonebot.plugin import PluginMetadata
from nonebot_plugin_session import EventSession
from nonebot_plugin_apscheduler import scheduler
from nonebot_plugin_alconna import Alconna, on_alconna
from zhenxun.services.log import logger
from zhenxun.utils.enum import PluginType
from zhenxun.utils.message import MessageUtils
from zhenxun.configs.path_config import TEMP_PATH
from zhenxun.configs.utils import PluginExtraData
from zhenxun.utils.utils import ResourceDirManager
__plugin_meta__ = PluginMetadata(
name="Bot管理",
description="指定bot对象的功能/被动开关和状态",
usage="""
清理临时数据
""".strip(),
extra=PluginExtraData(
author="",
version="0.1",
plugin_type=PluginType.SUPERUSER,
).dict(),
)
-61
View File
@@ -1,61 +0,0 @@
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()
+13 -6
View File
@@ -288,6 +288,13 @@ 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)
@@ -304,6 +311,7 @@ class ConfigsManager:
key: str,
value: Any,
auto_save: bool = False,
save_simple_data: bool = True,
):
"""设置配置值
@@ -312,16 +320,15 @@ class ConfigsManager:
key: 配置名称
value: 值
auto_save: 自动保存.
save_simple_data: 保存至config.yaml.
"""
key = key.upper()
if module in self._data:
if self._data[module].configs.get(key):
data = self._data[module].configs.get(key)
if data and data != value:
self._data[module].configs[key].value = value
else:
self.add_plugin_config(module, key, value)
self._simple_data[module][key] = value
self._simple_data[module][key] = value
if auto_save:
self.save(save_simple_data=True)
self.save(save_simple_data=save_simple_data)
def get_config(self, module: str, key: str, default: Any = None) -> Any:
"""获取指定配置值
-60
View File
@@ -1,60 +0,0 @@
from tortoise import fields
from zhenxun.services.db_context import Model
class BotConsole(Model):
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
bot_id = fields.CharField(255, unique=True, description="bot_id")
"""bot_id"""
status = fields.BooleanField(default=True, description="Bot状态")
"""Bot状态"""
block_plugin = fields.TextField(default="", description="禁用插件")
"""禁用插件"""
block_task = fields.TextField(default="", description="禁用被动技能")
"""禁用被动技能"""
create_time = fields.DatetimeField(auto_now_add=True, description="创建时间")
"""创建时间"""
platform = fields.CharField(255, null=True, description="平台")
"""平台"""
class Meta: # type: ignore
table = "bot_console"
table_description = "Bot数据表"
@classmethod
async def get_bot_status(cls, bot_id: str) -> bool:
result = await cls.get_or_none(bot_id=bot_id)
return result.status if result else False
@classmethod
async def set_block_plugin(cls, bot_id: str, module: str):
bot_data, _ = await cls.get_or_create(bot_id=bot_id)
if f"<{module}," not in bot_data.block_plugin:
bot_data.block_plugin += f"<{module},"
await bot_data.save(update_fields=["block_plugin"])
@classmethod
async def set_unblock_plugin(cls, bot_id: str, module: str):
bot_data, _ = await cls.get_or_create(bot_id=bot_id)
if f"<{module}," in bot_data.block_plugin:
bot_data.block_plugin = bot_data.block_plugin.replace(f"<{module},", "")
await bot_data.save(update_fields=["block_plugin"])
@classmethod
async def set_block_task(cls, bot_id: str, task: str):
bot_data, _ = await cls.get_or_create(bot_id=bot_id)
if f"<{task}," not in bot_data.block_task:
bot_data.block_plugin += f"<{task},"
await bot_data.save(update_fields=["block_task"])
@classmethod
async def is_block_plugin(cls, bot_id: str, task: str) -> bool:
bot_data, _ = await cls.get_or_create(bot_id=bot_id)
return f"<{task}," in bot_data.block_plugin
@classmethod
async def is_block_task(cls, bot_id: str, task: str) -> bool:
bot_data, _ = await cls.get_or_create(bot_id=bot_id)
return f"<{task}," in bot_data.block_task
+7 -5
View File
@@ -1,5 +1,5 @@
from datetime import datetime, timedelta
from typing import Literal
from typing import Literal, Tuple
from tortoise import fields
from tortoise.functions import Count
@@ -27,7 +27,7 @@ class ChatHistory(Model):
platform = fields.CharField(255, null=True)
"""平台"""
class Meta: # type: ignore
class Meta:
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(f"{o}count")
.order_by(o + "count")
.group_by("user_id")
.limit(limit)
.values_list("user_id", "count")
@@ -74,7 +74,9 @@ class ChatHistory(Model):
)
else:
message = await cls.all().order_by("create_time").first()
return message.create_time if message else None
if message:
return message.create_time
return None
@classmethod
async def get_message(
@@ -83,7 +85,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
+2 -2
View File
@@ -37,8 +37,8 @@ class GroupConsole(Model):
default="", description="超级用户禁用插件"
)
"""超级用户禁用插件"""
block_task = fields.TextField(default="", description="禁用被动技能")
"""禁用被动技能"""
block_task = fields.TextField(default="", description="禁用插件")
"""禁用插件"""
superuser_block_task = fields.TextField(default="", description="超级用户禁用被动")
"""超级用户禁用被动"""
platform = fields.CharField(255, default="qq", description="所属平台")
+11 -9
View File
@@ -10,6 +10,7 @@ from ._build_image import BuildImage
class RowStyle(BaseModel):
font: FreeTypeFont | str | Path | None = "HYWenHei-85W.ttf"
"""字体"""
font_size: int = 20
@@ -22,6 +23,7 @@ class RowStyle(BaseModel):
class ImageTemplate:
color_list = ["#C2CEFE", "#FFA94C", "#3FE6A0", "#D1D4F5"] # noqa: RUF012
@classmethod
@@ -86,7 +88,7 @@ class ImageTemplate:
head_text: str,
tip_text: str | None,
column_name: list[str],
data_list: list[list[str | int | tuple[Path | BuildImage, int, int]]],
data_list: list[list[str | tuple[Path | BuildImage, int, int]]],
row_space: int = 35,
column_space: int = 30,
padding: int = 5,
@@ -135,7 +137,7 @@ class ImageTemplate:
async def table(
cls,
column_name: list[str],
data_list: list[list[str | int | tuple[Path | BuildImage, int, int]]],
data_list: list[list[str | tuple[Path | BuildImage, int, int]]],
row_space: int = 25,
column_space: int = 10,
padding: int = 5,
@@ -159,11 +161,9 @@ class ImageTemplate:
column_data = []
for i in range(len(column_name)):
c = []
for item in data_list:
if len(item) > i:
c.append(
item[i] if isinstance(item[i], tuple | list) else str(item[i])
)
for lst in data_list:
if len(lst) > i:
c.append(lst[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(str(s), font)
w, _ = BuildImage.get_text_size(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 | list):
if isinstance(item, tuple):
"""图片"""
data, width, height = item
image_ = None
@@ -221,6 +221,8 @@ 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
)
+35
View File
@@ -0,0 +1,35 @@
import re
GITHUB_REPO_URL_PATTERN = re.compile(
r"^https://github.com/(?P<owner>[^/]+)/(?P<repo>[^/]+)(/tree/(?P<branch>[^/]+))?$"
)
"""github仓库地址正则"""
JSD_PACKAGE_API_FORMAT = (
"https://data.jsdelivr.com/v1/packages/gh/{owner}/{repo}@{branch}"
)
"""jsdelivr包地址格式"""
GIT_API_TREES_FORMAT = (
"https://api.github.com/repos/{owner}/{repo}/git/trees/{branch}?recursive=1"
)
"""git api trees地址格式"""
CACHED_API_TTL = 300
"""缓存api ttl"""
RAW_CONTENT_FORMAT = "https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{path}"
"""raw content格式"""
ARCHIVE_URL_FORMAT = "https://github.com/{owner}/{repo}/archive/refs/heads/{branch}.zip"
"""archive url格式"""
RELEASE_ASSETS_FORMAT = (
"https://github.com/{owner}/{repo}/releases/download/{version}/{filename}"
)
"""release assets格式"""
RELEASE_SOURCE_FORMAT = (
"https://codeload.github.com/{owner}/{repo}/legacy.{compress}/refs/tags/{version}"
)
"""release 源码格式"""
+2 -12
View File
@@ -431,20 +431,14 @@ class AsyncHttpx:
class AsyncPlaywright:
@classmethod
@asynccontextmanager
async def new_page(
cls, cookies: list[dict[str, Any]] | dict[str, Any] | None = None, **kwargs
) -> AsyncGenerator[Page, None]:
async def new_page(cls, **kwargs) -> AsyncGenerator[Page, None]:
"""获取一个新页面
参数:
cookies: cookies
user_agent: 请求头
"""
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
@@ -467,7 +461,6 @@ 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
@@ -481,8 +474,6 @@ class AsyncPlaywright:
wait_until: 等待类型
timeout: 超时限制
type_: 保存类型
user_agent: user_agent
cookies: cookies
"""
if viewport_size is None:
viewport_size = {"width": 2560, "height": 1080}
@@ -491,7 +482,6 @@ 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,
+2 -2
View File
@@ -390,7 +390,7 @@ def get_img_hash(image_file: str | Path) -> str:
return str(hash_value)
async def get_download_image_hash(url: str, mark: str, use_proxy: bool = False) -> str:
async def get_download_image_hash(url: str, mark: str) -> str:
"""下载图片获取哈希值
参数:
@@ -402,7 +402,7 @@ async def get_download_image_hash(url: str, mark: str, use_proxy: bool = False)
"""
try:
if await AsyncHttpx.download_file(
url, TEMP_PATH / f"compare_download_{mark}_img.jpg", use_proxy=use_proxy
url, TEMP_PATH / f"compare_download_{mark}_img.jpg"
):
img_hash = get_img_hash(TEMP_PATH / f"compare_download_{mark}_img.jpg")
return str(img_hash)
-27
View File
@@ -1,27 +0,0 @@
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 []
+2 -42
View File
@@ -4,17 +4,7 @@ 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,
Reference,
CustomNode,
UniMessage,
)
from nonebot_plugin_alconna import At, Text, AtAll, Image, Video, Voice, UniMessage
from zhenxun.services.log import logger
from zhenxun.configs.config import BotConfig
@@ -99,36 +89,6 @@ 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,
@@ -178,7 +138,7 @@ class MessageUtils:
if isinstance(r, Text):
s += str(r)
elif isinstance(r, Image):
if v := r.url or r.path or r.raw:
if v := r.url or r.path:
s += MessageSegment.image(v)
elif isinstance(r_list, Image):
if v := r_list.url or r_list.path:
+2 -2
View File
@@ -27,14 +27,14 @@ def admin_check(a: int | str, key: str | None = None) -> Rule:
if PlatformUtils.is_qbot(session):
"""官bot接口,放弃所有权限检查"""
return False
if session.group:
if session.id and session.group:
level = a
if isinstance(a, str) and key:
level = Config.get_config(a, key)
if level is not None:
return bool(
await LevelUser.check_level(
session.user.id, session.group.id, int(level)
session.id, session.group.id, int(level)
)
)
return False
-1
View File
@@ -189,7 +189,6 @@ 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