Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae5df38c21 | ||
|
|
545f6fd7f9 | ||
|
|
4c7c223b2c | ||
|
|
14b983cfa0 | ||
|
|
229908207b | ||
|
|
cfe7dfd6b5 | ||
|
|
b2da0a902d | ||
|
|
3f06131c34 | ||
|
|
24f1a1ca9a | ||
|
|
54a74cdd91 | ||
|
|
7ca4c18e1c | ||
|
|
a2b7980ae2 | ||
|
|
e75a56fe08 | ||
|
|
abd8b9b705 | ||
|
|
54d2ba1df4 | ||
|
|
dbfeeac313 | ||
|
|
93316be5fe | ||
|
|
60b78a9f1c | ||
|
|
6359ba63f9 | ||
|
|
2853a2feaa | ||
|
|
c9b864ca54 | ||
|
|
6519b1cad4 | ||
|
|
ebf3df046a | ||
|
|
b6611d6d0e | ||
|
|
23ea21380a | ||
|
|
54a93a2f54 | ||
|
|
05f954eb8b | ||
|
|
27d4630874 | ||
|
|
7ac2ff92c4 | ||
|
|
92b0c6b4bf | ||
|
|
75e10fe38a | ||
|
|
6dfebaae96 | ||
|
|
3ffe213652 | ||
|
|
c9aa568767 | ||
|
|
3d3a2a5f7f | ||
|
|
7567bfb732 | ||
|
|
f0f0e94a9c | ||
|
|
41b0dac223 | ||
|
|
792bcaa711 | ||
|
|
fe1634eb2d | ||
|
|
4a52c4825b | ||
|
|
6358ce5266 | ||
|
|
e98af0ac21 | ||
|
|
48a48204f3 | ||
|
|
6f313986df | ||
|
|
3856ba09bb | ||
|
|
f982d862ee | ||
|
|
c76566c2df | ||
|
|
e7fffa3ef4 | ||
|
|
f7b28127e9 | ||
|
|
7ea11a884b | ||
|
|
faa0785fa1 | ||
|
|
9e5266a491 | ||
|
|
2f459719e8 | ||
|
|
5f92efa658 | ||
|
|
856976526f | ||
|
|
6852363a03 | ||
|
|
862427a872 | ||
|
|
fd90e1ab82 | ||
|
|
3117dc264f | ||
|
|
a28a60d9c8 | ||
|
|
f0063283e7 | ||
|
|
84680aa88d | ||
|
|
bd50e17c58 | ||
|
|
f08114f6c5 | ||
|
|
42b6e94564 | ||
|
|
d3a4a5bbf7 | ||
|
|
482eb1a214 | ||
|
|
94e05944fd | ||
|
|
2c8c46d6b1 | ||
|
|
717a973807 | ||
|
|
d68a4099ba | ||
|
|
e8425f371c | ||
|
|
a3311adebb | ||
|
|
28b61e57cd | ||
|
|
7890cc577f | ||
|
|
b14220e6e3 | ||
|
|
7ec1bc9fac | ||
|
|
e89d1d4688 | ||
|
|
6be9e477b1 | ||
|
|
207f947a1c | ||
|
|
32c11b9919 | ||
|
|
3fc4eaa39a | ||
|
|
a04475abc1 | ||
|
|
38976589ec | ||
|
|
f2c20b84bf | ||
|
|
983248374d | ||
|
|
6f635ed978 | ||
|
|
fcfaf56021 | ||
|
|
60f4406ec1 | ||
|
|
51c010daa8 | ||
|
|
cd88d805ce | ||
|
|
e41e16370e | ||
|
|
f2e354edeb | ||
|
|
f1354c6264 | ||
|
|
029a731fb9 | ||
|
|
d97e437e80 | ||
|
|
8a688eb4f0 | ||
|
|
94ef33264b | ||
|
|
a8355fbab9 | ||
|
|
95762bdddd | ||
|
|
4e42d1dda1 | ||
|
|
e4a92ea34b | ||
|
|
f11e9c58e4 | ||
|
|
342e70cc38 | ||
|
|
440e7b54a5 | ||
|
|
fe11ff0772 | ||
|
|
2b006b8f5e | ||
|
|
1790a0b09e | ||
|
|
057001f0bd | ||
|
|
e618b19283 | ||
|
|
62fd93c1ff | ||
|
|
807b2f6504 | ||
|
|
0a5ab83ffe | ||
|
|
3f4787d4c6 | ||
|
|
db9153f42c | ||
|
|
3b4c206a24 | ||
|
|
51371ba954 | ||
|
|
c36bb9771c | ||
|
|
ce97dedc5f | ||
|
|
682d19aa2b | ||
|
|
c3927c7f2e | ||
|
|
8911bbfa21 | ||
|
|
7288d5bdba | ||
|
|
8615eb20d4 | ||
|
|
a61934650e | ||
|
|
a2549a0ae9 | ||
|
|
405e2d3a4c | ||
|
|
02aba68269 | ||
|
|
8d071f853b | ||
|
|
44e0f2d410 | ||
|
|
9eca6a97ca | ||
|
|
a56d1f2bd8 | ||
|
|
133d4e193a | ||
|
|
db75c4a433 | ||
|
|
15ad90da88 | ||
|
|
29c48765ae | ||
|
|
8fe061738a | ||
|
|
7e7436f433 | ||
|
|
a3681216bd |
@@ -8,12 +8,19 @@ NICKNAME=["真寻", "小真寻", "绪山真寻", "小寻子"]
|
||||
|
||||
SESSION_EXPIRE_TIMEOUT=30
|
||||
|
||||
ALCONNA_USE_COMMAND_START=True
|
||||
|
||||
# 全局图片统一使用bytes发送,当真寻与协议端不在同一服务器上时为True
|
||||
IMAGE_TO_BYTES = False
|
||||
IMAGE_TO_BYTES = True
|
||||
|
||||
# 回复消息时自称
|
||||
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"
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
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__
|
||||
@@ -13,11 +13,13 @@
|
||||
"getbbox",
|
||||
"hibiapi",
|
||||
"httpx",
|
||||
"jsdelivr",
|
||||
"kaiheila",
|
||||
"lolicon",
|
||||
"nonebot",
|
||||
"onebot",
|
||||
"pixiv",
|
||||
"qbot",
|
||||
"Setu",
|
||||
"tobytes",
|
||||
"ujson",
|
||||
|
||||
@@ -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>
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
</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 @@
|
||||
__version__: v0.2.4
|
||||
__version__: v0.2.4-fix2
|
||||
|
||||
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 315 KiB |
|
After Width: | Height: | Size: 352 KiB |
|
After Width: | Height: | Size: 279 KiB |
|
After Width: | Height: | Size: 182 KiB |
|
After Width: | Height: | Size: 228 KiB |
|
After Width: | Height: | Size: 200 KiB |
|
After Width: | Height: | Size: 201 KiB |
|
After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 60 KiB |
@@ -19,6 +19,8 @@ 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
|
||||
@@ -33,6 +35,10 @@ 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
|
||||
|
||||
@@ -11,6 +11,7 @@ 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
|
||||
@@ -234,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)
|
||||
@@ -244,6 +248,7 @@ 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)
|
||||
@@ -278,6 +283,16 @@ 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):
|
||||
"""插件限制
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
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,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"):
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
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(),
|
||||
)
|
||||
@@ -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()
|
||||
@@ -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:
|
||||
"""获取指定配置值
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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="所属平台")
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
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 源码格式"""
|
||||
@@ -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,
|
||||
|
||||
@@ -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) -> str:
|
||||
async def get_download_image_hash(url: str, mark: str, use_proxy: bool = False) -> str:
|
||||
"""下载图片获取哈希值
|
||||
|
||||
参数:
|
||||
@@ -402,7 +402,7 @@ async def get_download_image_hash(url: str, mark: str) -> str:
|
||||
"""
|
||||
try:
|
||||
if await AsyncHttpx.download_file(
|
||||
url, TEMP_PATH / f"compare_download_{mark}_img.jpg"
|
||||
url, TEMP_PATH / f"compare_download_{mark}_img.jpg", use_proxy=use_proxy
|
||||
):
|
||||
img_hash = get_img_hash(TEMP_PATH / f"compare_download_{mark}_img.jpg")
|
||||
return str(img_hash)
|
||||
|
||||
@@ -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 []
|
||||
@@ -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:
|
||||
|
||||
@@ -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.id and session.group:
|
||||
if 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.id, session.group.id, int(level)
|
||||
session.user.id, session.group.id, int(level)
|
||||
)
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -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
|
||||
|
||||