Compare commits

...
90 Commits
Author SHA1 Message Date
HibiKier 71026542df Update image_utils.py 2021-10-05 15:53:58 +08:00
HibiKier e756a50d97 Update README.md 2021-10-04 22:59:00 +08:00
HibiKier 49c47c01a3 Update data_source.py 2021-10-04 22:58:11 +08:00
HibiKier e7eea2a7d9 Update __init__.py 2021-10-04 22:57:59 +08:00
HibiKier 311ae7d4e8 Update README.md 2021-10-04 20:23:31 +08:00
HibiKier 058f0885f7 fix 0.0.5.1 2021-10-04 20:22:09 +08:00
HibiKier c6eaf435f2 Update update_info.json 2021-10-04 14:31:31 +08:00
HibiKier 22676f3bfa Merge pull request #59 from AkashiCoin/main
epic
2021-10-03 21:40:12 +08:00
HibiKier fedcb37b1a Update data_source.py 2021-10-03 21:40:05 +08:00
HibiKier 54025c9cfc Update __init__.py 2021-10-03 21:39:03 +08:00
AkashiCoin 2cdf3c28b6 Update __init__.py 2021-10-03 20:35:55 +08:00
AkashiCoin ba29232c9f Update __init__.py 2021-10-03 20:17:08 +08:00
HibiKier 5fd0667061 Update README.md 2021-10-03 18:46:06 +08:00
HibiKier 2c9f99ac3c Update README.md 2021-10-03 18:45:39 +08:00
HibiKier 775b1b937b Merge pull request #58 from AkashiCoin/main
epic
2021-10-03 18:44:42 +08:00
AkashiCoin 65723aee15 Update __init__.py 2021-10-03 18:34:56 +08:00
AkashiCoin 46b55e4224 Update data_source.py 2021-10-03 18:34:31 +08:00
HibiKier 918adc4b1c Add files via upload 2021-10-03 16:07:57 +08:00
HibiKier e99341c6aa Add files via upload 2021-10-03 15:35:30 +08:00
HibiKier 4b0d2a104b Add files via upload 2021-10-03 15:34:53 +08:00
HibiKier eb9bb1b173 Update __init__.py 2021-10-03 15:26:19 +08:00
HibiKier f2b4204a23 Update README.md 2021-10-03 15:21:09 +08:00
HibiKier b63aa952c4 Update requirements.txt 2021-10-03 15:18:20 +08:00
HibiKier 7a5767717f Update README.md 2021-10-03 14:46:16 +08:00
HibiKier 22af4f2b27 Update config.py 2021-10-03 14:39:12 +08:00
HibiKier 00658cf165 update v0.0.5.0 2021-10-03 14:24:07 +08:00
HibiKier 87ed445a58 Update group_user_checkin.py 2021-09-23 11:10:15 +08:00
HibiKier 36ea174804 Merge pull request #53 from Adsicmes/main
修改最低好感度 避免0好感度问题
2021-09-21 13:46:11 +08:00
FrZ 6ba2fedba2 最低好感改0.01 2021-09-21 13:45:33 +08:00
FrZ ca89ff7761 使用OS提供的最高质量源生成随机数计算好感度 2021-09-21 13:31:29 +08:00
FrZ f39d53a865 修改最低好感度 避免0好感度问题 2021-09-21 13:18:48 +08:00
HibiKier 6864d54e27 Update config.py 2021-09-10 20:10:31 +08:00
HibiKier bdc084212f Update README.md 2021-09-10 20:09:47 +08:00
HibiKier fc2487df0e fix withdraw 2021-09-10 20:08:01 +08:00
HibiKier 264a827a2c Update README.md 2021-09-10 11:23:31 +08:00
HibiKier 401886805b Update __version__ 2021-09-09 22:51:50 +08:00
HibiKier efcdf79f57 Update setu.py 2021-09-09 22:50:14 +08:00
HibiKier 616f215075 Update data_source.py 2021-09-09 22:49:45 +08:00
HibiKier 00b674cebb Update setu.py 2021-09-09 18:16:15 +08:00
HibiKier 8ac440335e Update README.md 2021-09-09 17:17:13 +08:00
HibiKier 4b1821ce42 Update query_resource.py 2021-09-09 17:15:26 +08:00
HibiKier 3ad955abf9 Update image_utils.py 2021-09-09 17:14:33 +08:00
HibiKier 5fabb974ce Update config.py 2021-09-09 16:39:37 +08:00
HibiKier 5325bc3e32 Update init_config.py 2021-09-09 16:39:03 +08:00
HibiKier 6688c4626b Update update_info.json 2021-09-09 16:26:29 +08:00
HibiKier 2b95ab3d7e Update init_config.py 2021-09-09 16:25:42 +08:00
HibiKier 23e6d7e27e Update config.py 2021-09-09 16:25:09 +08:00
HibiKier 2760e22336 Update update_info.json 2021-09-09 16:05:48 +08:00
HibiKier d026d09f98 Update __version__ 2021-09-09 16:04:34 +08:00
HibiKier e6fd1ce791 Update README.md 2021-09-09 16:02:58 +08:00
HibiKier 342eaa9a97 Update pixiv.py 2021-09-09 16:02:12 +08:00
HibiKier dc7681357e Update omega_pixiv_illusts.py 2021-09-09 16:01:50 +08:00
HibiKier b61cb49c1a Update setu.py 2021-09-09 16:01:35 +08:00
HibiKier c7b341393d Update setu.py 2021-09-09 14:30:42 +08:00
HibiKier 1f9fa2adb9 Update README.md 2021-09-09 12:59:23 +08:00
HibiKier 133b927d9d Update __version__ 2021-09-09 10:53:37 +08:00
HibiKier 46e6b26d75 Update README.md 2021-09-09 10:51:50 +08:00
hibiki 8d0b0e5505 update code 2021-09-09 10:47:26 +08:00
HibiKier 754a0c111c Update README.md 2021-09-08 15:16:58 +08:00
HibiKier 81ef3f04e4 Update group_user_checkin.py 2021-09-08 11:05:23 +08:00
HibiKier e7c00484b3 Update README.md 2021-09-07 11:17:19 +08:00
HibiKier 065432448f Merge pull request #40 from Ailitonia/patch-1
Fix: Check info_list to avoid TypeError
2021-09-07 11:11:38 +08:00
HibiKier 5d45a9c28a Update README.md 2021-09-07 11:08:43 +08:00
Ailitonia 7db5b3b5c0 Fix: Check info_list to avoid TypeError 2021-09-07 02:08:56 +08:00
HibiKier 5eb64060dc Update data_source.py 2021-09-06 21:14:26 +08:00
HibiKier 2c4877b9f8 Update update_info.json 2021-09-06 21:10:44 +08:00
HibiKier 218dad3b86 fix bilibili_sub 2021-09-06 21:03:50 +08:00
HibiKier 974c6b106a Update update_info.json 2021-09-06 20:42:06 +08:00
HibiKier 954b281b69 Update data_source.py 2021-09-06 18:09:16 +08:00
HibiKier b1b15b63a1 Update data_source.py 2021-09-06 18:03:21 +08:00
HibiKier 49567aa958 Update __version__ 2021-09-05 13:57:27 +08:00
HibiKier a7a470066b Update update_info.json 2021-09-05 13:57:06 +08:00
HibiKier 4e3010d75e Update data_source.py 2021-09-05 13:56:29 +08:00
HibiKier cbacd726ef Update __init__.py 2021-09-05 13:54:55 +08:00
HibiKier 58a1fc1ca0 Update __version__ 2021-09-05 13:06:41 +08:00
HibiKier a704f88d75 Update update_info.json 2021-09-05 13:05:06 +08:00
HibiKier 10d0ad7d47 Update update_info.json 2021-09-05 12:15:47 +08:00
HibiKier b47a29eb67 Update __init__.py 2021-09-05 06:58:40 +08:00
HibiKier 887177913d Update hook.py 2021-09-05 03:20:03 +08:00
HibiKier b6b0dc85bf Update update_info.json 2021-09-05 02:49:16 +08:00
HibiKier 29f47878e9 Update data_source.py 2021-09-05 02:46:52 +08:00
HibiKier 440b548a4f Update __init__.py 2021-09-05 02:46:40 +08:00
HibiKier 5191953657 Update update_info.json 2021-09-05 02:32:42 +08:00
HibiKier 877ac72761 Update update_info.json 2021-09-05 02:32:24 +08:00
HibiKier 685befee6b Update update_info.json 2021-09-05 02:29:59 +08:00
HibiKier 7afb099c12 update code 2021-09-05 02:21:38 +08:00
hibiki 21a5feda43 update readme.md 2021-08-22 12:20:23 +08:00
hibiki b7b16cfd21 update send_img 2021-08-19 19:12:33 +08:00
hibiki 615f3a58e9 fix upload_img 2021-08-19 18:43:24 +08:00
hibiki f65fd73d6d update readme.md 2021-08-19 13:57:11 +08:00
436 changed files with 9859 additions and 5185 deletions
+131 -400
View File
@@ -2,7 +2,7 @@
![maven](https://img.shields.io/badge/python-3.8%2B-blue)
![maven](https://img.shields.io/badge/nonebot-2.0.0-yellow)
![maven](https://img.shields.io/badge/go--cqhttp-0.9.40--fix4-red)
![maven](https://img.shields.io/badge/go--cqhttp-1.0.0-red)
# 绪山真寻Bot
****
@@ -11,7 +11,9 @@
用爱发电,某些功能学习借鉴了大佬们的代码,因为绪山真寻实在太可爱了因此开发了
绪山真寻bot,实现了一些对群友的娱乐功能和实用功能(大概)。
如果该项目的图片等等侵犯猫豆腐老师权益请联系我删除!
如果该项目的图片等等侵犯猫豆腐老师权益请联系我删除!
如果希望有个地方讨论绪山真寻Bot,或者有问题或建议,可以发送issues或加入[ <strong>[是真寻酱哒](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>]
## 声明
此项目仅用于学习交流,请勿用于非法用途
@@ -29,7 +31,6 @@
- [x] 图灵AI(会把'你'等关键字替换为你的昵称),且带有 [AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus),够味
- [x] 签到/我的签到/好感度排行/好感度总排行(影响色图概率和开箱次数,支持配置)
- [x] 发送某文件夹下的随机图片(支持自定义,默认:美图,萝莉,壁纸)
- [x] 尝试搜索不色的图片 ↑↑
- [x] 色图(这不是基础功能嘛喂)
- [x] coser
- [x] 黑白草图生成器
@@ -47,6 +48,7 @@
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 金币红包
- [x] 微博热搜
- [x] B站主播/UP/番剧订阅
- [x] pil对图片的一些操作
- [x] BUFF饰品底价查询(需要session)
@@ -69,7 +71,7 @@
- [x] 我的信息(只是为了看看什么时候入群)
- [x] 更新信息(如果继续更新的话)
- [x] go-cqhttp最新版下载和上传(不需要请删除)
- [x] 撤回 (使用[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)插件)
- [x] 撤回
- [x] 滴滴滴-(用户对超级用户发送消息)
- [x] 金币红包/金币排行
- [x] 俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
@@ -81,7 +83,7 @@
### 已实现的管理员功能
- [x] 更新群组成员信息
- [x] 95%的群功能开关 (基于[nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager)插件修改)
- [x] 95%的群功能开关
- [x] 查看群内被动技能状态
- [x] 自定义群欢迎消息(是真寻的不是管家的!)
- [x] .ban/.unban(支持设置ban时长)= 黑白名单
@@ -89,9 +91,10 @@
- [x] 上传图片/连续上传图片 (上传图片至指定图库)
- [x] 移动图片 (同上)
- [x] 删除图片 (同上)
- [x] 群内B站订阅
### 已实现的超级用户功能
- [x] 添加/删除管理(是真寻的管理员权限,不是群管理员)
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
- [x] 开启/关闭指定群的广播通知
- [x] 广播
- [x] 自检(检查系统状态)
@@ -103,7 +106,6 @@
- [x] 节日红包发送
- [x] 修改群权限
- [x] ban
- [x] 添加/删除群白名单
- [x] 更新色图
- [x] 更新价格/更加图片(csgo开箱)
- [x] 重载原神/方舟/赛马娘/坎公骑冠剑卡池
@@ -111,8 +113,10 @@
- [x] PIX相关操作
- [x] 检查更新真寻
- [x] 重启
- [x] 添加/删除群白名单
- [x] 添加/删除/查看群白名单
- [x] 功能开关(更多设置)
- [x] 功能状态
- [x] b了
#### 超级用户的被动技能
- [x] 邀请入群提醒(别人邀请真寻入群)
@@ -122,7 +126,7 @@
- [x] 进群欢迎消息
- [x] 群早晚安
- [x] 每日开箱重置提醒
- [x] b站转发解析(解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv)
- [x] b站转发解析(解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv),且5分钟内不解析相同url
- [x] 丢人爬(爬表情包)
- [x] epic通知(每日发送epic免费游戏链接)
- [x] 原神黄历提醒
@@ -145,10 +149,12 @@
### 常用功能
** [*]:表示该参数可有多个 [?]:表示参数可选 **
| 功能 | 指令 | 说明
| ----------------------| :--------------------------------------:| :------------------------:
| 签到 | 签到/我的签到/好感度排行/好感度总榜/好感度总榜\[显示我/屏蔽我] | 普通的签到插件,可以获得好感度和金币<br>好感度影响开箱次数和涩图触发概率,金币用于购买道具,俄罗斯轮盘赌注以及金币红包<br>好感度总榜,显示所有群的群员好感度排行,可通过命令好感度总榜\[显示我/屏蔽我] 来设置是否隐藏
| 发送图片 | 美图/壁纸/萝莉 \[id](默认随机)/\[num]张图\[keyword] | 发送指定文件夹下的图片<br>示例:萝莉->发送img文件夹下luoli文件夹下的图片<br>在线搜索一些不色的图,示例:3张图米浴
| 发送图片 | 美图/壁纸/萝莉 \[id]?(默认随机)/\[num]张图\[keyword] | 发送指定文件夹下的图片<br>示例:萝莉->发送img文件夹下luoli文件夹下的图片<br>在线搜索一些不色的图,示例:3张图米浴
| 色图 | 色图/色图xx/n张色图/n张xx的色图/查色图(查询本地色图信息)/色图r【n<10】 | 色图r返回10张r18色图(仅私聊),并限制每日次数(默认5次)<br>其他示例:色图 真寻 <br>5张真寻的色图
| 黑白草图 | 黑白草图/黑白图 \[文字] \[图片] | 整活生成器,示例:黑白图 我喜欢真寻 \[图片]
| coser | coser/cos/括丝 | coser图片,说实话挺失望的,太色了
@@ -156,7 +162,7 @@
| 戳一戳 | 戳一戳 | 随机发送钉宫语音 or 美图 or 萝莉图 or 文本
| 模拟开箱 | 开箱 \[武器箱名称](默认随机)/N连开箱 \[武器箱名称](默认随机)/我的开箱/群开箱统计/我的金色 | 当不指定武器箱时默认随机,此功能需要先在/open_cases/config.py中编写指定武器箱数据,然后提前爬取价格,使用超级用户命令更新cookie后,再使用命令更新xx武器箱【注:未设置爬取频率,可能会被禁用api(请谨慎!!用小号!!)】
| 鲁迅说过 | 鲁迅说过 \[文本] | 示例:鲁迅说过 真寻世界第一可爱
| 假消息 | 假消息 \[网址] \[标题] \[内容](可选) \[图片](可选) | 构造虚假的分享消息
| 假消息 | 假消息 \[网址] \[标题] \[内容]? \[图片]? | 构造虚假的分享消息
| 商店系统 | 商店/我的金币/购买道具 \[名称或序号] \[数量](默认1)/使用道具 \[名称或序号] | 示例:<br>购买道具 1 3<br>购买道具 好感度双倍加持卡Ⅰ 3<br>使用道具 1<br>使用道具 好感度双倍加持卡Ⅰ
| 抽卡系统 | 原神/明日方舟/赛马娘/坎公骑冠剑/碧蓝航线/阴阳师/公主连结(pcr)/FGO N抽/一井 | 详细帮助请查看: [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw) <br>示例:原神90抽
| 我有一个朋友 | 我有一个朋友他说/想问问/\[文本] | 会将文本中的(他,她,它)替换成 '我'<br>示例:我有一个朋友想问问他喜不喜欢真寻
@@ -170,20 +176,20 @@
| 金币排行 | 金币排行 | 字面意思
|网易云热评 | 到点了/12点了/网易云热评/网易云评论 | 防下塔
| 古诗 | 念诗/念首诗/来首诗 | 突然文艺起来了
|微博热搜 | 微博热搜/微博热搜[序号] | 快捷热搜查询方式
|微博热搜 | 微博热搜/微博热搜[序号]? | 快捷热搜查询方式
| pil对图片的操作 | 修改尺寸/等比压缩/旋转图片/水平翻转/铅笔滤镜/模糊效果/锐化效果/高斯模糊/边缘检测/底色替换 | 选项较多,请直接发送 真寻图片帮助
| BUFF皮肤底价查询 | 查询皮肤 \[武器名称] \[皮肤名称] | 网络不友好的话会经常超时<br>示例:查询皮肤 沙漠之鹰 印花集
| 天气查询 | \[城市]天气 | 非常常见的插件,第一个入门插件
| 疫情查询 | 疫情/查询疫情 \[城市名或省份名] | 示例:疫情杭州
| bt磁力搜索 | bt \[关键词] \[页数](默认第1页) | 该功能仅仅提供给私聊,因为可以搜到一些色色的东西,示例:bt钢铁侠 5
| bt磁力搜索 | bt \[关键词] \[页数]?(默认第1页) | 该功能仅仅提供给私聊,因为可以搜到一些色色的东西,示例:bt钢铁侠 5
| 上车 | 略 | 直接查看真寻帮助 上车,每日限制次数(默认5)
| 以图识番 | 识番 \[图片] | 以图搜翻,图片越清晰越完整正确率越高
| 以图搜图 | 识图 (asc)? \[图片] | 参数asc更换搜索引擎为ascii2d,默认为saucenao
| 点歌 | 点歌 \[歌名] | 网易云点歌小助手
| 搜番 | 搜番 \[关键字] | 群聊只返回5个结果,私聊返回20个结果
| epic白嫖游戏通知 | epic | 通知你又到了白嫖游戏的时候,可以不玩,不能没有
| P站排行榜 | p站排行 \[排行类型参数](默认日榜) \[数量](可选) \[日期](可选)| 9种不同排行榜,r18类型仅可私聊,通过参数选择,查看真寻帮助p站排行<br>示例:p站排行榜 1 9 2018-4-25
| 搜图 | 搜图 \[关键词] \[数量](可选) \[排序方式](可选) \[r18](可选)| r18仅可私聊,查看真寻帮助搜图
| P站排行榜 | p站排行 \[排行类型参数]? \[数量]? \[日期]?| 9种不同排行榜,r18类型仅可私聊,通过参数选择,查看真寻帮助p站排行<br>示例:p站排行榜 1 9 2018-4-25
| 搜图 | 搜图 \[关键词] \[数量]? \[排序方式]? \[r18]?| r18仅可私聊,查看真寻帮助搜图
| 通过PID搜索图片 | p搜 [pid] | 在群内使用此功能会在30秒内撤回
| 翻译 | 英翻/日翻/韩翻/翻韩/翻日/翻英 \[文本] | 三种语言互相翻译
| 获取b站视频封面 | b封面 [链接/av/bv/cv/直播id] | 快捷的封面获取方式
@@ -191,13 +197,15 @@
| 自我介绍 | 自我介绍 | 没错,一份正经的真寻自我介绍
| 我的权限 | 我的权限 | 真寻内部定义的一套权限系统
| 我的信息 | 我的信息 | 唯一的作用就是看看什么时候加入群
| 撤回 | 撤回 \[消息位置](默认为最新一条消息) | 按顺序撤回发送的消息,示例:撤回 1
| 撤回 | 撤回 \[消息位置]?(默认为最新一条消息) | 按顺序撤回发送的消息,示例:撤回 1
| 滴滴滴- | 滴滴滴- \[文本] | 用于用户联系真寻的超级用户
|功能调用统计可视化 | 功能调用统计(自记录以来的功能调用统计)<br>周功能调用统计 [plugin_name]<br>月功能调用统计 [plugin_name]| 当plugin_name为空时为7天或30内的所有功能统计
| pix | pix/PIX [tags/uid/pid:pid] [num] | 无参数时随机查看pix图库的图片(无r18),num数量默认=1,tags:查看相关tags图片,uid:查找相关画师图片,pid:pid:指定查看pid图片<br>示例:pix原神 3<br>pix23493844<br>pixpid:29429933
| 添加pix关键词/uid/pid | 添加pix关键词/uid/pid *[关键词/uid/pid]| 添加关键词或uid或pid用于下次搜索,关键词搜索相关tag,uid会收录作者下收藏符合标准的作品,pid收录单张作品<br>示例:添加pix关键词 原神<br> 添加pixuid 123441<br>添加pixpid 2748937|
| 查看pix图库 | 查看pix图库 [tags] | 查看已收录的tag相关图片数量<br>示例:查看pix图库 原神 莫娜
|显示pix关键词 | 显示pix关键词 | 查看已收录的所有关键词/UID/PID
| b了 | b了 [at] | 使真寻完全忽略一个用户的所有信息
| B站订阅 | 添加订阅 [主播/UP/番剧] [id/链接/番名] / 删除订阅 [id] / 查看订阅 | 可以通过直接间链接或主播间id添加订阅主播开播提醒,动态和投稿,可以通过番名,番剧的id,或者番剧链接添加番剧订阅(是番剧id,md开头,不是集数id,ep开头的)更新, 可以通过UP个人id或UP主页链接订阅UP动态和投稿
### 管理员功能
@@ -210,18 +218,19 @@
| 查看群被动技能 | 2 | 群通知状态 | 详细请查看被动技能列表
| 被动技能开关 | 2 | 开启/关闭被动技能 | 有时候花里胡哨通知也会很烦人
| 自定义群欢迎消息 | 2 | 自定义群欢迎消息 \[文本] \[图片] | 文本和图片至少需要一个,在文本内添加"\[at]"字符串可以用来设置艾特进群的新群员
| 黑名单 | 5 | .ban/.unban \[at] \[小时](可选) \[分钟](可选)| 不提供具体时间的话则ban掉永久,且权限低的用户无法unban高权限用户的ban,同级权限也无法进行ban/unban <br>示例:.ban@笨蛋 1 50
| 黑名单 | 5 | .ban/.unban \[at] \[小时]? \[分钟]?| 不提供具体时间的话则ban掉永久,且权限低的用户无法unban高权限用户的ban,同级权限也无法进行ban/unban <br>示例:.ban@笨蛋 1 50
| 刷屏检测相关 | 5 | 刷屏检测设置/设置检测时间 \[文本]/设置检测次数 \[文本]/设置禁言时长 \[分钟]| 非常讨厌刷屏的人,打算给他们一点教训
| 上传图片 | 6 | 上传图片 \[图库] \[图片]... | 上传图片至指定图库,虽然并不打算开放给群员,但还是写了,支持批量图片<br>示例:上传图片 美图 \[图片]..
| 删除图片 | 6 | 删除图片 [图库] \[图片id] | 通过指定本地图片id来删除指定图库的图片<br>示例:删除图片 美图 1
| 移动图片 | 6 | 移动图片 \[移出的图库] \[移入的图库] \[图片id] | 移动指定图库中的图片到指定的新图库中,移入的图片id更改为移入图库的最后一位,移除的图库中原本图片的id又最后一位图片替代<br>示例:移动图片 美图 萝莉 22
|B站订阅 | 5 | 功能同上,就是在群中有权限限制 | 略
### 超级用户功能
| 功能 | 指令 | 说明
| ----------------------| :--------------------------------------:| :------------------------:
| 权限增删 | 添加/删除权限 \[at] \[level]<br>添加/删除权限 [qq] [group] [level] | 用于添加或修改权限等级,且该权限不会被自动更新取消
| 查看群组/好友 | 查看群组/好友 | 查看真寻添加的群组与好友
| 所有群组/好友 | 所有群组/好友 | 查看真寻添加的群组与好友
| 广播 | 广播- [文本] | 广播所有群组
| 更新色图 | 更新色图 | 更新群友搜索色图时保存的url
| 回复 | /t | 命令较多,请查看/t帮助,省略群号则私聊用户(必须要有用户的好友)
@@ -231,240 +240,30 @@
| 检查系统状态 | 自检 | 略
| 更新好友/群组信息| 更新好友/群组信息 | 包含自动更新,被t出群等等有更好的可视信息
| 重载卡池 | 略 | 重载抽卡的游戏卡池,请查看 \[nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw)
| 添加商品 | 添加商品 \[名称]-\[价格]-\[描述]-\[折扣](小数)(可选)-\[限时时间](分钟)(可选) | 为真寻的商店添加一点点道具<br>示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60
| 添加商品 | 添加商品 \[名称]-\[价格]-\[描述]-\[折扣](小数)?-\[限时时间](分钟)? | 为真寻的商店添加一点点道具<br>示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60
| 删除商品 | 删除商品 \[名称或序号] | 在真寻的商店中删除一点东西
| 修改商品 | 修改商品 -name \[名称或序号] -price \[价格] -des \[描述] -discount \[折扣] -time \[限时]| 注意空格,不需要的参数可以不加<br>示例:修改商品 -name 1 -price 900 【修改序号为1的商品的价格为900】
| 节日红包 | 节日红包 \[金额] \[数量] \[祝福语](可选) \[群号](可选)... | 群号支持批量,使用空格隔开,不使用群号则对所有群发送节日红包,节日红包有效时间为24小时,祝福语默认为“恭喜发财 大吉大利”<br>示例:节日红包 10000 15 真寻真可爱 123324423 23423423
| 节日红包 | 节日红包 \[金额] \[数量] \[祝福语]? \[群号]?... | 群号支持批量,使用空格隔开,不使用群号则对所有群发送节日红包,节日红包有效时间为24小时,祝福语默认为“恭喜发财 大吉大利”<br>示例:节日红包 10000 15 真寻真可爱 123324423 23423423
| 修改群权限 | 修改群权限 \[group] \[level] | 所以说这功能是对内鬼的无奈,默认群权限为5,默认无法使用 色图/coser/p站排行/搜图(这些功能都要9级权限)
|更新原神今日素材| 更新原神今日素材 | 自动更新原神每日素材失败时可以手动触发
|更新原神资源信息| 更新原神资源信息 | 除了每日自动更新的资源外,额外更新大地图
| 清理数据 | 清理数据 | 清理 temp,rar,r18_rar 文件夹的文件数据
|添加pix关键词/uid/pid | 添加pix关键词/uid/pid [keyword/pid:pid/uid:uid] [-f]? | 与普通功能相同,额外可以通过参数 -f 强制通过检测
|删除pix关键词 | 删除pix关键词 *[keyword/uid/pid:pid] | 删除已收录的keyword/uid/pid
|更新pix关键词 | 更新pix关键词 [keyword/pid:pid/uid:uid] [num]| 更新keyword,uid,pid或指定uid,pid,未指定时,则更新全部,当num未指定时为keyword/uid/pid更新全部<br>示例:更新pix关键词<br>更新pix关键词uid 8<br>更新pix关键词pid:83457477
|更新pix关键词 | 更新pix关键词 [keyword/pid:pid/uid:uid] [num]?| 更新keyword,uid,pid或指定uid,pid,未指定时,则更新全部,当num未指定时为keyword/uid/pid更新全部<br>示例:更新pix关键词<br>更新pix关键词uid 8<br>更新pix关键词pid:83457477<br>num:倒叙更新数量
|删除pix图片 | 删除pix图片 [*pid] [-b]? | [-b]参数为删除的同时加入黑名单(不再更新),虽然是pid,但是_p也可以<br>示例:删除pix图片3458344 8235234_p1 -b
|显示pix关键词 | 显示pix关键词 | 与普通功能相同,额外显示待收录和黑名单
|pix检测更新 | pix检测更新 [update]? | 检测从未更新过的pid或uid,-update参数将在检测后直接更新未更新过的pid或uid<br>示例:pix检测更新 update
| 检查更新真寻 | 检查更新真寻 | 不再需要麻烦的clone第一步
| 关闭功能 | 关闭[功能] [group/private]/*[群号] | 关闭色图:维护功能(关闭总开关)<br>关闭色图 g:在群内限制功能<br>关闭色图 p:在私聊限制功能<br>关闭色图 1234678:禁用12345678的色图功能
| 群白名单 | 添加/删除群白名单 *[群号] | 白名单内的群不会受到 维护 限制
| 关闭功能 | 关闭[功能] [group/private]/*[群号]? | 关闭色图:维护功能(关闭总开关)<br>关闭色图 g:在群内限制功能<br>关闭色图 p:在私聊限制功能<br>关闭色图 1234678:禁用12345678的色图功能
| 群白名单 | 添加/删除群白名单 *[群号] / 查看群白名单 | 白名单内的群不会受到 维护 限制
| 功能状态 | 功能状态 | 查看功能开关状态
| pix | pix [-s/-r] [keyword] | 可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
| 重载插件配置 |重载插件配置 |用于生效手动修改配文件
|帮助 -super | 帮助[功能] -super | 显示该插件的超级用户帮助
</details>
## 部分功能展示
<details>
<summary>部分功能展示及说明</summary>
### 帮助以及开关(功能控制)
群帮助将会在功能左侧展示该功能的开关,带有√或×的功能代表可以开关<br>
此插件使用 [nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager) 并魔改一点实现
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/help.PNG)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/kg1.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/kg3.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/kg2.png)
<br>
如果你希望某功能暂时停用<br>
私聊发送 npm block xx (xx=功能名)来锁定<br>
使用npm unblock xx 进行解锁
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/ocgn.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/ocgn2.png)
### 签到
普普通通的签到,设置影响开箱次数和涩图触发成功的概率(可配置)<br>
开箱次数 = 初始开箱数量 + 好感度 / 3<br>
金币 = random.randint(100) + random.randint(好感度)【好感度获取的金币不会超过200】
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/sign.png)
### 黑白草图
整活生成器(从未设想的道路)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/w2b.png)
### 发送文件夹下随机图片
提供了 美图589(获取该图库下文件名589.jpg的图片)方法,图库内图片名称需要有序(如:0.jpg,1.jpg....)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/send_img.png)
### 色图
略,send_setu/check_setu_hash.py文件用于记录涩图hash和检测文件名是否连贯(例如:0.jpg, 1.jpg....)
### 开箱(csgo模拟开箱)
我的开箱/群开箱统计/我的金色 功能是对开箱数据的统计展示 <br>
目前支持的武器箱(数据已备好):
* 狂牙大行动武器箱
* 突围大行动武器箱
* 命悬一线武器箱
* 裂空武器箱
* 光谱武器箱
<br>
BUFF账号可能会因为短时间内访问api次数过多被禁止访问api!!
如果是第一次启动请先使用命令 “更新价格”, “更新图片” (需要配置cookie!!如果经常超时请设置代理,配置文件中的 buff_proxy!)<br>
如果需要配置新的箱子,请在.config.py中配置好该箱子中的皮肤,且列表名是箱子名称的大写拼音<br>
示例:光谱武器箱 GUANGPU_CASE_KNIFE,GUANGPU_CASE_RED...后面的颜色代表皮肤品质
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/kaixiang.png)
### BUFF皮肤底价查询
需要配置cookie!!!!!!!!<br>
如果经常超时请设置代理,配置文件中的 buff_proxy!
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/buff.png)
### coser
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/coser.png)
### 鸡汤/语录
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/jitang.png)
### 骂我
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/mawo.png)
### 鲁迅说
此插件使用 [nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/luxun.png)
### 假消息
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/jiaxiaoxi.png)
### 商店系统
商店内的道具支持自定义,但需要写触发后的效果...整不出活,到头来也就增加好感度概率的商品
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/shop.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/daoju.png)
### 昵称系统
养成方法第一步,让可爱的小真寻叫自己昵称!(替换ai中的'你'等等)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/nicheng1.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/nicheng2.png)
### 抽卡(8种手游的抽卡)
已单独分离并上传至nb2商店,不再放图片了,项目地址:[nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw)
### 我有一个朋友...
使用大佬的插件 [cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins#%E7%94%9F%E6%88%90%E5%99%A8%E6%8F%92%E4%BB%B6)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/one_firend.png)
### 原神黄历/今日素材/丘丘语翻译/地图资源查询
使用大佬的插件 [Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)
### 对图片的操作
只是一些简单对图片操作(娱乐整活)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/tupian.png)
### 识番
使用大佬的插件 [XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/shifan.png)
### 识图
使用nb2商店插件 [nonebot_plugin_picsearcher](https://github.com/synodriver/nonebot_plugin_picsearcher) (可配置图片返回的最大数量)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/shitu.png)
### epic免费游戏
访问rsshub获取数据解析<br>可以不玩,不能没有
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/epic.png)
### P站排行/搜图
访问rsshub获取数据解析
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/p_rank.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/p_sou.png)
### 翻译
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/fanyi.png)
### 自定义群欢迎消息
关键字 [at] 判断是否艾特入群用户
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/qhyxx.png)
### 查看当前群欢迎消息
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/qunhuanying.png)
### 自检
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/check.png)
### .ban/.unban
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/ban.png)
### 查看被动技能(被动技能除复读外都提供了开关)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/beidong.png)
### 自我介绍
只是一段简单自我介绍,但是,还是想放上来
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/jieshao.png)
### 我的信息/我的权限
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/info.png)
### 金币红包
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/redbag0.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/redbag1.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/redbag2.png)
### 俄罗斯轮盘
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/russian0.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/russian1.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/russian2.png)
<br>
### 其他
点歌:使用 [nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) 插件<br>
<br><br>
## 其他功能请自己试一试 )
</details>
## 部署
@@ -491,7 +290,7 @@ pip install -r requirements.txt
python bot.py
```
## 配置(暂时不更新 json 配置,请将USE_CONFIG_FILE设置为False)
## 配置
在 configs/config.py 中的 USE_CONFIG_FILE,默认为False
```
@@ -507,167 +306,98 @@ python bot.py
在./configs/config.py中配置基本配置(除API KEY ,数据库和代理外都含有默认值)
在./configs/path_config.py配置路径(含有默认配置)
########(暂时不更新 json 配置,请将USE_CONFIG_FILE设置为False,直接进入./configs/config.py进行配置)
# 是否使用配置文件(为True时这将会生成三份配置文件
./config.json:主要配置
./configs/plugins2cmd_config.json: 功能模块与对应命令配置
./configs/other_config.json: 一些插件配置)
USE_CONFIG_FILE = True
# 如果不使用配置文件,将USE_CONFIG_FILE设置为False
#可在./configs/config.py文件中修改配置,在./configs/path_config.py修改资源路径
# 已在./configs/config.py和./configs/path_config.py中为各个配置提供注解!
```
## 配置文件注解(如果使用配置文件的话)
<details>
<summary>配置文件注解</summary>
./config.json
```
{
# 必填(影响功能运行)
"apikey": {
"LOLICON_KEY": "", # loliconAPI,缺失会导致色图功能异常
"TL_KEY": [] # 图灵Key(为什么要用列表?因为白嫖用户能拿5个apikey,每个apikey每日限制100条)
},
# (必填!!!)
# 数据库配置(如果填写了bind,后面就不用再填了)只是帮你拼接好)
# 示例:"bind": "postgresql://user:password@127.0.0.1:5432/database"
"sql": {
"bind": "",
"sql_name": "",
"user": "",
"password": "",
"address": "",
"port": "",
"database": ""
},
# 路径设置(不填则使用默认)
"path": {
"IMAGE_PATH": "", # 图片路径
"VOICE_PATH": "", # 音频路径
"TXT_PATH": "", # 文本路径
"LOG_PATH": "", # 日志路径
"DATA_PATH": "", # 数据路径
"DRAW_PATH": "" # 抽卡数据路径
"TEMP_PATH": "" # 临时图片路径
},
# 代理设置
"proxy": {
"system_proxy": "", # 系统代理
"buff_proxy": "" # buff代理
},
# RSSHUB地址
"rsshub": {
"RSSHUBAPP": "https:\/\/docs.rsshub.app\/"
},
# 各个管理员功能 对应的 权限
"level": {
"DELETE_IMG_LEVEL": 7,
"MOVE_IMG_LEVEL": 7,
"UPLOAD_LEVEL": 6,
"BAN_LEVEL": 5,
"OC_LEVEL": 2,
"MUTE_LEVEL": 5
}
}
```
./configs/plugins2cmd_config.json
```
# 单个例子注解
"send_img": [
"发送图片",
"萝莉",
"美图",
"壁纸"
]
# 发送 关闭发送图片/关闭萝莉/关闭美图/关闭壁纸 都将触发命令 关闭send_img
```
./configs/other_config.json
```
{
"base": {
# 图库配置,会影响 上传/删除/移动/发送图片等功能
"IMAGE_DIR_LIST": [
"色图",
"美图",
"萝莉",
"壁纸"
],
"BAN_RESULT": "才不会给你发消息." # 当被ban用户触发命令后发送的消息
},
"bool": {
"AUTO_ADD_FRIEND": true, # 是否自动添加好友
"DOWNLOAD_SETU": true # 是否下载bot发送过的色图(不会重复)
},
"max_count": {
"MAXINFO_REIMU": 7, # 上车(reimu)功能查找目的地的最大数
"COUNT_PER_DAY_REIMU": 5, # 每日上车(reimu)次数限制
"MAXINFO_BT": 10, # bt功能单次查找最大数
"MAXINFO_PRIVATE_ANIME": 20, # 私聊搜索动漫返回的最大数量
"MAXINFO_GROUP_ANIME": 5, # 群搜索动漫返回的最大数量
"MAX_FIND_IMG_COUNT": 3, # 识图最大返回数
"MAX_SIGN_GOLD": 200, # 签到好感度加成额外获得的最大金币数
"MAX_SETU_R_COUNT": 5, # 每日色图r次数限制
},
"probability": {
"INITIAL_SETU_PROBABILITY": 0.7, # 涩图触发的基础概率(触发概率 = 基础概率 + 好感度)
"FUDU_PROBABILITY": 0.7 # 复读概率
},
# 注:即在 MALICIOUS_CHECK_TIME 时间内触发相同命令 MALICIOUS_BAN_COUNT 将被ban MALICIOUS_BAN_TIME 分钟
"malicious_ban": {
"MALICIOUS_BAN_TIME": 30, # 恶意触发命令被ban的时长(分钟)
"MALICIOUS_BAN_COUNT": 4, # 恶意触发命令的规定次数
"MALICIOUS_CHECK_TIME": 5 # 恶意触发命令的规定时间(秒)
},
"open_case": {
"INITIAL_OPEN_CASE_COUNT": 20 # 每日开箱的基本数量(总数量=基本数量 + 好感度/3)
},
# 注:即在 MUTE_DEFAULT_TIME 内发送相似(包含)消息超过 MUTE_DEFAULT_COUNT 将会被 MUTE_DEFAULT_DURATION 分钟
# 这只是默认配置,各个群可以自由设置群内刷屏检测配置
"mute": {
"MUTE_DEFAULT_COUNT": 10, # 刷屏检测默认检测最大次数
"MUTE_DEFAULT_TIME": 7, # 刷屏检测默认规定时间(秒)
"MUTE_DEFAULT_DURATION": 10 # 刷屏检测默认禁言时长(分钟)
},
"other": {
"UPDATE_GOCQ_GROUP": [], # 是否需要为某些群上传最新版的gocq?
"ADMIN_DEFAULT_AUTH": 5 # 默认群管理员权限
},
# 管理员功能 和 对应的 权限
"auth": {
"admin_plugins_auth": {
"admin_bot_manage": 2,
"ban": 5,
"delete_img": 7,
"move_img": 7,
"upload_img": 6,
"admin_help": 1,
"mute": 5
}
}
}
```
</details>
## 更新
### 2021/10/4
* 修复了功能调用统计失效问题
* 当色图库中没有色图时,会在线搜索色图而不是‘没找到符合条件的色图...’
* 快速更新权限再给超级用户发送错误日志
* 修复疫情未加载省份城市无法正常使用
### 2021/10/3
* 对插件进行分离
* 重写了插件与限制管理器以及帮助获取
* 修改一些插件目录和数据存储目录
* 插件通用配置与限制数据将以ymal文件存储 \[路径:data/configs]
* 所有商店相关操作调用统计合并为商店(包括之前已经保存的数据,会先进行备份)
* 简化了点歌的代码相关
* 修复了碧蓝航线抽卡新框导致报错无法正常初始化
* 修复了P站排行/搜图在PC端无法正常显示
* 添加了插件对超级用户是否限制的配置 ‘limit_superuser’
* 添加命令 ‘重载插件配置’,用于生效手动修改配文件
* 超级用户帮助可以添加 -super 来显示该插件的超级用户帮助,示例:帮助.ban -super
* 原神黄历改为网页截图
* 修改了鲁迅说逻辑结构
* 修改了统计图表样式,改为自定义CreateMat
* 节日红包不再被24小时限制,群内多个节日红包将会覆盖
* 当群权限为-1时,不会对群发送修改权限通知,并屏蔽此群一切命令(包括提醒)
* 修复了红包数量可以过大或为负数,红包数量大于群员数量时会修改为群员数量
* 修复了负数开箱
* 签到最低好感度设置为0.01 [@pull/53](https://github.com/HibiKier/zhenxun_bot/pull/53)
* pip安装新依赖 ruamel.yaml
* 修复功能 EPIC [@pull/58](https://github.com/HibiKier/zhenxun_bot/pull/58)
### 2021/9/10
* 修复撤回消息有时无法正确获取消息id
### 2021/9/9
* 替换coser API
* 修复签到uid可能不默认为0
* 修复签到可能重复的问题
* 修复无订阅时递归出错
* 启用了plugins2info_dict, plugins2cd_dict, plugins2exists_dict配置文件,通过USE_CONFIG_FILE=True开启
* 修复涩图local_id会被固定为50
* 优化图库数量查询
* 修复原神大地图过大无法打开报错
* 修复无法显示正确的涩图上限
### 2021/9/7
* 修改 update_info.json
* 修改 更新信息 图片大小
* 修复 查看订阅 命令 UP和番剧无法正常显示
* 修复订阅推送无法正确推送
* 修复搜图返回列表为空时无法正确回复 [@pull/40](https://github.com/HibiKier/zhenxun_bot/pull/40)
### 2021/9/5
* 添加配置PIX_IMAGE_SIZE,调整PIX下载图片大小,当设置的图片404时,改为原图
* 新增配置DEFAULT_GROUP_LEVEL,默认群等级
* 新增超级用户功能 super ban,将屏蔽被ban用户的所有消息,指令:b了
* b站转发解析支持纯BV号解析,且五分钟内不会解析相同url
* 俄罗斯轮盘新增 连胜/最高连胜/连败/最高连败 纪录,新增 最高连胜排行榜/最高连败排行榜
* 增加扩展图库 OmegaPixivIllusts,不想自己找图的人福音([Ailitonia](https://github.com/Ailitonia) 佬的高质量精品手筛图库)([传送门](https://github.com/Ailitonia/omega-miya/blob/master/archive_data/db_pixiv.7z) ),可以手动导入图库,也可以将解压文件放在bot.py同级目录重启bot
* 增加配置PIX_OMEGA_PIXIV_RATIO,PIX功能发送PIX图库和扩展图库OmegaPixivIllusts图片的比例,如果没有使用扩展图库OmegaPixivIllusts,请设置为(10, 0)
* 增加配置WITHDRAW_PIX_TIME,用于配置在开关PIX图片在群私聊的自动撤回
* 上传图库cases, 开箱 也可以连抽(未更新过没有价格)
* 新增命令 查看群白名单
* plugins2info_dict新增键"default_status",设置加入新群时功能的默认开关状态
* 增加配置plugins2exists_dict,可自定义是否阻塞某命令同时触发多次
* 增加配置plugins2cd_dict,可自定义为命令添加cd
* 新增B站订阅(直播/番剧/UP)[测试],提供命令:添加订阅 [主播/UP/番剧] [id/链接/番名],删除订阅 [id],查看订阅
* 优化pix和色图的数据库查询
* 触发已关闭的功能的正则时不再触发ai
* 更换coser API
* PIX搜索pid功能在群聊无法搜索PIX图库的r18和OmegaPixivIllusts的r15以及r18,超级用户除外
* PIX单次搜索的图片张数超级用户限制为至多30张,普通用户10张
* PIX超级用户新增-s,-r,可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
* 优化P站排行和搜图,现在需要艾特,改为使用HIBIAPI,在群内时将使用合并消息(群聊搜图会屏蔽R-18)
* win10下playwright相关功能无法使用,但是不再需要删除文件
* 签到大改,优化签到方式与逻辑,改为图片形式发送,有概率额外获得随机道具(好感度有加成)
* 修改撤回功能,改为回复撤回,回复发送撤回
* 更改logging为loguru
* 删除了 发送图片 中的 [N]张图[keyword] 功能
* 修复私聊 关闭[功能] 默认不为 全部 而要添加参数 ‘a’
* 修复0权限用户可以修改禁言检测相关设置
### 2021/8/17
* 新增配置CHECK_NOTICE_INFO_CD,修改群权限,个人权限检测各种检测的提示消息cd
@@ -737,13 +467,13 @@ python bot.py
* 功能维护时超级用户依然可以调用(苦了谁都不能苦了自己)
* 修复获取赛马娘UP公告
* 重写 色图/更新色图
* 色图数据存储改为数据库,启动时会更新之前的色图数据(有的话),更新完毕后会删除原数据文件,如果需要保留请提前备份,
* lolicon api改为v2
* 取消r18次数限制
* 单次搜索至多保存100条链接
* 添加定时撤回
* 暂时取消上传/删除色图
*
* 色图数据存储改为数据库,启动时会更新之前的色图数据(有的话),更新完毕后会删除原数据文件,如果需要保留请提前备份,
* lolicon api改为v2
* 取消r18次数限制
* 单次搜索至多保存100条链接
* 添加定时撤回
* 暂时取消上传/删除色图
*
* 更新建议(不要替换你的data和resources文件夹!)
* 删除configs,plugins,services,utils,models文件夹重新clone
* 删除多余文件夹,resources/img/genshin/seek_god_eye
@@ -855,3 +585,4 @@ python bot.py
[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)
[nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says)
[AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus)
[omega-miya](https://github.com/Ailitonia/omega-miya)
+1
View File
@@ -0,0 +1 @@
__version__: v0.0.5.0
+51
View File
@@ -0,0 +1,51 @@
from typing import Optional, Dict
from .data_class import StaticData
from utils.utils import FreqLimiter
from services.log import logger
from pathlib import Path
class AdminManager(StaticData):
"""
管理员命令 管理器
"""
def __init__(self):
super().__init__(None)
def add_admin_command(self, plugin: str, level: int):
"""
添加一个管理员命令
:param plugin: 模块名
:param level: 权限等级
"""
self._data[plugin] = level
def remove_admin_command(self, plugin: str):
"""
删除一个管理员命令
:param plugin: 模块名
"""
if plugin in self._data.keys():
del self._data[plugin]
def check(self, plugin: str, level: int) -> bool:
"""
检查是否满足权限
:param plugin: 模块名
:param level: 权限等级
"""
if plugin in self._data.keys():
return level >= self._data[plugin]
return True
def get_plugin_level(self, plugin: str) -> int:
"""
获取插件等级
:param plugin: 模块名
"""
if plugin in self._data.keys():
return self._data[plugin]
return 0
+1 -6
View File
@@ -2,19 +2,14 @@ import nonebot
from nonebot.adapters.cqhttp import Bot as CQHTTPBot
from services.db_context import init, disconnect
nonebot.init()
driver = nonebot.get_driver()
driver.register_adapter("cqhttp", CQHTTPBot)
config = driver.config
driver.on_startup(init)
driver.on_shutdown(disconnect)
nonebot.load_builtin_plugins()
nonebot.load_plugins("plugins")
nonebot.load_plugins("plugins/shop")
nonebot.load_plugins("plugins/genshin")
nonebot.load_plugins("plugins/alapi")
nonebot.load_plugins("plugins/pix_gallery")
nonebot.load_plugins("plugins/admin_bot_manage")
if __name__ == "__main__":
+18 -108
View File
@@ -1,17 +1,13 @@
from typing import List, Optional, Tuple
from services.service_config import TL_M_KEY, SYSTEM_M_PROXY, ALAPI_M_TOKEN
try:
import ujson as json
except ModuleNotFoundError:
import json
# 是否使用配置文件
USE_CONFIG_FILE: bool = False
# 回复消息名称
NICKNAME: str = '小真寻'
NICKNAME: str = "小真寻"
# API KEY(必要)
RSSHUBAPP: str = "https://rsshub.app" # rsshub
@@ -41,6 +37,9 @@ IMAGE_DIR_LIST: List[str] = ["美图", "萝莉", "壁纸"]
# 对被ban用户发送的消息
BAN_RESULT: str = "才不会给你发消息."
# PIX图库下载的画质 可能的值:original:原图,master:缩略图(加快发送速度)
PIX_IMAGE_SIZE: str = "master"
# 插件配置
MAXINFO_REIMU: int = 7 # 上车(reimu)功能查找目的地的最大数
@@ -51,6 +50,11 @@ MAXINFO_GROUP_ANIME: int = 5 # 群搜索动漫返回的最大数量
MAX_FIND_IMG_COUNT: int = 3 # 识图最大返回数
# 参1:延迟撤回色图时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)
WITHDRAW_SETU_TIME: Tuple[int, int] = (0, 1)
# 参1:延迟撤回PIX图片时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)
WITHDRAW_PIX_TIME: Tuple[int, int] = (0, 1)
# PIX图库 与 额外图库OmegaPixivIllusts 混合搜索的比例 参1:PIX图库 参2:OmegaPixivIllusts扩展图库(没有此图库请设置为0)
PIX_OMEGA_PIXIV_RATIO: Tuple[int, int] = (10, 0)
# 各种卡池的开关
PRTS_FLAG = True # 明日方舟
@@ -68,7 +72,7 @@ SEMAPHORE = 5 # 限制碧蓝航线和FGO并发数
ADMIN_DEFAULT_AUTH: int = 5 # 默认群管理员权限
MAX_SIGN_GOLD: int = 200 # 签到好感度加成额外获得的最大金币数
MAX_RUSSIAN_BET_GOLD: int = 1000 # 俄罗斯轮盘最大赌注金额
MAX_RUSSIAN_BET_GOLD: int = 1000 # 俄罗斯轮盘最大赌注金额
INITIAL_SETU_PROBABILITY: float = 0.7 # 色图概率
FUDU_PROBABILITY: float = 0.7 # 复读概率
@@ -78,21 +82,24 @@ MUTE_DEFAULT_COUNT: int = 10 # 刷屏禁言默认检测次数
MUTE_DEFAULT_TIME: int = 7 # 刷屏检测默认规定时间
MUTE_DEFAULT_DURATION: int = 10 # 刷屏检测默禁言时长(分钟)
CHECK_NOTICE_INFO_CD = 300 # 群检测,个人权限检测等各种检测提示信息cd
CHECK_NOTICE_INFO_CD = 300 # 群检测,个人权限检测等各种检测提示信息cd
# 注:即在 MALICIOUS_CHECK_TIME 时间内触发相同命令 MALICIOUS_BAN_COUNT 将被ban MALICIOUS_BAN_TIME 分钟
MALICIOUS_BAN_TIME: int = 30 # 恶意命令触发检测触发后ban的时长(分钟)
MALICIOUS_BAN_COUNT: int = 8 # 恶意命令触发检测最大触发次数
MALICIOUS_BAN_COUNT: int = 6 # 恶意命令触发检测最大触发次数
MALICIOUS_CHECK_TIME: int = 5 # 恶意命令触发检测规定时间内(秒)
# LEVEL
DELETE_IMG_LEVEL: int = 7 # 删除图片权限
MOVE_IMG_LEVEL: int = 7 # 移动图片权限
UPLOAD_LEVEL: int = 6 # 上传图片权限
UPLOAD_IMG_LEVEL: int = 6 # 上传图片权限
BAN_LEVEL: int = 5 # BAN权限
OC_LEVEL: int = 2 # 开关群功能权限
MUTE_LEVEL: int = 5 # 更改禁言设置权限
MEMBER_ACTIVITY_LEVEL = 5 # 群员活跃检测设置权限
GROUP_BILIBILI_SUB_LEVEL = 5 # 群内bilibili订阅需要的权限
DEFAULT_GROUP_LEVEL = 5 # 默认群等级
# 是否开启HIBIAPI搜图功能(该功能会搜索群友提交的xp)
HIBIAPI_FLAG: bool = True
@@ -116,92 +123,6 @@ IMPORT_DEFAULT_SHOP_GOODS: bool = True
# 真寻是否自动更新
AUTO_UPDATE_ZHENXUN: bool = True
# 群管理员功能 与 对应权限
admin_plugins_auth = {
"custom_welcome_message": OC_LEVEL,
"group_notification_state": OC_LEVEL,
"switch_rule": OC_LEVEL,
"update_group_member_info": OC_LEVEL,
"ban": BAN_LEVEL,
"delete_img": DELETE_IMG_LEVEL,
"move_img": MOVE_IMG_LEVEL,
"upload_img": UPLOAD_LEVEL,
"admin_help": 1,
"mute": MUTE_LEVEL,
"member_activity_handle": MEMBER_ACTIVITY_LEVEL,
}
# 模块与对应命令和对应群权限
# 用于生成帮助图片 和 开关功能
plugins2info_dict = {
"sign_in": {"level": 5, "cmd": ["签到"]},
"send_img": {"level": 5, "cmd": ["发送图片", "发图", "萝莉", "美图", "壁纸"]},
"send_setu": {"level": 9, "cmd": ["色图", "涩图", "瑟图", "查色图"]},
"white2black": {"level": 5, "cmd": ["黑白图", "黑白草图"]},
"coser": {"level": 9, "cmd": ["coser", "cos"]},
"quotations": {"level": 5, "cmd": ["语录"]},
"jitang": {"level": 5, "cmd": ["鸡汤"]},
"send_dinggong_voice": {"level": 5, "cmd": ["骂我", "骂老子", "骂劳资"]},
"open_cases": {"level": 5, "cmd": ["开箱", "我的开箱", "群开箱统计", "我的金色"]},
"luxun": {"level": 5, "cmd": ["鲁迅说", "鲁迅说过"]},
"fake_msg": {"level": 5, "cmd": ["假消息"]},
"buy": {"level": 5, "cmd": ["购买", "购买道具"]},
"my_gold": {"level": 5, "cmd": ["我的金币"]},
"my_props": {"level": 5, "cmd": ["我的道具"]},
"shop_handle": {"level": 5, "cmd": ["商店"]},
"update_pic": {"level": 5, "cmd": ["图片", "操作图片", "修改图片"]},
"search_buff_skin_price": {"level": 5, "cmd": ["查询皮肤"]},
"weather": {"level": 5, "cmd": ["天气", "查询天气", "天气查询"]},
"yiqing": {"level": 5, "cmd": ["疫情", "疫情查询", "查询疫情"]},
"what_anime": {"level": 5, "cmd": ["识番"]},
"search_anime": {"level": 5, "cmd": ["搜番"]},
"songpicker2": {"level": 5, "cmd": ["点歌"]},
"epic": {"level": 5, "cmd": ["epic"]},
"pixiv": {"level": 9, "cmd": ["pixiv", "p站排行", "搜图"]},
"poke": {"level": 5, "cmd": ["戳一戳", "拍一拍"]},
"draw_card": {
"level": 5,
"cmd": [
"抽卡",
"游戏抽卡",
"原神抽卡",
"方舟抽卡",
"坎公骑冠剑抽卡",
"pcr抽卡",
"fgo抽卡",
"碧蓝抽卡",
"碧蓝航线抽卡",
"阴阳师抽卡",
],
},
"ai": {"level": 5, "cmd": ["ai", "Ai", "AI", "aI"]},
"one_friend": {"level": 5, "cmd": ["我有一个朋友", "我有一个朋友想问问"]},
"translate": {"level": 5, "cmd": ["翻译", "英翻", "翻英", "日翻", "翻日", "韩翻", "翻韩"]},
"nonebot_plugin_picsearcher": {"level": 5, "cmd": ["识图"]},
"almanac": {"level": 5, "cmd": ["原神黄历", "黄历"]},
"material_remind": {"level": 5, "cmd": ["今日素材", "天赋材料"]},
"qiu_qiu_translation": {"level": 5, "cmd": ["丘丘翻译", "丘丘一下", "丘丘语翻译"]},
"query_resource_points": {"level": 5, "cmd": ["原神资源查询", "原神资源列表"]},
"russian": {"level": 5, "cmd": ["俄罗斯轮盘", "俄罗斯转盘", "装弹"]},
"gold_redbag": {"level": 5, "cmd": ["塞红包", "红包", "抢红包"]},
"poetry": {"level": 5, "cmd": ["念诗", "来首诗", "念首诗"]},
"comments_163": {"level": 5, "cmd": ["到点了", "12点了", "网易云热评", "网易云评论"]},
"cover": {"level": 5, "cmd": ["b封面", "B封面"]},
"pid_search": {"level": 9, "cmd": ["p搜", "P搜"]},
"pix": {
"level": 5,
"cmd": ["pix", "PIX", "pIX", "Pix", "PIx"],
},
"wbtop": {
"level": 5,
"cmd": ['微博热搜', "微博", "wbtop"]
},
"update_info": {
"level": 5,
"cmd": ['更新信息', '更新日志']
}
}
if TL_M_KEY:
TL_KEY = TL_M_KEY
@@ -214,16 +135,5 @@ if ALAPI_M_TOKEN:
HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI
RSSHUBAPP = RSSHUBAPP[:-1] if RSSHUBAPP[-1] == "/" else RSSHUBAPP
# 配置文件应用
# if USE_CONFIG_FILE:
# config = get_config_data()
# if config:
# for key in config.keys():
# if isinstance(config[key], str):
# config[key] = config[key].strip()
# if key.find("proxy") != -1:
# if not config[key]:
# config[key] = None
# # if not configs[key] and key.find("PATH") == -1:
# # configs[key] = None
# globals().update(config)
+8 -29
View File
@@ -1,17 +1,15 @@
from .utils.util import get_config_data
from pathlib import Path
# from configs.config import USE_CONFIG_FILE
# 图片路径
IMAGE_PATH = Path("resources/img/")
# 音频路径
VOICE_PATH = Path("resources/voice/")
# 文本路径
TXT_PATH = Path("resources/txt/")
TEXT_PATH = Path("resources/txt/")
# 日志路径
LOG_PATH = Path("log/")
# 字体路径
TTF_PATH = Path("resources/ttf/")
FONT_PATH = Path("resources/ttf/")
# 数据路径
DATA_PATH = Path("data/")
# 临时图片路径
@@ -19,38 +17,20 @@ TEMP_PATH = Path("resources/img/temp/")
def init_path():
global IMAGE_PATH, VOICE_PATH, TXT_PATH, LOG_PATH, TTF_PATH, DATA_PATH, TEMP_PATH
# if USE_CONFIG_FILE:
# data = get_config_data()
# if data.get('IMAGE_PATH'):
# IMAGE_PATH = Path(data['IMAGE_PATH'])
# if data.get('VOICE_PATH'):
# VOICE_PATH = Path(data['VOICE_PATH'])
# if data.get('TXT_PATH'):
# TXT_PATH = Path(data['TXT_PATH'])
# if data.get('LOG_PATH'):
# LOG_PATH = Path(data['LOG_PATH'])
# if data.get('TTF_PATH'):
# TTF_PATH = Path(data['TTF_PATH'])
# if data.get('DATA_PATH'):
# DATA_PATH = Path(data['DATA_PATH'])
# if data.get('DRAW_PATH'):
# DRAW_PATH = Path(data['DRAW_PATH'])
# if data.get('TEMP_PATH'):
# TEMP_PATH = Path(data['TEMP_PATH'])
global IMAGE_PATH, VOICE_PATH, TEXT_PATH, LOG_PATH, FONT_PATH, DATA_PATH, TEMP_PATH
IMAGE_PATH.mkdir(parents=True, exist_ok=True)
VOICE_PATH.mkdir(parents=True, exist_ok=True)
TXT_PATH.mkdir(parents=True, exist_ok=True)
TEXT_PATH.mkdir(parents=True, exist_ok=True)
LOG_PATH.mkdir(parents=True, exist_ok=True)
TTF_PATH.mkdir(parents=True, exist_ok=True)
FONT_PATH.mkdir(parents=True, exist_ok=True)
DATA_PATH.mkdir(parents=True, exist_ok=True)
TEMP_PATH.mkdir(parents=True, exist_ok=True)
IMAGE_PATH = str(IMAGE_PATH.absolute()) + '/'
VOICE_PATH = str(VOICE_PATH.absolute()) + '/'
TXT_PATH = str(TXT_PATH.absolute()) + '/'
TEXT_PATH = str(TEXT_PATH.absolute()) + '/'
LOG_PATH = str(LOG_PATH.absolute()) + '/'
TTF_PATH = str(TTF_PATH.absolute()) + '/'
FONT_PATH = str(FONT_PATH.absolute()) + '/'
DATA_PATH = str(DATA_PATH.absolute()) + '/'
TEMP_PATH = str(TEMP_PATH.absolute()) + '/'
@@ -58,5 +38,4 @@ def init_path():
init_path()
if __name__ == '__main__':
print(IMAGE_PATH)
-176
View File
@@ -1,176 +0,0 @@
# import nonebot
from pathlib import Path
try:
import ujson as json
except ModuleNotFoundError:
import json
# driver: nonebot.Driver = nonebot.get_driver()
base_config = Path() / 'config.json'
plugins_cmd_config = Path() / 'configs' / 'plugins2cmd_config.json'
plugins_setting = Path() / 'configs' / 'plugins_setting.json'
def init_config():
if not base_config.exists():
base_config.parent.mkdir(parents=True, exist_ok=True)
config_dict = {
'apikey': {
'LOLICON_KEY': '',
'TL_KEY': [],
},
'sql': {
'bind': '',
'sql_name': '',
'user': '',
'password': '',
'address': '',
'port': '',
'database': '',
},
'path': {
'IMAGE_PATH': '',
'VOICE_PATH': '',
'TXT_PATH': '',
'LOG_PATH': '',
'DATA_PATH': '',
'DRAW_PATH': '',
'TEMP_PATH': '',
},
'proxy': {
'system_proxy': '',
'buff_proxy': ''
},
'level': {
'DELETE_IMG_LEVEL': 7,
'MOVE_IMG_LEVEL': 7,
'UPLOAD_LEVEL': 6,
'BAN_LEVEL': 5,
'OC_LEVEL': 2,
'MUTE_LEVEL': 5,
},
'auth': {
'ADMIN_DEFAULT_AUTH': 5,
'admin_plugins_auth': {
"admin_bot_manage": 2,
"ban": 5,
"delete_img": 7,
"move_img": 7,
"upload_img": 6,
"admin_help": 1,
"mute": 5
}
}
}
with open(base_config, 'w', encoding='utf8') as f:
json.dump(config_dict, f, indent=4, ensure_ascii=False)
if not plugins_cmd_config.exists():
plugins_cmd_config.parent.mkdir(parents=True, exist_ok=True)
config_dict = {
'base_config': {
'sign_in': ['签到'],
'send_img': ['发送图片', '萝莉', '美图', '壁纸'],
'send_setu': ['色图', '涩图', '瑟图', '查色图'],
'white2black': ['黑白图', '黑白草图'],
'coser': ['coser', 'cos'],
'quotations': ['语录'],
'jitang': ['鸡汤'],
'send_dinggong_voice': ['骂我', '骂老子', '骂劳资'],
'open_cases': ['开箱', '我的开箱', '群开箱统计', '我的金色'],
'luxun': ['鲁迅说过', '鲁迅说'],
'fake_msg': ['假消息'],
'buy': ['购买', '购买道具'],
'my_gold': ['我的金币'],
'my_props': ['我的道具'],
'shop_handle': ['商店'],
'nonebot_plugin_cocdicer': ['骰子娘'],
'update_pic': ['图片', '操作图片', '修改图片'],
'search_buff_skin_price': ['查询皮肤'],
'weather': ['天气', '查询天气', '天气查询'],
'yiqing': ['疫情', '疫情查询', '查询疫情'],
'what_anime': ['识番'],
'search_anime': ['搜番'],
'songpicker2': ['点歌'],
'epic': ['epic'],
'pixiv': ['pixiv', 'p站排行', '搜图'],
'poke': ['戳一戳'],
'draw_card': ['游戏抽卡', '原神一井', '原神来一井', '方舟一井', '方舟来一井'],
'ai': ['ai', 'Ai', 'AI', 'aI'],
'one_friend': ['我有一个朋友', '我有一个朋友想问问'],
'translate': ['翻译', '英翻', '翻英', '日翻', '翻日', '韩翻', '翻韩'],
'nonebot_plugin_picsearcher': ['识图'],
'almanac': ['原神黄历', '黄历'],
'material_remind': ['今日素材', '天赋材料'],
'qiu_qiu_translation': ['丘丘翻译', '丘丘一下', '丘丘语翻译'],
'query_resource_points': ['原神资源查询', '原神资源列表'],
}
}
with open(plugins_cmd_config, 'w', encoding='utf8') as f:
json.dump(config_dict, f, indent=4, ensure_ascii=False)
if not plugins_setting.exists():
plugins_setting.parent.mkdir(parents=True, exist_ok=True)
config_dict = {
'base': {
'IMAGE_DIR_LIST': ["色图", "美图", "萝莉", "壁纸"],
'BAN_RESULT': "才不会给你发消息.",
},
'draw_card': {
'PRTS_FLAG': True, # 明日方舟
'GENSHIN_FLAG': True, # 原神
'PRETTY_FLAG': True, # 赛马娘
'GUARDIAN_FLAG': True, # 坎公骑冠剑
'PCR_FLAG': True, # 公主连结
'AZUR_FLAG': True, # 碧蓝航线
'FGO_FLAG': True, # 命运-冠位指定(FGO)
'ONMYOJI_FLAG': True, # 阴阳师
'PCR_TAI': False # pcr是否开启台服卡池
},
'fudu': {
'FUDU_PROBABILITY': 0.7,
},
'reimu': {
'MAXINFO_REIMU': 7,
'COUNT_PER_DAY_REIMU': 5,
},
'bt': {
'MAXINFO_BT': 10,
},
'search_anime': {
'MAXINFO_PRIVATE_ANIME': 20,
'MAXINFO_GROUP_ANIME': 5,
},
'picsearcher': {
'MAX_FIND_IMG_COUNT': 3,
},
'sign': {
'MAX_SIGN_GOLD': 200,
},
'send_setu': {
'INITIAL_SETU_PROBABILITY': 0.7,
'MAX_SETU_R_COUNT': 5,
'DOWNLOAD_SETU': True,
},
'malicious_ban': {
'MALICIOUS_BAN_TIME': 30,
'MALICIOUS_BAN_COUNT': 8,
'MALICIOUS_CHECK_TIME': 5,
},
'open_case': {
'INITIAL_OPEN_CASE_COUNT': 20,
},
'mute': {
'MUTE_DEFAULT_COUNT': 10,
'MUTE_DEFAULT_TIME': 7,
'MUTE_DEFAULT_DURATION': 10,
},
'update_gocq': {
'UPDATE_GOCQ_GROUP': [],
},
}
with open(plugins_setting, 'w', encoding='utf8') as f:
json.dump(config_dict, f, indent=4, ensure_ascii=False)
-35
View File
@@ -1,35 +0,0 @@
from pathlib import Path
from configs.utils.init_config import init_config
try:
import ujson as json
except ModuleNotFoundError:
import json
data: dict = {}
def get_config_data():
global data
if not data:
try:
base_config = json.load(open(Path() / "config.json", 'r', encoding='utf8'))
plugins2cmd_config = json.load(open(Path() / 'configs' / 'plugins2cmd_config.json', 'r', encoding='utf8'))
other_config = json.load(open(Path() / 'configs' / 'other_config.json', 'r', encoding='utf8'))
for key in base_config.keys():
data.update(base_config[key])
for key in plugins2cmd_config.keys():
data.update(plugins2cmd_config[key])
for key in other_config.keys():
data.update(other_config[key])
except FileNotFoundError:
# logger.warning('配置文件不存在,生成默认配置....请填写数据库等必要数据后再次启动bot...')
init_config()
raise FileNotFoundError('配置文件不存在,生成默认配置....请填写数据库等必要数据后再次启动bot...')
except ValueError:
# logger.error('配置文件错误....')
raise ValueError('配置文件错误....')
return data
+14
View File
@@ -60,6 +60,20 @@ class BanUser(db.Model):
await cls.unban(user_qq)
return False
@classmethod
async def is_super_ban(cls, user_qq: int) -> bool:
"""
说明:
判断用户是否被ban
参数:
:param user_qq: qq号
"""
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
if not user:
return False
if user.ban_level == 10:
return True
@classmethod
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
"""
+249
View File
@@ -0,0 +1,249 @@
from services.log import logger
from services.db_context import db
from datetime import datetime
from typing import Optional, List
class BilibiliSub(db.Model):
__tablename__ = "bilibili_sub"
id = db.Column(db.Integer(), primary_key=True)
sub_id = db.Column(db.Integer(), nullable=False)
sub_type = db.Column(db.String(), nullable=False)
# 订阅用户
sub_users = db.Column(db.String(), nullable=False)
# 直播
live_short_id = db.Column(db.Integer())
live_status = db.Column(db.Integer)
# 主播/UP
uid = db.Column(db.BigInteger())
uname = db.Column(db.String())
latest_video_created = db.Column(db.BigInteger()) # 视频上传时间
dynamic_upload_time = db.Column(db.BigInteger(), default=0) # 动态发布时间
# 番剧
season_name = db.Column(db.String())
season_id = db.Column(db.Integer())
season_current_episode = db.Column(db.String())
season_update_time = db.Column(db.DateTime())
_idx1 = db.Index("bilibili_sub_idx1", "sub_id", "sub_type", unique=True)
@classmethod
async def add_bilibili_sub(
cls,
sub_id: int,
sub_type: str,
sub_user: str,
*,
live_short_id: Optional[int] = None,
live_status: Optional[int] = None,
dynamic_upload_time: Optional[int] = None,
uid: Optional[int] = None,
uname: Optional[str] = None,
latest_video_created: Optional[int] = None,
season_name: Optional[str] = None,
season_id: Optional[int] = None,
season_current_episode: Optional[str] = None,
season_update_time: Optional[datetime] = None,
) -> bool:
"""
说明:
添加订阅
参数:
:param sub_id: 订阅名称,房间号,番剧号等
:param sub_type: 订阅类型
:param sub_user: 订阅此条目的用户
:param live_short_id: 直接短 id
:param live_status: 主播开播状态
:param dynamic_upload_time: 主播/UP最新动态时间
:param uid: 主播/UP uid
:param uname: 用户名称
:param latest_video_created: 最新视频上传时间
:param season_name: 番剧名称
:param season_id: 番剧 season_id
:param season_current_episode: 番剧最新集数
:param season_update_time: 番剧更新时间
"""
try:
async with db.transaction():
query = (
await cls.query.where(cls.sub_id == sub_id)
.with_for_update()
.gino.first()
)
sub_user = sub_user if sub_user[-1] == "," else f"{sub_user},"
if query:
if sub_user not in query.sub_users:
sub_users = query.sub_users + sub_user
await query.update(sub_users=sub_users).apply()
else:
sub = await cls.create(
sub_id=sub_id, sub_type=sub_type, sub_users=sub_user
)
await sub.update(
live_short_id=live_short_id
if live_short_id
else sub.live_short_id,
live_status=live_status if live_status else sub.live_status,
dynamic_upload_time=dynamic_upload_time
if dynamic_upload_time
else sub.dynamic_upload_time,
uid=uid if uid else sub.uid,
uname=uname if uname else sub.uname,
latest_video_created=latest_video_created
if latest_video_created
else sub.latest_video_created,
season_update_time=season_update_time
if season_update_time
else sub.season_update_time,
season_current_episode=season_current_episode
if season_current_episode
else sub.season_current_episode,
season_id=season_id if season_id else sub.season_id,
season_name=season_name if season_name else sub.season_name,
).apply()
return True
except Exception as e:
logger.info(f"bilibili_sub 添加订阅错误 {type(e)}: {e}")
return False
@classmethod
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str) -> bool:
"""
说明:
删除订阅
参数:
:param sub_id: 订阅名称
:param sub_user: 删除此条目的用户
"""
try:
async with db.transaction():
query = (
await cls.query.where(
(cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user))
)
.with_for_update()
.gino.first()
)
if not query:
return False
await query.update(
sub_users=query.sub_users.replace(f"{sub_user},", "")
).apply()
if not query.sub_users.strip():
await query.delete()
return True
except Exception as e:
logger.info(f"bilibili_sub 删除订阅错误 {type(e)}: {e}")
return False
@classmethod
async def get_sub(cls, sub_id: int) -> Optional["BilibiliSub"]:
"""
说明:
获取订阅对象
参数:
:param sub_id: 订阅 id
"""
return await cls.query.where(cls.sub_id == sub_id).gino.first()
@classmethod
async def get_sub_data(cls, id_: str) -> List["BilibiliSub"]:
"""
获取 id_ 订阅的所有内容
:param id_: id
"""
query = cls.query.where(cls.sub_users.contains(id_))
return await query.gino.all()
@classmethod
async def update_sub_info(
cls,
sub_id: int,
*,
live_short_id: Optional[int] = None,
live_status: Optional[int] = None,
dynamic_upload_time: Optional[int] = None,
uid: Optional[int] = None,
uname: Optional[str] = None,
latest_video_created: Optional[int] = None,
season_name: Optional[str] = None,
season_id: Optional[int] = None,
season_current_episode: Optional[str] = None,
season_update_time: Optional[datetime] = None,
) -> bool:
"""
说明:
更新订阅信息
参数:
:param sub_id: 订阅名称,房间号,番剧号等
:param live_short_id: 直接短 id
:param live_status: 主播开播状态
:param dynamic_upload_time: 主播/UP最新动态时间
:param uid: 主播/UP uid
:param uname: 用户名称
:param latest_video_created: 最新视频上传时间
:param season_name: 番剧名称
:param season_id: 番剧 season_id
:param season_current_episode: 番剧最新集数
:param season_update_time: 番剧更新时间
"""
try:
async with db.transaction():
sub = (
await cls.query.where(cls.sub_id == sub_id)
.with_for_update()
.gino.first()
)
if sub:
await sub.update(
live_short_id=live_short_id
if live_short_id is not None
else sub.live_short_id,
live_status=live_status
if live_status is not None
else sub.live_status,
dynamic_upload_time=dynamic_upload_time
if dynamic_upload_time is not None
else sub.dynamic_upload_time,
uid=uid if uid is not None else sub.uid,
uname=uname if uname is not None else sub.uname,
latest_video_created=latest_video_created
if latest_video_created is not None
else sub.latest_video_created,
season_update_time=season_update_time
if season_update_time is not None
else sub.season_update_time,
season_current_episode=season_current_episode
if season_current_episode is not None
else sub.season_current_episode,
season_id=season_id if season_id is not None else sub.season_id,
season_name=season_name
if season_name is not None
else sub.season_name,
).apply()
return True
except Exception as e:
logger.info(f"bilibili_sub 更新订阅错误 {type(e)}: {e}")
return False
@classmethod
async def get_all_sub_data(
cls,
) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]":
"""
说明:
分类获取所有数据
"""
live_data = []
up_data = []
season_data = []
query = await cls.query.gino.all()
for x in query:
if x.sub_type == "live":
live_data.append(x)
if x.sub_type == "up":
up_data.append(x)
if x.sub_type == "season":
season_data.append(x)
return live_data, up_data, season_data
+35 -1
View File
@@ -1,7 +1,7 @@
from datetime import datetime
from services.db_context import db
from typing import List
from typing import List, Optional
class GroupInfoUser(db.Model):
@@ -13,6 +13,7 @@ class GroupInfoUser(db.Model):
belonging_group = db.Column(db.BigInteger(), nullable=False)
user_join_time = db.Column(db.DateTime(), nullable=False)
nickname = db.Column(db.Unicode())
uid = db.Column(db.BigInteger())
_idx1 = db.Index("info_group_users_idx1", "user_qq", "belonging_group", unique=True)
@@ -23,6 +24,7 @@ class GroupInfoUser(db.Model):
belonging_group: int,
user_name: str,
user_join_time: datetime,
uid: Optional[int] = None,
) -> bool:
"""
说明:
@@ -32,6 +34,7 @@ class GroupInfoUser(db.Model):
:param belonging_group: 群号
:param user_name: 用户名称
:param user_join_time: 入群时间
:param uid: 用户唯一 id(自动生成)
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
@@ -43,6 +46,7 @@ class GroupInfoUser(db.Model):
user_name=user_name,
belonging_group=belonging_group,
user_join_time=user_join_time,
uid=uid
)
return True
except Exception:
@@ -141,3 +145,33 @@ class GroupInfoUser(db.Model):
if user.nickname:
return user.nickname
return ""
@classmethod
async def get_group_member_uid(cls, user_qq: int, belonging_group: int) -> Optional[str]:
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
user = await query.gino.first()
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.belonging_group == 114514)).with_for_update()
_max_uid_user = await _max_uid.gino.first()
_max_uid = _max_uid_user.uid
if not user or not user.uid:
all_user = await cls.query.where(cls.user_qq == user_qq).gino.all()
for x in all_user:
if x.uid:
return x.uid
else:
if not user:
await GroupInfoUser.add_member_info(user_qq, belonging_group, '', datetime.min)
user = await cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
).gino.first()
await user.update(
uid=_max_uid + 1,
).apply()
await _max_uid_user.update(
uid=_max_uid + 1,
).apply()
return user.uid if user and user.uid else None
+1 -1
View File
@@ -102,4 +102,4 @@ class GroupRemind(db.Model):
).apply()
return True
except Exception as e:
return False
return False
+139
View File
@@ -0,0 +1,139 @@
from typing import Optional, List
from datetime import datetime
from services.db_context import db
class OmegaPixivIllusts(db.Model):
__tablename__ = "omega_pixiv_illusts"
id = db.Column(db.Integer(), primary_key=True)
pid = db.Column(db.BigInteger(), nullable=False)
uid = db.Column(db.BigInteger(), nullable=False)
title = db.Column(db.String(), nullable=False)
uname = db.Column(db.String(), nullable=False)
nsfw_tag = db.Column(db.Integer(), nullable=False)
width = db.Column(db.Integer(), nullable=False)
height = db.Column(db.Integer(), nullable=False)
tags = db.Column(db.String(), nullable=False)
url = db.Column(db.String(), nullable=False)
created_at = db.Column(db.DateTime(timezone=True))
updated_at = db.Column(db.DateTime(timezone=True))
_idx1 = db.Index("omega_pixiv_illusts_idx1", "pid", "url", unique=True)
@classmethod
async def add_image_data(
cls,
pid: int,
title: str,
width: int,
height: int,
url: str,
uid: int,
uname: str,
nsfw_tag: int,
tags: str,
created_at: datetime,
updated_at: datetime,
):
"""
说明:
添加图片信息
参数:
:param pid: pid
:param title: 标题
:param width: 宽度
:param height: 长度
:param url: url链接
:param uid: 作者uid
:param uname: 作者名称
:param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18
:param tags: 相关tag
:param created_at: 创建日期
:param updated_at: 更新日期
"""
if not await cls.check_exists(pid):
await cls.create(
pid=pid,
title=title,
width=width,
height=height,
url=url,
uid=uid,
uname=uname,
nsfw_tag=nsfw_tag,
tags=tags,
)
return True
return False
@classmethod
async def query_images(
cls,
keywords: Optional[List[str]] = None,
uid: Optional[int] = None,
pid: Optional[int] = None,
nsfw_tag: Optional[int] = 0,
num: int = 100
) -> List[Optional["OmegaPixivIllusts"]]:
"""
说明:
查找符合条件的图片
参数:
:param keywords: 关键词
:param uid: 画师uid
:param pid: 图片pid
:param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18
:param num: 获取图片数量
"""
if nsfw_tag is not None:
query = cls.query.where(cls.nsfw_tag == nsfw_tag)
else:
query = cls.query
if keywords:
for keyword in keywords:
query = query.where(cls.tags.contains(keyword))
elif uid:
query = query.where(cls.uid == uid)
elif pid:
query = query.where(cls.uid == pid)
query = query.order_by(db.func.random()).limit(num)
return await query.gino.all()
@classmethod
async def check_exists(cls, pid: int) -> bool:
"""
说明:
检测pid是否已存在
参数:
:param pid: 图片PID
"""
query = await cls.query.where(cls.pid == pid).gino.all()
return bool(query)
@classmethod
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int, int":
"""
说明:
获取相关关键词(keyword, tag)在图库中的数量
参数:
:param tags: 关键词/Tag
"""
setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count'))
query = cls.select('count')
if tags:
for tag in tags:
query = query.where(cls.tags.contains(tag))
count = await query.where(cls.nsfw_tag == 0).gino.first()
setu_count = await query.where(cls.nsfw_tag == 1).gino.first()
r18_count = await query.where(cls.nsfw_tag == 2).gino.first()
return count[0], setu_count[0], r18_count[0]
@classmethod
async def get_all_pid(cls) -> List[int]:
"""
说明:
获取所有图片PID
"""
data = await cls.select('pid').gino.all()
return [x[0] for x in data]
+42 -63
View File
@@ -1,6 +1,5 @@
from typing import Optional, List
from services.db_context import db
import asyncio
class Pixiv(db.Model):
@@ -24,18 +23,19 @@ class Pixiv(db.Model):
@classmethod
async def add_image_data(
cls,
pid: int,
title: str,
width: int,
height: int,
view: int,
bookmarks: int,
img_url: str,
img_p: str,
uid: int,
author: str,
tags: str,
cls,
pid: int,
title: str,
width: int,
height: int,
view: int,
bookmarks: int,
img_url: str,
img_p: str,
uid: int,
author: str,
tags: str,
nws
):
"""
说明:
@@ -65,7 +65,7 @@ class Pixiv(db.Model):
img_p=img_p,
uid=uid,
author=author,
is_r18=True if 'R-18' in tags else False,
is_r18=True if "R-18" in tags else False,
tags=tags,
)
return True
@@ -97,44 +97,45 @@ class Pixiv(db.Model):
说明:
获取所有PID
"""
pid = []
query = await cls.query.gino.all()
for image in query:
if image.pid not in pid:
pid.append(image.pid)
return pid
query = await cls.query.select("pid").gino.first()
pid = [x[0] for x in query]
return list(set(pid))
# 0:非r18 1:r18 2:混合
@classmethod
async def query_images(
cls,
keyword: Optional[List[str]] = None,
keywords: Optional[List[str]] = None,
uid: Optional[int] = None,
pid: Optional[int] = None,
r18: int = 0,
r18: Optional[int] = 0,
num: int = 100
) -> List[Optional["Pixiv"]]:
"""
说明:
查找符合条件的图片
参数:
:param keyword: 关键词
:param keywords: 关键词
:param uid: 画师uid
:param pid: 图片pid
:param r18: 是否r18,0:非r18 1:r18 2:混合
:param num: 查找图片的数量
"""
if r18 == 0:
query = await cls.query.where(cls.is_r18 == False).gino.all()
query = cls.query.where(cls.is_r18 == False)
elif r18 == 1:
query = await cls.query.where(cls.is_r18 == True).gino.all()
query = cls.query.where(cls.is_r18 == True)
else:
query = await cls.query.gino.all()
if keyword:
query = [x for x in query if set(x.tags.split(',')) > set(keyword)]
query = cls.query
if keywords:
for keyword in keywords:
query = query.where(cls.tags.contains(keyword))
elif uid:
query = [x for x in query if x.uid == uid]
query = query.where(cls.uid == uid)
elif pid:
query = [x for x in query if x.pid == pid]
return query
query = query.where(cls.uid == pid)
query = query.order_by(db.func.random()).limit(num)
return await query.gino.all()
@classmethod
async def check_exists(cls, pid: int, img_p: str) -> bool:
@@ -151,41 +152,19 @@ class Pixiv(db.Model):
return bool(query)
@classmethod
async def get_keyword_num(cls, keyword: List[str]) -> "int, int":
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int":
"""
说明:
获取相关关键词(keyword, tag)在图库中的数量
参数:
:param keyword: 关键词/Tag
:param tags: 关键词/Tag
"""
query = await cls.query.gino.all()
i = int(len(query) / 200)
mod = len(query) % 200
tasks = []
start = 0
end = 200
count = 0
r18_count = 0
for _ in range(i):
tasks.append(asyncio.ensure_future(split_query_list(query[start: end], keyword)))
start += 200
end += 200
if mod:
tasks.append(asyncio.ensure_future(split_query_list(query[end:], keyword)))
result = await asyncio.gather(*tasks)
for x, j in result:
count += x
r18_count += j
# query = [x for x in query if set(x.tags.split(',')) > set(keyword)]
# r18_count = len([x for x in query if x.is_r18])
return count, r18_count
setattr(Pixiv, 'count', db.func.count(cls.pid).label('count'))
query = cls.select('count')
if tags:
for tag in tags:
query = query.where(cls.tags.contains(tag))
count = await query.where(cls.is_r18 == False).gino.first()
r18_count = await query.where(cls.is_r18 == True).gino.first()
return count[0], r18_count[0]
async def split_query_list(query: List['Pixiv'], keyword: List[str]) -> 'int, int':
return await asyncio.get_event_loop().run_in_executor(None, _split_query_list, query, keyword)
def _split_query_list(query: List['Pixiv'], keyword: List[str]) -> 'int, int':
query = [x for x in query if set(x.tags.split(',')) > set(keyword)]
r18_count = len([x for x in query if x.is_r18])
return len(query) - r18_count, r18_count
+20
View File
@@ -12,6 +12,10 @@ class RussianUser(db.Model):
fail_count = db.Column(db.Integer(), default=0)
make_money = db.Column(db.Integer(), default=0)
lose_money = db.Column(db.Integer(), default=0)
winning_streak = db.Column(db.Integer(), default=0)
losing_streak = db.Column(db.Integer(), default=0)
max_winning_streak = db.Column(db.Integer(), default=0)
max_losing_streak = db.Column(db.Integer(), default=0)
_idx1 = db.Index("russian_group_users_idx1", "user_qq", "group_id", unique=True)
@@ -52,12 +56,28 @@ class RussianUser(db.Model):
if not user:
user = await cls.create(user_qq=user_qq, group_id=group_id)
if itype == "win":
_max = (
user.max_winning_streak
if user.max_winning_streak > user.winning_streak + 1
else user.winning_streak + 1
)
await user.update(
win_count=user.win_count + 1,
winning_streak=user.winning_streak + 1,
losing_streak=0,
max_winning_streak=_max
).apply()
elif itype == "lose":
_max = (
user.max_losing_streak
if user.max_losing_streak > user.losing_streak + 1
else user.losing_streak + 1
)
await user.update(
fail_count=user.fail_count + 1,
losing_streak=user.losing_streak + 1,
winning_streak=0,
max_losing_streak=_max,
).apply()
return True
except Exception:
+15 -8
View File
@@ -57,6 +57,7 @@ class Setu(db.Model):
local_id: Optional[int] = None,
tags: Optional[List[str]] = None,
r18: int = 0,
limit: int = 50,
):
"""
说明:
@@ -65,6 +66,7 @@ class Setu(db.Model):
:param local_id: 本地色图 id
:param tags: tags
:param r18: 是否 r18,0:非r18 1:r18 2:混合
:param limit: 获取数量
"""
if local_id:
flag = True if r18 == 1 else False
@@ -72,23 +74,27 @@ class Setu(db.Model):
(cls.local_id == local_id) & (cls.is_r18 == flag)
).gino.first()
if r18 == 0:
query = await cls.query.where(cls.is_r18 == False).gino.all()
query = cls.query.where(cls.is_r18 == False)
elif r18 == 1:
query = await cls.query.where(cls.is_r18 == True).gino.all()
query = cls.query.where(cls.is_r18 == True)
else:
query = await cls.query.gino.all()
query = cls.query
if tags:
query = [x for x in query if set(x.tags.split(",")) > set(tags)]
return query
for tag in tags:
query = query.where(cls.tags.contains(tag) | cls.title.contains(tag) | cls.author.contains(tag))
query = query.order_by(db.func.random()).limit(limit)
return await query.gino.all()
@classmethod
async def get_image_count(cls, r18: int = 0):
async def get_image_count(cls, r18: int = 0) -> int:
"""
说明:
查询图片数量
"""
return len(await cls.query_image(r18=r18))
# return await db.func.count(cls.local_id).gino.scalar()
flag = False if r18 == 0 else True
setattr(Setu, 'count', db.func.count(cls.local_id).label('count'))
count = await cls.select('count').where(cls.is_r18 == flag).gino.first()
return count[0]
@classmethod
async def get_image_in_hash(cls, img_hash: str) -> "Setu":
@@ -166,3 +172,4 @@ class Setu(db.Model):
获取所有图片对象
"""
return await cls.query.gino.all()
@@ -41,7 +41,17 @@ class SignGroupUser(db.Model):
)
@classmethod
async def get_all_impression(cls, belonging_group: int) -> "list, list":
async def sign(cls, user: "SignGroupUser", impression: float, checkin_time_last: datetime):
await user.update(
checkin_count=user.checkin_count + 1,
checkin_time_last=checkin_time_last,
impression=user.impression + impression,
add_probability=0,
specify_probability=0,
).apply()
@classmethod
async def get_all_impression(cls, belonging_group: int) -> "list, list, list":
"""
说明:
获取该群所有用户 id 及对应 好感度
+6 -4
View File
@@ -12,22 +12,24 @@ from utils.utils import FreqLimiter
from configs.config import NICKNAME
__plugin_name__ = "基本设置 [Hidden]"
__zx_plugin_name__ = "基本设置 [Hidden]"
__plugin_usage__ = "用法: 无"
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
_flmt = FreqLimiter(300)
config_playgame = on_keyword({"打游戏"}, permission=GROUP, priority=1, block=True)
config_play_game = on_keyword({"打游戏"}, permission=GROUP, priority=1, block=True)
@config_playgame.handle()
@config_play_game.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if not _flmt.check(event.group_id):
return
_flmt.start_cd(event.group_id)
await config_playgame.finish(
await config_play_game.finish(
image(random.choice(os.listdir(IMAGE_PATH + "dayouxi/")), "dayouxi")
)
+3
View File
@@ -0,0 +1,3 @@
import nonebot
nonebot.load_plugins("plugins/admin_bot_manage")
@@ -4,16 +4,26 @@ from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from .data_source import custom_group_welcome
from nonebot.adapters.cqhttp.permission import GROUP
from configs.config import OC_LEVEL
from services.log import logger
__plugin_name__ = "自定义进群欢迎消息"
__zx_plugin_name__ = "自定义进群欢迎消息 [Admin]"
__plugin_usage__ = """
自定义进群欢迎消息 [消息] [图片](可省略)
示例:自定义进群欢迎消息 欢迎新人![图片]
"""
usage:
指令:
自定义进群欢迎消息 ?[文本] ?[图片]
示例:自定义进群欢迎消息 欢迎新人![图片]
Note:可以通过[at]来确认是否艾特新成员
示例:自定义进群欢迎消息 欢迎你[at]
""".strip()
__plugin_des__ = '简易的自定义群欢迎消息'
__plugin_cmd__ = ['自定义群欢迎消息 ?[文本] ?[图片]']
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"admin_level": OC_LEVEL,
}
custom_welcome = on_command(
"自定义进群欢迎消息",
@@ -26,12 +36,16 @@ custom_welcome = on_command(
@custom_welcome.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg = get_message_text(event.json())
imgs = get_message_imgs(event.json())
if not msg and not imgs:
await custom_welcome.finish(__plugin_usage__)
await custom_welcome.send(
await custom_group_welcome(msg, imgs, event.user_id, event.group_id),
at_sender=True,
)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}")
try:
msg = get_message_text(event.json())
imgs = get_message_imgs(event.json())
if not msg and not imgs:
await custom_welcome.finish(__plugin_usage__)
await custom_welcome.send(
await custom_group_welcome(msg, imgs, event.user_id, event.group_id),
at_sender=True,
)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}")
except Exception as e:
logger.error(f"自定义进群欢迎消息发生错误 {type(e)}:{e}")
await custom_welcome.send("发生了一些未知错误...")
+110 -106
View File
@@ -1,22 +1,22 @@
from models.group_remind import GroupRemind
from typing import List
from nonebot.adapters.cqhttp.message import MessageSegment
from services.log import logger
from configs.path_config import DATA_PATH
import os
import aiofiles
import aiohttp
from utils.message_builder import image
from utils.utils import get_local_proxy, get_bot
from pathlib import Path
from configs.config import plugins2info_dict
from models.group_member_info import GroupInfoUser
import time
from datetime import datetime
from services.db_context import db
from models.level_user import LevelUser
from configs.config import ADMIN_DEFAULT_AUTH
from utils.static_data import group_manager
from utils.manager import group_manager, plugins2settings_manager
from utils.image_utils import CreateImg
import aiofiles
import aiohttp
import asyncio
import time
import os
try:
import ujson as json
@@ -24,70 +24,16 @@ except ModuleNotFoundError:
import json
command_dict = {
"早晚安": "zwa",
"进群欢迎": "hy",
"每日开箱重置提醒": "kxcz",
"b站转发解析": "blpar",
"epic": "epic",
"丢人爬": "pa",
"原神黄历提醒": "almanac",
}
command_list = list(command_dict.values())
command_info_dt = {
"早晚安": "将会在每晚11:59晚安,在6:01早安哦",
"每日开箱重置提醒": "将会在每日00:01提示开箱重置!",
"epic": "将会在每日中午12:01发送可白嫖的epic游戏",
"原神黄历提醒": "将会在每日8:00发送当日的原神黄历",
}
async def remind_status(group: int, name: str, flag: bool) -> str:
_name = ""
if name in command_dict.values():
_name = list(command_dict.keys())[list(command_dict.values()).index(name)]
if flag:
rst = "开启"
if await GroupRemind.get_status(group, name):
return f"该群已经{rst}过 {_name},请勿重复开启!"
else:
rst = "关闭"
if not await GroupRemind.get_status(group, name):
return f"该群已经{rst}过 {_name},请勿重复关闭!"
if await GroupRemind.set_status(group, name, flag):
info = command_info_dt[_name] if command_info_dt.get(_name) else ""
if info:
info = "\n" + info
return f"成功{rst} {_name}!0v0 {info}"
else:
return f"{rst} {_name} 失败了..."
async def set_group_status(name: str, group_id: int):
flag = None
if name[:2] == "开启":
flag = True
elif name[:2] == "关闭":
flag = False
cmd = name[2:]
if cmd in ["全部通知", "所有通知"]:
for command in command_list:
await remind_status(group_id, command, flag)
return f"已{name[:2]}所有通知!"
return await remind_status(group_id, command_dict[cmd], flag)
async def group_current_status(group_id: int):
result = (
f'(被动技能)\n早晚安通知:{"√" if await GroupRemind.get_status(group_id, "zwa") else "×"}\n'
f'进群欢迎:{"√" if await GroupRemind.get_status(group_id, "hy") else "×"}\n'
f'每日开箱重置通知:{"√" if await GroupRemind.get_status(group_id, "kxcz") else "×"}\n'
f'b站转发解析:{"√" if await GroupRemind.get_status(group_id, "blpar") else "×"}\n'
f'丢人爬:{"√" if await GroupRemind.get_status(group_id, "pa") else "×"}\n'
f'epic免费游戏:{"√" if await GroupRemind.get_status(group_id, "epic") else "×"}\n'
f'原神黄历提醒:{"√" if await GroupRemind.get_status(group_id, "almanac") else "×"}'
)
return result
async def group_current_status(group_id: int) -> str:
"""
获取当前所有通知的开关
:param group_id: 群号
"""
rst = "[被动技能 状态]\n"
_data = group_manager.get_task_data()
for task in _data.keys():
rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n'
return rst.strip()
custom_welcome_msg_json = (
@@ -95,13 +41,21 @@ custom_welcome_msg_json = (
)
async def custom_group_welcome(msg, imgs, user_id, group_id):
async def custom_group_welcome(
msg: str, imgs: List[str], user_id: int, group_id: int
) -> str:
"""
替换群欢迎消息
:param msg: 欢迎消息文本
:param imgs: 欢迎消息图片,只取第一张
:param user_id: 用户id,用于log记录
:param group_id: 群号
"""
img_result = ""
img = imgs[0] if imgs else ""
result = ""
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"):
os.remove(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
# print(custom_welcome_msg_json)
if not custom_welcome_msg_json.exists():
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
data = {}
@@ -133,54 +87,99 @@ async def custom_group_welcome(msg, imgs, user_id, group_id):
return f"替换群欢迎消息成功:\n{result}" + img_result
def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
task_data = None
async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
global task_data
"""
修改群功能状态
:param cmd: 功能名称
:param group_id: 群号
:param is_super: 是否位超级用户,超级用户用于私聊开关功能状态
"""
if not task_data:
task_data = group_manager.get_task_data()
group_help_file = Path(DATA_PATH) / "group_help" / f"{group_id}.png"
group_id = str(group_id)
status = cmd[:2]
cmd = cmd[2:]
for plugin_cmd in plugins2info_dict.keys():
if cmd in plugins2info_dict[plugin_cmd]["cmd"]:
if is_super:
plugin_cmd = f'{plugin_cmd}:super'
type_ = 'plugin'
modules = plugins2settings_manager.get_plugin_module(cmd, True)
if cmd == '全部被动':
for task in task_data:
if status == "开启":
if group_manager.get_plugin_status(plugin_cmd, group_id):
return f"功能 {cmd} 正处于开启状态!不要重复开启."
group_manager.unblock_plugin(plugin_cmd, group_id)
if not await group_manager.check_group_task_status(group_id, task):
await group_manager.open_group_task(group_id, task)
else:
if not group_manager.get_plugin_status(plugin_cmd, group_id):
if await group_manager.check_group_task_status(group_id, task):
await group_manager.close_group_task(group_id, task)
return f"已 {status} 全部被动技能!"
if cmd in [task_data[x] for x in task_data.keys()]:
type_ = 'task'
modules = [x for x in task_data.keys() if task_data[x] == cmd]
for module in modules:
if is_super:
module = f"{module}:super"
if status == "开启":
if type_ == 'task':
if await group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
await group_manager.open_group_task(group_id, module)
else:
if group_manager.get_plugin_status(module, group_id):
return f"功能 {cmd} 正处于开启状态!不要重复开启."
group_manager.unblock_plugin(module, group_id)
else:
if type_ == 'task':
if not await group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
await group_manager.close_group_task(group_id, module)
else:
if not group_manager.get_plugin_status(module, group_id):
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
group_manager.block_plugin(plugin_cmd, group_id)
if group_help_file.exists():
group_help_file.unlink()
return f"{status} {cmd} 功能!"
return f"没有找到 {cmd} 功能..."
group_manager.block_plugin(module, group_id)
if group_help_file.exists():
group_help_file.unlink()
return f"{status} {cmd} 功能!"
def set_plugin_status(cmd: str, block_type: str = "all"):
"""
设置插件功能状态(超级用户使用)
:param cmd: 功能名称
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
"""
status = cmd[:2]
cmd = cmd[2:]
for plugin_cmd in plugins2info_dict.keys():
if cmd in plugins2info_dict[plugin_cmd]["cmd"]:
if status == "开启":
group_manager.unblock_plugin(plugin_cmd)
else:
group_manager.block_plugin(plugin_cmd, block_type=block_type)
break
module = plugins2settings_manager.get_plugin_module(cmd)
if status == "开启":
group_manager.unblock_plugin(module)
else:
group_manager.block_plugin(module, block_type=block_type)
async def get_plugin_status():
"""
获取功能状态
"""
return await asyncio.get_event_loop().run_in_executor(None, _get_plugin_status)
def _get_plugin_status():
rst = '\t功能\n'
flag_str = '状态'.rjust(4) + '\n'
for plugin_cmd in plugins2info_dict:
flag = group_manager.get_plugin_block_type(plugin_cmd)
flag = flag.upper() + ' CLOSE' if flag else 'OPEN'
rst += f'{plugins2info_dict[plugin_cmd]["cmd"][0]}\n'
flag_str += f'{flag}\n'
height = len(rst.split('\n')) * 24
def _get_plugin_status() -> MessageSegment:
"""
合成功能状态图片
"""
rst = "\t功能\n"
flag_str = "状态".rjust(4) + "\n"
for module in plugins2settings_manager.get_data():
flag = group_manager.get_plugin_block_type(module)
flag = flag.upper() + " CLOSE" if flag else "OPEN"
try:
rst += f'{plugins2settings_manager.get(module)["cmd"][0]}\n'
except IndexError:
rst += f"{module}\n"
flag_str += f"{flag}\n"
height = len(rst.split("\n")) * 24
a = CreateImg(150, height, font_size=20)
a.text((10, 10), rst)
b = CreateImg(200, height, font_size=20)
@@ -191,7 +190,12 @@ def _get_plugin_status():
return image(b64=A.pic2bs4())
async def update_member_info(group_id: int) -> bool:
async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool:
"""
更新群成员信息
:param group_id: 群号
:param remind_superuser: 失败信息提醒超级用户
"""
bot = get_bot()
_group_user_list = await bot.get_group_member_list(group_id=group_id)
_error_member_list = []
@@ -259,7 +263,7 @@ async def update_member_info(group_id: int) -> bool:
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
else:
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
if _error_member_list:
if _error_member_list and remind_superuser:
result = ""
for error_user in _error_member_list:
result += error_user
@@ -1,57 +0,0 @@
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from .data_source import set_group_status, group_current_status
from nonebot.adapters.cqhttp.permission import GROUP
from services.log import logger
from nonebot import on_command
__plugin_name__ = "群通知开关"
__plugin_usage__ = """
示例:
开启早晚安
关闭早晚安
"""
group_status = on_command(
"oc_reminds",
aliases={
"开启早晚安",
"关闭早晚安",
"开启进群欢迎",
"关闭进群欢迎",
"开启每日开箱重置提醒",
"关闭每日开箱重置提醒",
"开启b站转发解析",
"关闭b站转发解析",
"开启epic通知",
"关闭epic通知",
"开启丢人爬",
"关闭丢人爬",
"开启原神黄历提醒",
"关闭原神黄历提醒",
"开启全部通知",
"开启所有通知",
"关闭全部通知",
"关闭所有通知",
"群通知状态",
},
permission=GROUP,
priority=5,
block=True,
)
@group_status.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if state["_prefix"]["raw_command"] in ["群通知状态"]:
await group_status.finish(await group_current_status(event.group_id))
await group_status.send(
await set_group_status(state["_prefix"]["raw_command"], event.group_id),
at_sender=True,
)
logger.info(
f'USER {event.user_id} GROUP {event.group_id} 使用群通知管理命令 {state["_prefix"]["raw_command"]}'
)
+42
View File
@@ -0,0 +1,42 @@
from nonebot.adapters.cqhttp import Bot, Event
from nonebot.typing import T_State
from utils.manager import group_manager, plugins2settings_manager
from utils.utils import get_message_text
from services.log import logger
cmd = []
def switch_rule(bot: Bot, event: Event, state: T_State) -> bool:
"""
检测文本是否是关闭功能命令
:param bot: pass
:param event: pass
:param state: pass
"""
try:
if not cmd:
cmd.append('关闭全部被动')
cmd.append('开启全部被动')
_data = group_manager.get_task_data()
for key in _data:
cmd.append(f"开启{_data[key]}")
cmd.append(f"关闭{_data[key]}")
cmd.append(f"开启 {_data[key]}")
cmd.append(f"关闭 {_data[key]}")
_data = plugins2settings_manager.get_data()
for key in _data:
try:
for x in _data[key]["cmd"]:
cmd.append(f"开启{x}")
cmd.append(f"关闭{x}")
cmd.append(f"开启 {x}")
cmd.append(f"关闭 {x}")
except KeyError:
pass
msg = get_message_text(event.json()).split()
msg = msg[0] if msg else ""
return msg in cmd
except Exception as e:
logger.error(f"检测是否为功能开关命令发生错误 {type(e)}: {e}")
return False
+82 -53
View File
@@ -1,77 +1,106 @@
from nonebot import on_command
from nonebot import on_command, on_message
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
from .data_source import change_group_switch, set_plugin_status, get_plugin_status
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP
from .data_source import (
change_group_switch,
set_plugin_status,
get_plugin_status,
group_current_status,
)
from services.log import logger
from configs.config import plugins2info_dict, NICKNAME
from configs.config import NICKNAME, OC_LEVEL
from utils.utils import get_message_text, is_number
from nonebot.permission import SUPERUSER
from .rule import switch_rule
__plugin_name__ = "群功能开关"
__zx_plugin_name__ = "群功能开关 [Admin]"
__plugin_usage__ = """
示例:
开启色图
关闭色图
"""
usage:
群内功能与被动技能开关
指令:
开启/关闭[功能]
群被动状态
开启全部被动
关闭全部被动
示例:开启/关闭色图
""".strip()
__plugin_superuser_usage__ = """
usage:
功能总开关与指定群禁用
指令:
功能状态
开启/关闭[功能] [group]
开启/关闭[功能] ['private'/'group']
""".strip()
__plugin_des__ = "群内功能开关"
__plugin_cmd__ = [
"开启/关闭[功能]",
"群被动状态",
"开启全部被动",
"关闭全部被动",
"功能状态 [_superuser]",
"开启/关闭[功能] [group] [_superuser]",
"开启/关闭[功能] ['private'/'group'] [_superuser]",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"admin_level": OC_LEVEL,
}
switch_rule_matcher = on_message(rule=switch_rule, priority=4, block=True)
plugins_status = on_command("功能状态", permission=SUPERUSER, priority=5, block=True)
group_task_status = on_command("群被动状态", permission=GROUP, priority=5, block=True)
cmds = []
for cmd_list in plugins2info_dict.values():
for cmd in cmd_list["cmd"]:
cmds.append(f"开启{cmd}")
cmds.append(f"关闭{cmd}")
cmds = set(cmds)
switch_rule = on_command(
"switch_rule", aliases=cmds, priority=5, block=True
)
plugins_status = on_command('功能状态', permission=SUPERUSER, priority=5, block=True)
@switch_rule.handle()
@switch_rule_matcher.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
_cmd = get_message_text(event.json()).split()[0]
if isinstance(event, GroupMessageEvent):
await switch_rule.send(
change_group_switch(
state["_prefix"]["raw_command"].strip(), event.group_id
)
)
logger.info(
f'USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {state["_prefix"]["raw_command"]}'
)
await switch_rule_matcher.send(await change_group_switch(_cmd, event.group_id))
logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {_cmd}")
else:
if str(event.user_id) in bot.config.superusers:
block_type = get_message_text(event.json())
_cmd = state["_prefix"]["raw_command"].strip()
block_type = " ".join(get_message_text(event.json()).split()[1:])
block_type = block_type if block_type else "a"
if is_number(block_type):
if not int(block_type) in [g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id))]:
await switch_rule.finish(f'{NICKNAME}未加入群聊:{block_type}')
change_group_switch(_cmd, int(block_type), True)
group_name = (await bot.get_group_info(group_id=int(block_type)))['group_name']
await switch_rule.send(f'已禁用群聊 {group_name}({block_type}) 的 {_cmd[2:]} 功能')
elif block_type in ['all', 'private', 'group', 'a', 'p', 'g']:
block_type = 'all' if block_type == 'a' else block_type
block_type = 'private' if block_type == 'p' else block_type
block_type = 'group' if block_type == 'g' else block_type
if not int(block_type) in [
g["group_id"]
for g in await bot.get_group_list(self_id=int(bot.self_id))
]:
await switch_rule_matcher.finish(f"{NICKNAME}未加入群聊:{block_type}")
await change_group_switch(_cmd, int(block_type), True)
group_name = (await bot.get_group_info(group_id=int(block_type)))[
"group_name"
]
await switch_rule_matcher.send(
f"已禁用群聊 {group_name}({block_type}) 的 {_cmd[2:]} 功能"
)
elif block_type in ["all", "private", "group", "a", "p", "g"]:
block_type = "all" if block_type == "a" else block_type
block_type = "private" if block_type == "p" else block_type
block_type = "group" if block_type == "g" else block_type
set_plugin_status(_cmd, block_type)
if block_type == 'all':
await switch_rule.send(f'已{_cmd[:2]}功能:{_cmd[2:]}')
elif block_type == 'private':
await switch_rule.send(f'已在私聊中{_cmd[:2]}功能:{_cmd[2:]}')
if block_type == "all":
await switch_rule_matcher.send(f"已{_cmd[:2]}功能:{_cmd[2:]}")
elif block_type == "private":
await switch_rule_matcher.send(f"已在私聊中{_cmd[:2]}功能:{_cmd[2:]}")
else:
await switch_rule.send(f'已在群聊中{_cmd[:2]}功能:{_cmd[2:]}')
await switch_rule_matcher.send(f"已在群聊中{_cmd[:2]}功能:{_cmd[2:]}")
else:
await switch_rule.finish('格式错误:关闭[功能] [group]/[p/g]')
logger.info(
f'USER {event.user_id} 使用功能管理命令 {state["_prefix"]["raw_command"]} | {block_type}'
)
await switch_rule_matcher.finish("格式错误:关闭[功能] [group]/[p/g]")
logger.info(f"USER {event.user_id} 使用功能管理命令 {_cmd} | {block_type}")
@plugins_status.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await plugins_status.send(await get_plugin_status())
@group_task_status.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await group_task_status.send(await group_current_status(event.group_id))
+24 -15
View File
@@ -5,6 +5,13 @@ from models.group_info import GroupInfo
from asyncpg.exceptions import ConnectionDoesNotExistError
__zx_plugin_name__ = '管理方面定时任务 [Hidden]'
__plugin_usage__ = '无'
__plugin_des__ = '成员信息和管理权限的定时更新'
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
# 自动更新群员信息
@scheduler.scheduled_job(
"cron",
@@ -13,14 +20,15 @@ from asyncpg.exceptions import ConnectionDoesNotExistError
)
async def _():
bot = get_bot()
gl = await bot.get_group_list(self_id=bot.self_id)
gl = [g["group_id"] for g in gl]
for g in gl:
try:
await update_member_info(g)
logger.info(f"更新群组 g:{g} 成功")
except Exception as e:
logger.error(f"更新群组错误 g:{g} e:{e}")
if bot:
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
try:
await update_member_info(g)
logger.info(f"更新群组 g:{g} 成功")
except Exception as e:
logger.error(f"更新群组错误 g:{g} e:{e}")
# 快速更新群员信息以及管理员权限
@@ -31,12 +39,13 @@ async def _():
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list(self_id=bot.self_id)
gl = [g["group_id"] for g in gl]
all_group = [x.group_id for x in await GroupInfo.get_all_group()]
for g in gl:
if g not in all_group:
await update_member_info(g)
logger.info(f"快速更新群信息以及权限:{g}")
if bot:
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
all_group = [x.group_id for x in await GroupInfo.get_all_group()]
for g in gl:
if g not in all_group:
await update_member_info(g, False)
logger.info(f"快速更新群信息以及权限:{g}")
except (IndexError, ConnectionDoesNotExistError):
pass
@@ -1,19 +1,23 @@
from nonebot import on_command, export
from nonebot import on_command, on_notice
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, GROUP
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
from .data_source import update_member_info
__plugin_name__ = "更新群组成员列表"
__zx_plugin_name__ = "更新群组成员列表 [Admin]"
__plugin_usage__ = """
说明:
更新群组成员的基本信息
示例:
更新群组成员列表
"""
usage:
更新群组成员的基本信息
指令:
更新群组成员列表/更新群组成员信息
""".strip()
__plugin_des__ = '更新群组成员列表'
__plugin_cmd__ = ['更新群组成员列表']
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"admin_level": 1,
}
export = export()
export.update_member_info = update_member_info
refresh_member_group = on_command(
"更新群组成员列表", aliases={"更新群组成员信息"}, permission=GROUP, priority=5, block=True
@@ -26,3 +30,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await refresh_member_group.finish("更新群员信息成功!", at_sender=True)
else:
await refresh_member_group.finish("更新群员信息失败!", at_sender=True)
group_increase_handle = on_notice(priority=1, block=False)
@group_increase_handle.handle()
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
if event.user_id == int(bot.self_id):
await update_member_info(event.group_id)
+3 -3
View File
@@ -7,9 +7,9 @@ from models.group_member_info import GroupInfoUser
from configs.config import ADMIN_DEFAULT_AUTH
__plugin_name__ = "群管理员监测"
__plugin_usage__ = "无"
__zx_plugin_name__ = "群管理员变动监测 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
admin_notice = on_notice(priority=5)
+12 -35
View File
@@ -2,49 +2,26 @@ from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters import Bot
from nonebot.adapters.cqhttp import GroupMessageEvent
from utils.image_utils import CreateImg
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from configs.config import NICKNAME
from .data_source import create_help_image, admin_help_image
__plugin_name__ = '管理帮助 [Hidden]'
__plugin_usage__ = f'''管理帮助(权限等级):
1.更新群组成员列表(1)
2.功能开关 --> 指令:开启/关闭xx功能(2)
3.查看群被动技能 --> 指令:群通知状态(2)
4.自定义群欢迎 --> 指令:自定义进群欢迎消息(2)
5.将用户拉入{NICKNAME}黑名单 --> .ban/.unban(5)
6.刷屏禁言相关 --> 指令:刷屏检测设置/设置检测时间
\t\t/设置检测次数/设置禁言时长(5)
8.上传图片/连续上传图片(6)
9.移动图片(7)
10.删除图片(7)
对我说 “{NICKNAME}帮助 指令” 获取对应详细帮助
群主与管理员默认 5 级权限
'''
passive_help = '''【被动技能开关(2):
开启/关闭早晚安
开启/关闭进群欢迎
开启/关闭每日开箱重置提醒
开启/关闭b站转发解析
开启/关闭丢人爬
开启/关闭epic通知
开启/关闭原神黄历提醒
开启/关闭全部通知】
'''
__zx_plugin_name__ = '管理帮助 [Admin]'
__plugin_usage__ = '管理员帮助,在群内回复“管理员帮助”'
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"admin_level": 1,
}
admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True)
admin_help_img = CreateImg(1000, 600, font_size=24)
admin_help_img.text((10, 10), __plugin_usage__)
text_img = CreateImg(450, 600, font_size=24)
text_img.text((0, 0), passive_help)
admin_help_img.paste(text_img, (650, 50))
admin_help_img.save(IMAGE_PATH + 'admin_help_img.png')
if admin_help_image.exists():
admin_help_image.unlink()
@admin_help.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if not admin_help_image.exists():
await create_help_image()
await admin_help.send(image('admin_help_img.png'))
+91
View File
@@ -0,0 +1,91 @@
from utils.image_utils import CreateImg
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.utils import get_matchers
from utils.manager import group_manager
from nonebot.adapters.cqhttp import Bot
from pathlib import Path
from nonebot import Driver
import asyncio
import nonebot
driver: Driver = nonebot.get_driver()
background = Path(IMAGE_PATH) / "background" / "0.png"
admin_help_image = Path(IMAGE_PATH) / 'admin_help_img.png'
@driver.on_bot_connect
async def create_help_image(bot: Bot = None):
"""
创建管理员帮助图片
"""
if not group_manager.get_task_data():
await group_manager.init_group_task()
logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.')
await asyncio.get_event_loop().run_in_executor(
None, _create_help_image
)
def _create_help_image():
"""
创建管理员帮助图片
"""
_matchers = get_matchers()
_plugin_name_list = []
width = 0
_plugin_level = {}
for matcher in _matchers:
_plugin = nonebot.plugin.get_plugin(matcher.module)
_module = _plugin.module
try:
plugin_name = _module.__getattribute__("__zx_plugin_name__")
except AttributeError:
continue
try:
if (
"[admin]" in plugin_name.lower()
and plugin_name not in _plugin_name_list
and plugin_name != "管理帮助 [Admin]"
):
_plugin_name_list.append(plugin_name)
plugin_settings = _module.__getattribute__("__plugin_settings__")
plugin_des = _module.__getattribute__("__plugin_des__")
plugin_cmd = _module.__getattribute__("__plugin_cmd__")
plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x]
admin_level = int(plugin_settings["admin_level"])
if _plugin_level.get(admin_level):
_plugin_level[admin_level].append(
f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)
)
else:
_plugin_level[admin_level] = [
f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)
]
x = len(f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)) * 23
width = width if width > x else x
except AttributeError:
logger.warning(f"获取管理插件 {matcher.module}: {plugin_name} 设置失败...")
help_str = "* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" \
"[权限等级] 管理员帮助:\n\n"
x = list(_plugin_level.keys())
x.sort()
for level in x:
for help_ in _plugin_level[level]:
help_str += f"\t{help_}\n\n"
help_str += '-----[被动技能开关]-----\n\n'
task_data = group_manager.get_task_data()
for i, x in enumerate(task_data.keys()):
help_str += f'{i+1}.开启/关闭{task_data[x]}\n\n'
height = len(help_str.split("\n")) * 33
A = CreateImg(width, height, font_size=24)
_background = CreateImg(width, height, background=background)
A.text((150, 110), help_str)
A.paste(_background, alpha=True)
A.save(admin_help_image)
logger.info(f'已成功加载 {len(_plugin_name_list)} 条管理员命令')
+29 -16
View File
@@ -1,20 +1,33 @@
from .data_source import get_chat_result, hello, no_result
from services.log import logger
from nonebot import on_message
from nonebot.rule import to_me
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import (
Bot,
PrivateMessageEvent,
GroupMessageEvent,
Message,
MessageEvent,
)
from utils.utils import get_message_text, get_message_imgs
from nonebot.rule import to_me
from nonebot.typing import T_State
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.utils import get_message_text, get_message_imgs
from .data_source import get_chat_result, hello, no_result
from configs.config import NICKNAME
__plugin_name__ = "AI [Hidden]"
__zx_plugin_name__ = "AI"
__plugin_usage__ = f"""
usage:
与{NICKNAME}普普通通的对话吧!
"""
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["Ai", "ai", "AI", "aI"],
}
ai = on_message(rule=to_me(), priority=8)
@@ -38,21 +51,21 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
]:
await ai.finish(hello())
img = imgs[0] if imgs else ""
if isinstance(event, PrivateMessageEvent):
nickname = await FriendUser.get_friend_nickname(event.user_id)
else:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
if not nickname:
if isinstance(event, PrivateMessageEvent):
nickname = event.sender.nickname
else:
if isinstance(event, GroupMessageEvent):
nickname = event.sender.card if event.sender.card else event.sender.nickname
else:
nickname = event.sender.nickname
result = await get_chat_result(msg, img, event.user_id, nickname)
logger.info(
f"USER {event.user_id} GROUP {event.group_id if not isinstance(event, PrivateMessageEvent) else ''} "
f"问题:{msg}\n回答:{result}"
f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else ''} "
f"问题:{msg} ---- 回答:{result}"
)
if result:
await ai.finish(Message(result))
+55 -17
View File
@@ -1,19 +1,21 @@
import os
import random
import re
import aiohttp
from aiohttp.client import ClientSession
from configs.config import TL_KEY, ALAPI_TOKEN, ALAPI_AI_CHECK, NICKNAME
from configs.path_config import IMAGE_PATH, DATA_PATH
from aiohttp.client import ClientSession
from services.log import logger
from utils.message_builder import image, face
from utils.utils import get_bot
import re
import aiohttp
import random
import os
try:
import ujson as json
except ModuleNotFoundError:
import json
url = "http://openapi.tuling123.com/openapi/api/v2"
check_url = "https://v2.alapi.cn/api/censor/text"
@@ -23,8 +25,15 @@ index = 0
anime_data = json.load(open(DATA_PATH + "anime.json", "r", encoding="utf8"))
# 图灵AI
async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) -> str:
"""
获取 AI 返回值,顺序:图灵 -> 青云客
:param text: 问题
:param img_url: 图片链接
:param user_id: 用户id
:param nickname: 用户昵称
:return: 回答
"""
global index
if index == 5:
index = 0
@@ -51,7 +60,15 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str)
# 图灵接口
async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession):
async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession) -> str:
"""
获取图灵接口的回复
:param text: 问题
:param img_url: 图片链接
:param user_id: 用户id
:param sess: AIOHTTP SESSION
:return: 图灵回复
"""
global index
try:
if text:
@@ -95,7 +112,13 @@ async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession):
# 屑 AI
async def xie_ai(text: str, sess: ClientSession):
async def xie_ai(text: str, sess: ClientSession) -> str:
"""
获取青云客回复
:param text: 问题
:param sess: AIOHTTP SESSION
:return: 青云可回复
"""
async with sess.get(
f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}"
) as res:
@@ -104,7 +127,9 @@ async def xie_ai(text: str, sess: ClientSession):
if data["result"] == 0:
content = data["content"]
if "菲菲" in content:
content = content.replace("菲菲", f"{NICKNAME}")
content = content.replace("菲菲", NICKNAME)
if "艳儿" in content:
content = content.replace("艳儿", NICKNAME)
if "公众号" in content:
content = ""
if "{br}" in content:
@@ -122,16 +147,22 @@ async def xie_ai(text: str, sess: ClientSession):
)
else:
break
return content if not content and not ALAPI_AI_CHECK else await check_text(content, sess)
return (
content
if not content and not ALAPI_AI_CHECK
else await check_text(content, sess)
)
# 打招呼内容
def hello() -> str:
"""
一些打招呼的内容
"""
result = random.choice(
(
"哦豁?!",
"你好!Ov<",
f"库库库,呼唤{list(get_bot().config.nickname)[0]}做什么呢",
f"库库库,呼唤{NICKNAME}做什么呢",
"我在呢!",
"呼呼,叫俺干嘛",
)
@@ -146,6 +177,9 @@ def hello() -> str:
# 没有回答时回复内容
def no_result() -> str:
"""
没有回答时的回复
"""
return (
random.choice(
[
@@ -160,8 +194,12 @@ def no_result() -> str:
)
# 检测屑AI回复的文本是否是 *话
async def check_text(text: str, sess: ClientSession) -> str:
"""
ALAPI文本检测,主要针对青云客API,检测为恶俗文本改为无回复的回答
:param text: 回复
:param sess: AIOHTTP SESSION
"""
if not ALAPI_TOKEN:
return text
params = {"token": ALAPI_TOKEN, "text": text}
@@ -169,8 +207,8 @@ async def check_text(text: str, sess: ClientSession) -> str:
async with sess.get(check_url, timeout=2, params=params) as response:
data = await response.json()
if data["code"] == 200:
if data["conclusion_type"] == 2:
return ''
if data["data"]["conclusion_type"] == 2:
return ""
except Exception as e:
logger.error(f"检测违规文本错误...e:{e}")
logger.error(f"检测违规文本错误...{type(e)}:{e}")
return text
+3
View File
@@ -0,0 +1,3 @@
import nonebot
nonebot.load_plugins("plugins/alapi")
+30 -18
View File
@@ -5,32 +5,44 @@ from configs.config import ALAPI_TOKEN
from .data_source import get_data
from services.log import logger
__plugin_name__ = '网易云热评'
__plugin_usage__ = '用法: 生了个人,我很抱歉'
comments_163 = on_command("网易云热评", aliases={'网易云评论', '到点了', '12点了'}, priority=5, block=True)
__zx_plugin_name__ = "网易云热评"
__plugin_usage__ = """
usage:
到点了,还是防不了下塔
指令:
网易云热评/到点了/12点了
""".strip()
__plugin_des__ = "生了个人,我很抱歉"
__plugin_cmd__ = ["网易云热评", "到点了", "12点了"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["网易云热评", "网易云评论", "到点了", "12点了"],
}
comments_163_url = 'https://v2.alapi.cn/api/comment'
comments_163 = on_command(
"网易云热评", aliases={"网易云评论", "到点了", "12点了"}, priority=5, block=True
)
comments_163_url = "https://v2.alapi.cn/api/comment"
@comments_163.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
params = {
'token': ALAPI_TOKEN
}
params = {"token": ALAPI_TOKEN}
data, code = await get_data(comments_163_url, params)
if code != 200:
await comments_163.finish(data, at_sender=True)
data = data['data']
comment = data['comment_content']
song_name = data['title']
await comments_163.send(f'{comment}\n\t——《{song_name}》')
data = data["data"]
comment = data["comment_content"]
song_name = data["title"]
await comments_163.send(f"{comment}\n\t——《{song_name}》")
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送网易云热评: {comment} \n\t\t————{song_name}")
f" 发送网易云热评: {comment} \n\t\t————{song_name}"
)
+16 -3
View File
@@ -7,9 +7,22 @@ from utils.utils import get_message_text
from .data_source import get_data
from services.log import logger
__plugin_name__ = 'b封面'
__plugin_usage__ = '用法: b封面 (链接,av,bv,cv,直播id)\n\t' \
'示例:b封面 av86863038'
__zx_plugin_name__ = 'b封面'
__plugin_usage__ = """usage:
b封面 [链接/av/bv/cv/直播id]
示例:b封面 av86863038
"""
__plugin_des__ = '快捷的b站视频封面获取方式'
__plugin_cmd__ = ['b封面/B封面']
__plugin_type__ = ('一些工具',)
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["b封面", 'B封面'],
}
cover = on_command('b封面', aliases={'B封面'}, priority=5, block=True)
+12 -2
View File
@@ -2,10 +2,16 @@ from nonebot.adapters.cqhttp import MessageSegment
from utils.image_utils import CreateImg
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from typing import Union
import aiohttp
async def get_data(url: str, params: dict):
async def get_data(url: str, params: dict) -> 'Union[dict, str], int':
"""
获取ALAPI数据
:param url: 请求链接
:param params: 参数
"""
async with aiohttp.ClientSession() as session:
try:
async with session.get(
@@ -22,7 +28,11 @@ async def get_data(url: str, params: dict):
return "超时了....", 998
def gen_wbtop_pic(data) -> MessageSegment:
def gen_wbtop_pic(data: dict) -> MessageSegment:
"""
生成微博热搜图片
:param data: 微博热搜数据
"""
bk = CreateImg(700, 32 * 50 + 280, 700, 32, color='#797979')
wbtop_bk = CreateImg(700, 280, background=f'{IMAGE_PATH}/other/webtop.png')
bk.paste(wbtop_bk)
+15 -3
View File
@@ -5,9 +5,21 @@ from configs.config import ALAPI_TOKEN
from services.log import logger
from .data_source import get_data
__plugin_name__ = '古诗'
__plugin_usage__ = '用法: 无'
__zx_plugin_name__ = '古诗'
__plugin_usage__ = """usage:
平白无故念首诗
示例:念诗/来首诗/念首诗
"""
__plugin_des__ = '为什么突然文艺起来了!'
__plugin_cmd__ = ['念诗/来首诗/念首诗']
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ['念诗', '来首诗', '念首诗'],
}
poetry = on_command("念诗", aliases={'来首诗', '念首诗'}, priority=5, block=True)
+27 -10
View File
@@ -10,9 +10,25 @@ from configs.path_config import IMAGE_PATH
from utils.message_builder import image
import asyncio
__plugin_name__ = '微博热搜'
__plugin_usage__ = '用法: 无'
__zx_plugin_name__ = '微博热搜'
__plugin_usage__ = """
usage:
在QQ上吃个瓜
指令:
微博热搜:发送实时热搜
微博热搜 [id]:截图该热搜页面
示例:微博热搜 5
""".strip()
__plugin_des__ = '刚买完瓜,在吃瓜现场'
__plugin_cmd__ = ['微博热搜', '微博热搜 [id]']
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ['微博热搜'],
}
wbtop = on_command("wbtop", aliases={'微博热搜'}, priority=5, block=True)
@@ -34,11 +50,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
if code != 200:
await wbtop.finish(data, at_sender=True)
wbtop_data = data['data']
img = await asyncio.get_event_loop().run_in_executor(None, gen_wbtop_pic, wbtop_data)
await wbtop.send(img)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询微博热搜")
if not msg:
img = await asyncio.get_event_loop().run_in_executor(None, gen_wbtop_pic, wbtop_data)
await wbtop.send(img)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询微博热搜")
if is_number(msg) and 0 < int(msg) <= 50:
url = wbtop_data[int(msg) - 1]['url']
browser = await get_browser()
@@ -51,9 +68,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
await page.goto(url, wait_until='networkidle', timeout=10000)
await page.set_viewport_size({"width": 2560, "height": 1080})
div = await page.query_selector("#pl_feedlist_index")
await div.screenshot(path=f'{IMAGE_PATH}/temp/webtop_{event.user_id}.png', timeout=100000)
await div.screenshot(path=f'{IMAGE_PATH}/temp/wbtop_{event.user_id}.png', timeout=100000)
await page.close()
await wbtop.send(image(f'webtop_{event.user_id}.png', 'temp'))
await wbtop.send(image(f'wbtop_{event.user_id}.png', 'temp'))
except Exception as e:
logger.error(f'微博热搜截图出错... {type(e)}: {e}')
if page:
+3 -1
View File
@@ -7,7 +7,9 @@ from nonebot.adapters.cqhttp.exception import ActionFailed
from utils.utils import scheduler
import time
__plugin_name__ = "好友群聊处理请求 [Hidden]"
__zx_plugin_name__ = "好友群聊处理请求 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
friend_req = on_request(priority=5)
+43 -13
View File
@@ -4,22 +4,38 @@ from models.level_user import LevelUser
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent
from nonebot.adapters.cqhttp.permission import GROUP
from utils.utils import get_message_at, get_message_text, is_number
from configs.config import NICKNAME
from configs.config import NICKNAME, BAN_LEVEL
from nonebot.permission import SUPERUSER
from services.log import logger
__plugin_name__ = "Ban/unBan"
__plugin_usage__ = (
"用法:\n"
f"(不是禁言!是针对{NICKNAME}是否处理封禁用户消息)\n"
"封禁/解封用户 [小时] [分钟]\n"
"示例:.ban @djdsk\n"
"示例:.ban @djdsk 0 30\n"
"示例:.ban @sdasf 4\n"
"示例:.unban @sdasf"
)
__zx_plugin_name__ = "封禁Ban用户 [Admin]"
__plugin_usage__ = """
usage:
将用户拉入或拉出黑名单
指令:
.ban [at] ?[小时] ?[分钟]
.unban
示例:.ban @user
示例:.ban @user 6
示例:.ban @user 3 10
示例:.unban @user
""".strip()
__plugin_superuser_usage__ = """
usage:
屏蔽用户消息,相当于最上级.ban
指令:
b了 [at]
示例:b了 @user
""".strip()
__plugin_des__ = '你被逮捕了!丢进小黑屋!'
__plugin_cmd__ = ['.ban [at] ?[小时] ?[分钟]', '.unban [at]', 'b了 [at] [_superuser]']
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"admin_level": BAN_LEVEL,
}
ban = on_command(
@@ -29,6 +45,8 @@ ban = on_command(
block=True,
)
super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True)
@ban.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
@@ -155,5 +173,17 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
@super_ban.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
qq = get_message_at(event.json())
if qq:
qq = qq[0]
user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
user_name = user['card'] if user['card'] else user['nickname']
if not await BanUser.ban(qq, 10, 99999999):
await BanUser.unban(qq)
await BanUser.ban(qq, 10, 99999999)
await ban.send(f"已将 {user_name} 拉入黑名单!")
else:
await super_ban.send('需要艾特被super ban的对象..')
+217
View File
@@ -0,0 +1,217 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message
from .data_source import (
add_live_sub,
delete_sub,
add_up_sub,
add_season_sub,
get_media_id,
get_sub_status,
SubManager,
)
from models.level_user import LevelUser
from configs.config import GROUP_BILIBILI_SUB_LEVEL
from utils.utils import get_message_text, is_number, scheduler, get_bot
from models.bilibili_sub import BilibiliSub
from typing import Optional
from services.log import logger
from nonebot import Driver
import nonebot
__zx_plugin_name__ = "B站订阅"
__plugin_usage__ = """
usage:
B站直播,番剧,UP动态开播等提醒
主播订阅相当于 直播间订阅 + UP订阅
指令:[示例Id乱打的,仅做示例]
添加订阅 ['主播'/'UP'/'番剧'] [id/链接/番名]
删除订阅 [id]
查看订阅
示例:添加订阅主播 2345344 <-(直播房间id)
示例:添加订阅UP 2355543 <-(个人主页id)
示例:添加订阅番剧 史莱姆 <-(支持模糊搜索)
示例:添加订阅番剧 125344 <-(番剧id)
示例:删除订阅 2324344 <-(任意id,通过查看订阅获取)
""".strip()
__plugin_des__ = '非常便利的B站订阅通知'
__plugin_cmd__ = ['添加订阅 [主播/UP/番剧] [id/链接/番名]', '删除订阅 [id]', '查看订阅']
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["B站订阅", 'b站订阅', '添加订阅', '删除订阅', '查看订阅'],
}
add_sub = on_command("添加订阅", priority=5, block=True)
del_sub = on_command("删除订阅", priority=5, block=True)
show_sub_info = on_command('查看订阅', priority=5, block=True)
driver: Driver = nonebot.get_driver()
sub_manager: Optional[SubManager] = None
@driver.on_startup
async def _():
global sub_manager
sub_manager = SubManager()
@add_sub.args_parser
async def _(bot: Bot, event: MessageEvent, state: T_State):
season_data = state["season_data"]
msg = get_message_text(event.json())
if not is_number(msg) or int(msg) < 1 or int(msg) > len(season_data):
await add_sub.reject("Id必须为数字且在范围内!请重新输入...")
state["id"] = season_data[int(msg) - 1]["media_id"]
@add_sub.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json()).split()
if len(msg) < 2:
await add_sub.finish("参数不完全,请查看订阅帮助...")
sub_type = msg[0]
id_ = ""
if isinstance(event, GroupMessageEvent):
if not await LevelUser.check_level(
event.user_id, event.group_id, GROUP_BILIBILI_SUB_LEVEL
):
await add_sub.finish(
f"您的权限不足,群内订阅的需要 {GROUP_BILIBILI_SUB_LEVEL} 级权限..", at_sender=True
)
sub_user = f"{event.user_id}:{event.group_id}"
else:
sub_user = f"{event.user_id}"
state["sub_type"] = sub_type
state["sub_user"] = sub_user
if len(msg) > 1:
if "http" in msg[1]:
msg[1] = msg[1].split("?")[0]
msg[1] = msg[1][:-1] if msg[1][-1] == "/" else msg[1]
msg[1] = msg[1].split("/")[-1]
id_ = msg[1][2:] if msg[1].startswith("md") else msg[1]
if not is_number(id_):
if sub_type in ["season", "动漫", "番剧"]:
rst = "*以为您找到以下番剧,请输入Id选择:*\n"
state["season_data"] = await get_media_id(id_)
if len(state["season_data"]) == 0:
await add_sub.finish(f"未找到番剧:{msg}")
for i, x in enumerate(state["season_data"]):
rst += f'{i + 1}.{state["season_data"][x]["title"]}\n----------\n'
await add_sub.send("\n".join(rst.split("\n")[:-1]))
else:
await add_sub.finish("Id 必须为全数字!")
else:
state["id"] = int(id_)
@add_sub.got("id")
async def _(bot: Bot, event: MessageEvent, state: T_State):
sub_type = state["sub_type"]
sub_user = state["sub_user"]
id_ = state["id"]
if sub_type in ["主播", "直播"]:
await add_sub.send(await add_live_sub(id_, sub_user))
elif sub_type.lower() in ["up", "用户"]:
await add_sub.send(await add_up_sub(id_, sub_user))
elif sub_type in ["season", "动漫", "番剧"]:
await add_sub.send(await add_season_sub(id_, sub_user))
else:
await add_sub.finish("参数错误,第一参数必须为:主播/up/番剧!")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 添加订阅:{sub_type} -> {sub_user} -> {id_}"
)
@del_sub.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if not is_number(msg):
await del_sub.finish('Id必须为数字!', at_sender=True)
id_ = f'{event.user_id}:{event.group_id}' if isinstance(event, GroupMessageEvent) else f'{event.user_id}'
if await BilibiliSub.delete_bilibili_sub(int(msg), id_):
await del_sub.send(f'删除订阅id:{msg} 成功...')
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除订阅 {id_}"
)
else:
await del_sub.send(f'删除订阅id:{msg} 失败...')
@show_sub_info.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
id_ = f'{event.user_id}:{event.group_id}' if isinstance(event, GroupMessageEvent) else f'{event.user_id}'
data = await BilibiliSub.get_sub_data(id_)
live_rst = ''
up_rst = ''
season_rst = ''
for x in data:
if x.sub_type == 'live':
live_rst += f'\t直播间id:{x.sub_id}\n' \
f'\t名称:{x.uname}\n' \
f'------------------\n'
if x.sub_type == 'up':
up_rst += f'\tUP:{x.uname}\n' \
f'\tuid:{x.uid}\n' \
f'------------------\n'
if x.sub_type == 'season':
season_rst += f'\t番名:{x.season_name}\n' \
f'\t当前集数:{x.season_current_episode}\n' \
f'------------------\n'
live_rst = '当前订阅的直播:\n' + live_rst if live_rst else live_rst
up_rst = '当前订阅的UP:\n' + up_rst if up_rst else up_rst
season_rst = '当前订阅的番剧:\n' + season_rst if season_rst else season_rst
if not live_rst and not up_rst and not season_rst:
live_rst = '您目前没有任何订阅...'
await show_sub_info.send(live_rst + up_rst + season_rst)
# 推送
@scheduler.scheduled_job(
"interval",
seconds=30,
)
async def _():
bot = get_bot()
sub = None
if bot:
try:
await sub_manager.reload_sub_data()
sub = await sub_manager.random_sub_data()
if sub:
rst = await get_sub_status(sub.sub_id, sub.sub_type)
await send_sub_msg(rst, sub, bot)
if sub.sub_type == "live":
rst = await get_sub_status(sub.sub_id, "up")
await send_sub_msg(rst, sub, bot)
except Exception as e:
logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id if sub else 0} {type(e)}:{e}")
async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
"""
推送信息
:param rst: 回复
:param sub: BilibiliSub
:param bot: Bot
"""
if rst:
for x in sub.sub_users.split(",")[:-1]:
try:
if ":" in x:
await bot.send_group_msg(
group_id=int(x.split(":")[1]), message=Message(rst)
)
else:
await bot.send_private_msg(user_id=int(x), message=Message(rst))
except Exception as e:
logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id} {type(e)}:{e}")
+390
View File
@@ -0,0 +1,390 @@
from bilibili_api.exceptions.ResponseCodeException import ResponseCodeException
from asyncio.exceptions import TimeoutError
from models.bilibili_sub import BilibiliSub
from bilibili_api.live import LiveRoom
from bilibili_api import bangumi
from utils.message_builder import image
from bilibili_api.user import User
from bilibili_api import user
from typing import Optional
from pathlib import Path
from configs.path_config import IMAGE_PATH
from datetime import datetime
from utils.browser import get_browser
from services.db_context import db
from services.log import logger
import aiohttp
import random
bilibili_search_url = "https://api.bilibili.com/x/web-interface/search/all/v2"
dynamic_path = Path(IMAGE_PATH) / "bilibili_sub" / "dynamic"
dynamic_path.mkdir(exist_ok=True, parents=True)
async def add_live_sub(live_id: int, sub_user: str) -> str:
"""
添加直播订阅
:param live_id: 直播房间号
:param sub_user: 订阅用户 id # 7384933:private or 7384933:2342344(group)
:return:
"""
try:
async with db.transaction():
try:
live = LiveRoom(live_id)
live_info = (await live.get_room_info())["room_info"]
except ResponseCodeException:
return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确"
uid = live_info["uid"]
room_id = live_info["room_id"]
short_id = live_info["short_id"]
title = live_info["title"]
live_status = live_info["live_status"]
if await BilibiliSub.add_bilibili_sub(
room_id,
"live",
sub_user,
uid=uid,
live_short_id=short_id,
live_status=live_status,
):
await _get_up_status(live_id)
uname = (await BilibiliSub.get_sub(live_id)).uname
return (
"已成功订阅主播:\n"
f"\ttitle:{title}\n"
f"\tname: {uname}\n"
f"\tlive_id:{live_id}\n"
f"\tuid:{uid}"
)
else:
return "添加订阅失败..."
except Exception as e:
logger.error(f"订阅主播live_id:{live_id} 发生了错误 {type(e)}:{e}")
return "添加订阅失败..."
async def add_up_sub(uid: int, sub_user: str) -> str:
"""
添加订阅 UP
:param uid: UP uid
:param sub_user: 订阅用户
"""
try:
async with db.transaction():
try:
u = user.User(uid)
user_info = await u.get_user_info()
except ResponseCodeException:
return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
uname = user_info["name"]
dynamic_info = await u.get_dynamics(0)
dynamic_upload_time = 0
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
video_info = await u.get_videos()
latest_video_created = 0
if video_info["list"].get("vlist"):
latest_video_created = video_info["list"]["vlist"][0]["created"]
if await BilibiliSub.add_bilibili_sub(
uid,
"up",
sub_user,
uid=uid,
uname=uname,
dynamic_upload_time=dynamic_upload_time,
latest_video_created=latest_video_created,
):
return "已成功订阅UP:\n" f"\tname: {uname}\n" f"\tuid:{uid}"
else:
return "添加订阅失败..."
except Exception as e:
logger.error(f"订阅Up uid:{uid} 发生了错误 {type(e)}:{e}")
return "添加订阅失败..."
async def add_season_sub(media_id: int, sub_user: str) -> str:
"""
添加订阅 UP
:param media_id: 番剧 media_id
:param sub_user: 订阅用户
"""
try:
async with db.transaction():
try:
season_info = await bangumi.get_meta(media_id)
except ResponseCodeException:
return f"未找到media_id:{media_id} 的信息,请检查Id是否正确"
season_id = season_info["media"]["season_id"]
season_current_episode = season_info["media"]["new_ep"]["index"]
season_name = season_info["media"]["title"]
if await BilibiliSub.add_bilibili_sub(
media_id,
"season",
sub_user,
season_name=season_name,
season_id=season_id,
season_current_episode=season_current_episode,
):
return (
"已成功订阅番剧:\n"
f"\ttitle: {season_name}\n"
f"\tcurrent_episode: {season_current_episode}"
)
else:
return "添加订阅失败..."
except Exception as e:
logger.error(f"订阅番剧 media_id:{media_id} 发生了错误 {type(e)}:{e}")
return "添加订阅失败..."
async def delete_sub(sub_id: str, sub_user: str) -> str:
"""
删除订阅
:param sub_id: 订阅 id
:param sub_user: 订阅用户 id # 7384933:private or 7384933:2342344(group)
"""
if await BilibiliSub.delete_bilibili_sub(sub_id, sub_user):
return f"已成功取消订阅:{sub_id}"
else:
return f"取消订阅:{sub_id} 失败,请检查是否订阅过该Id...."
async def get_media_id(keyword: str) -> dict:
"""
获取番剧的 media_id
:param keyword: 番剧名称
"""
params = {"keyword": keyword}
async with aiohttp.ClientSession() as session:
for _ in range(3):
try:
_season_data = {}
async with session.get(
bilibili_search_url, timeout=5, params=params
) as response:
if response.status == 200:
data = await response.json()
if data.get("data"):
for item in data["data"]["result"]:
if item["result_type"] == "media_bangumi":
idx = 0
for x in item["data"]:
_season_data[idx] = {
"media_id": x["media_id"],
"title": x["title"]
.replace('<em class="keyword">', "")
.replace("</em>", ""),
}
idx += 1
return _season_data
except TimeoutError:
pass
return {}
async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
"""
获取订阅状态
:param id_: 订阅 id
:param sub_type: 订阅类型
:return:
"""
try:
if sub_type == "live":
return await _get_live_status(id_)
elif sub_type == "up":
return await _get_up_status(id_)
elif sub_type == "season":
return await _get_season_status(id_)
except ResponseCodeException:
return "获取信息失败...请检查订阅Id是否存在或稍后再试..."
# except Exception as e:
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
async def _get_live_status(id_: int) -> Optional[str]:
"""
获取直播订阅状态
:param id_: 直播间 id
"""
live = LiveRoom(id_)
live_info = (await live.get_room_info())["room_info"]
title = live_info["title"]
room_id = live_info["room_id"]
live_status = live_info["live_status"]
cover = live_info["cover"]
sub = await BilibiliSub.get_sub(id_)
if sub.live_status != live_status:
await BilibiliSub.update_sub_info(id_, live_status=live_status)
if sub.live_status == 0 and live_status == 1:
return (
f"{image(cover)}\n"
f"{sub.uname} 开播啦!\n"
f"标题:{title}\n"
f"直链:https://live.bilibili.com/{room_id}"
)
return None
async def _get_up_status(id_: int) -> Optional[str]:
"""
获取用户投稿状态
:param id_: 用户 id
:return:
"""
_user = await BilibiliSub.get_sub(id_)
u = user.User(_user.uid)
user_info = await u.get_user_info()
uname = user_info["name"]
video_info = await u.get_videos()
latest_video_created = 0
video = None
if _user.uname != uname:
await BilibiliSub.update_sub_info(id_, uname=uname)
dynamic_img, dynamic_upload_time = await get_user_dynamic(u, _user)
if video_info["list"].get("vlist"):
video = video_info["list"]["vlist"][0]
latest_video_created = video["created"]
rst = ""
if dynamic_img:
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n"
if _user.latest_video_created != latest_video_created and video:
rst = rst + "-------------\n" if rst else rst
await BilibiliSub.update_sub_info(
id_, latest_video_created=latest_video_created
)
rst += (
f'{image(video["pic"])}\n'
f"{uname} 投稿了新视频啦\n"
f'标题:{video["title"]}\n'
f'Bvid:{video["bvid"]}\n'
f'直链:https://www.bilibili.com/video/{video["bvid"]}'
)
rst = None if rst == "-------------\n" else rst
return rst
async def _get_season_status(id_) -> Optional[str]:
"""
获取 番剧 更新状态
:param id_: 番剧 id
"""
season_info = await bangumi.get_meta(id_)
title = season_info["media"]["title"]
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode
new_ep = season_info["media"]["new_ep"]["index"]
if new_ep != _idx:
await BilibiliSub.update_sub_info(
id_, season_current_episode=new_ep, season_update_time=datetime.now()
)
return (
f'{image(season_info["media"]["cover"])}\n'
f"[{title}]更新啦\n"
f"最新集数:{new_ep}"
)
return None
async def get_user_dynamic(
u: User, local_user: BilibiliSub
) -> "Optional[MessageSegment], int":
"""
获取用户动态
:param u: 用户类
:param local_user: 数据库存储的用户数据
:return: 最新动态截图与时间
"""
dynamic_info = await u.get_dynamics(0)
browser = await get_browser()
if dynamic_info.get("cards") and browser:
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
if local_user.dynamic_upload_time != dynamic_upload_time:
page = await browser.new_page()
await page.goto(
f"https://space.bilibili.com/{local_user.uid}/dynamic",
wait_until="networkidle",
timeout=10000,
)
await page.set_viewport_size({"width": 2560, "height": 1080})
# 删除置顶
await page.evaluate(
"""
xs = document.getElementsByClassName('first-card-with-title');
for (x of xs) {
x.remove();
}
"""
)
card = await page.query_selector(".card")
# 截图并保存
await card.screenshot(
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
timeout=100000,
)
await page.close()
return (
image(
f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
"bilibili_sub/dynamic",
),
dynamic_upload_time,
)
return None, None
class SubManager:
def __init__(self):
self.live_data = []
self.up_data = []
self.season_data = []
self.current_index = -1
async def reload_sub_data(self):
"""
重载数据
"""
if not self.live_data or not self.up_data or not self.season_data:
(
_live_data,
_up_data,
_season_data,
) = await BilibiliSub.get_all_sub_data()
if not self.live_data:
self.live_data = _live_data
if not self.up_data:
self.up_data = _up_data
if not self.season_data:
self.season_data = _season_data
async def random_sub_data(self) -> Optional[BilibiliSub]:
"""
随机获取一条数据
:return:
"""
sub = None
if not self.live_data and not self.up_data and not self.season_data:
return sub
self.current_index += 1
if self.current_index == 0:
if self.live_data:
sub = random.choice(self.live_data)
self.live_data.remove(sub)
elif self.current_index == 1:
if self.up_data:
sub = random.choice(self.up_data)
self.up_data.remove(sub)
elif self.current_index == 2:
if self.season_data:
sub = random.choice(self.season_data)
self.season_data.remove(sub)
else:
self.current_index = -1
if sub:
return sub
await self.reload_sub_data()
return await self.random_sub_data()
+72
View File
@@ -0,0 +1,72 @@
from utils.image_utils import CreateImg
from configs.path_config import IMAGE_PATH
from pathlib import Path
from bilibili_api import user
from io import BytesIO
import aiohttp
BORDER_PATH = Path(IMAGE_PATH) / 'border'
BORDER_PATH.mkdir(parents=True, exist_ok=True)
async def get_pic(url: str) -> bytes:
"""
获取图像
:param url: 图像链接
:return: 图像二进制
"""
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=2) as response:
return await response.read()
async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des: str):
"""
生成主播简介图片
:param uid: 主播 uid
:param title: 直播间标题
:param cover: 直播封面
:param tags: 直播标签
:param des: 直播简介
:return:
"""
u = user.User(uid)
user_info = await u.get_user_info()
name = user_info['name']
sex = user_info['sex']
face = user_info['face']
sign = user_info['sign']
ava = CreateImg(100, 100, background=BytesIO(await get_pic(face)))
ava.circle()
cover = CreateImg(470, 265, background=BytesIO(await get_pic(cover)))
print()
def _create_live_des_image(title: str, cover: CreateImg, tags: str, des: str, user_name: str, sex: str, sign: str, ava: CreateImg):
"""
生成主播简介图片
:param title: 直播间标题
:param cover: 直播封面
:param tags: 直播标签
:param des: 直播简介
:param user_name: 主播名称
:param sex: 主播性别
:param sign: 主播签名
:param ava: 主播头像
:return:
"""
border = BORDER_PATH / '0.png'
border_img = None
if border.exists():
border_img = CreateImg(1772, 2657, background=border)
bk = CreateImg(1772, 2657, font_size=30)
bk.paste(cover, (0, 100), center_type='by_width')
+37 -26
View File
@@ -5,12 +5,21 @@ from nonebot.permission import SUPERUSER
import asyncio
from utils.utils import get_message_text, get_message_imgs
from services.log import logger
from models.group_remind import GroupRemind
from utils.message_builder import image
from utils.manager import group_manager
__plugin_name__ = "广播 [Hidden]"
__plugin_usage__ = '广播- [消息] or [图片]'
__zx_plugin_name__ = "广播 [Superuser]"
__plugin_usage__ = """
usage:
指令:
广播- ?[消息] ?[图片]
示例:广播- 你们好!
""".strip()
__plugin_des__ = "昭告天下!"
__plugin_cmd__ = ["广播-"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"broadcast": "广播"}
broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
@@ -19,30 +28,32 @@ broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
async def _(bot: Bot, event: Event, state: T_State):
msg = get_message_text(event.json())
imgs = get_message_imgs(event.json())
rst = ''
rst = ""
for img in imgs:
rst += image(img)
sid = bot.self_id
gl = await bot.get_group_list(self_id=sid)
gl = [g['group_id'] for g in gl]
gl = [
g["group_id"]
for g in gl
if await group_manager.check_group_task_status(g["group_id"], "broadcast")
]
g_cnt = len(gl)
cnt = 0
error = ""
x = 0.25
for g in gl:
if await GroupRemind.get_status(g, 'gb'):
await asyncio.sleep(0.5)
try:
await bot.send_group_msg(self_id=sid, group_id=g, message=msg+rst)
logger.info(f'群{g} 投递广播成功')
except Exception as e:
logger.error(f'群{g} 投递广播失败:{type(e)}')
try:
await broadcast.send(f'群{g} 投递广播失败:{type(e)}')
except Exception as e:
logger.critical(f'向广播发起者进行错误回报时发生错误:{type(e)}')
await broadcast.send(f'广播完成!')
cnt += 1
if cnt / g_cnt > x:
await broadcast.send(f"已播报至 {int(cnt / g_cnt * 100)}% 的群聊")
x += 0.25
try:
await bot.send_group_msg(self_id=sid, group_id=g, message=msg + rst)
logger.info(f"GROUP {g} 投递广播成功")
except Exception as e:
logger.error(f"GROUP {g} 投递广播失败:{type(e)}")
error += f"GROUP {g} 投递广播失败:{type(e)}\n"
await asyncio.sleep(0.5)
await broadcast.send(f"已播报至 100% 的群聊")
if error:
await broadcast.send(f"播报时错误:{error}")
+22 -17
View File
@@ -6,21 +6,33 @@ from nonebot.adapters import Bot
from nonebot.adapters.cqhttp import PrivateMessageEvent
from utils.utils import get_message_text
from nonebot.adapters.cqhttp.permission import PRIVATE
from utils.utils import UserExistLimiter
from asyncio.exceptions import TimeoutError
from aiohttp.client_exceptions import ServerDisconnectedError
__plugin_name__ = "磁力搜索"
__plugin_usage__ = r"""
* 请各位使用后不要转发 *
* 拒绝反冲斗士! *
bt [关键词] [页数](默认为1)
示例:
bt 钢铁侠
bt 钢铁侠 3
__zx_plugin_name__ = "磁力搜索"
__plugin_usage__ = """
usage:
* 请各位使用后不要转发 *
* 拒绝反冲斗士! *
指令:
bt [关键词] ?[页数]
示例:bt 钢铁侠
示例:bt 钢铁侠 3
""".strip()
__plugin_des__ = "bt(磁力搜索)[仅支持私聊,懂的都懂]"
__plugin_cmd__ = ["bt [关键词] ?[页数]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["bt", "磁力搜索", "Bt", "BT"],
}
__plugin_block_limit__ = {
"rst": "您有bt任务正在进行,请等待结束."
}
_ulmt = UserExistLimiter()
bt = on_command("bt", permission=PRIVATE, priority=5, block=True)
@@ -38,8 +50,6 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
@bt.handle()
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
if _ulmt.check(event.user_id):
await bt.finish("您有bt任务正在进行,请等待结束.", at_sender=True)
mp = get_message_text(event.json())
if not mp:
return
@@ -54,7 +64,6 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
@bt.got("keyword", prompt="虚空磁力?查什么GKD")
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
_ulmt.set_True(event.user_id)
keyword = state["keyword"]
page = state["page"]
await bt.send("开始搜索....", at_sender=True)
@@ -72,16 +81,12 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
)
send_flag = True
except TimeoutError:
_ulmt.set_False(event.user_id)
await bt.finish(f"搜索 {keyword} 超时...")
except ServerDisconnectedError:
_ulmt.set_False(event.user_id)
await bt.finish(f"搜索 {keyword} 连接失败")
except Exception as e:
_ulmt.set_False(event.user_id)
await bt.finish(f"bt 其他未知错误..")
logger.error(f"bt 错误 e:{e}")
if not send_flag:
await bt.send(f"{keyword} 未搜索到...")
logger.info(f"USER {event.user_id} BT搜索 {keyword} 第 {page} 页")
_ulmt.set_False(event.user_id)
+57
View File
@@ -0,0 +1,57 @@
from .music_163 import get_song_id, get_song_info
from nonebot.adapters.cqhttp import Bot, Event, GroupMessageEvent
from nonebot.typing import T_State
from services.log import logger
from nonebot import on_command
__zx_plugin_name__ = "点歌"
__plugin_usage__ = """
usage:
在线点歌
指令:
点歌 [歌名]
""".strip()
__plugin_des__ = "为你点播了一首曾经的歌"
__plugin_cmd__ = ["点歌 [歌名]"]
__plugin_type__ = ("一些工具",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["点歌"],
}
songpicker = on_command("点歌", priority=5, block=True)
@songpicker.handle()
async def handle_first_receive(bot: Bot, event: Event, state: T_State):
args = str(event.get_message()).strip()
if args:
state["song_name"] = args
@songpicker.got("song_name", prompt="歌名是?")
async def _(bot: Bot, event: Event, state: T_State):
song = state["song_name"]
song_id = await get_song_id(song)
if not song_id:
await songpicker.finish("没有找到这首歌!", at_sender=True)
for _ in range(3):
song_content = [{"type": "music", "data": {"type": 163, "id": song_id}}]
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 点歌 :{song}"
)
await songpicker.finish(song_content)
else:
await songpicker.finish("网易云繁忙...")
+47
View File
@@ -0,0 +1,47 @@
import aiohttp
import json
headers = {"referer": "http://music.163.com"}
cookies = {"appver": "2.0.2"}
async def search_song(song_name: str):
async with aiohttp.ClientSession(
headers=headers, cookies=cookies
) as session:
async with session.post(
f"http://music.163.com/api/search/get/",
data={"s": song_name, "limit": 1, "type": 1, "offset": 0},
) as r:
if r.status != 200:
return None
r = await r.text()
return json.loads(r)
async def get_song_id(songName: str) -> int:
"""
根据用户输入的songName 获取候选songId列表 [默认songId数量:5]
"""
r = await search_song(songName)
return r["result"]["songs"][0]["id"]
async def get_song_info(songId: int):
"""
获取歌曲信息
"""
async with aiohttp.ClientSession(
headers=headers, cookies=cookies
) as session:
async with session.post(
f"http://music.163.com/api/song/detail/?id={songId}&ids=%5B{songId}%5D",
) as r:
if r.status != 200:
return None
r = await r.text()
return json.loads(r)
+11 -2
View File
@@ -6,9 +6,18 @@ from nonebot.rule import to_me
from nonebot.permission import SUPERUSER
__plugin_name__ = "自我检查 [Hidden]"
__zx_plugin_name__ = "服务器自我检查 [Superuser]"
__plugin_usage__ = """
usage:
查看服务器当前状态
指令:
自检
"""
__plugin_des__ = "查看服务器当前状态"
__plugin_cmd__ = ["自检/check"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_usage__ = "用法:自检"
check = Check()
+50 -26
View File
@@ -12,44 +12,68 @@ import platform
import os
update_zhenxun = on_command('检查更新真寻', permission=SUPERUSER, priority=1, block=True)
__zx_plugin_name__ = "自动更新 [Superuser]"
__plugin_usage__ = """
usage:
检查更新真寻最新版本,包括了自动更新
指令:
检查更新真寻
重启
""".strip()
__plugin_des__ = "就算是真寻也会成长的"
__plugin_cmd__ = ["检查更新真寻", "重启"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
restart = on_command('重启', aliases={'restart'}, permission=SUPERUSER, rule=to_me(), priority=1, block=True)
update_zhenxun = on_command("检查更新真寻", permission=SUPERUSER, priority=1, block=True)
restart = on_command(
"重启",
aliases={"restart"},
permission=SUPERUSER,
rule=to_me(),
priority=1,
block=True,
)
@update_zhenxun.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
try:
code = await check_update(bot)
code, error = await check_update(bot)
if error:
logger.error(f"更新真寻未知错误 {error}")
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]), message=f"更新真寻未知错误 {error}"
)
except Exception as e:
logger.error(f'更新真寻未知错误 {type(e)}:{e}')
logger.error(f"更新真寻未知错误 {type(e)}:{e}")
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f'更新真寻未知错误 {type(e)}:{e}'
message=f"更新真寻未知错误 {type(e)}:{e}",
)
else:
if code == 200:
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f'更新完毕,请重启真寻....'
user_id=int(list(bot.config.superusers)[0]), message=f"更新完毕,请重启真寻...."
)
@restart.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
if str(platform.system()).lower() == 'windows':
await restart.finish('暂无windows重启脚本...')
if str(platform.system()).lower() == "windows":
await restart.finish("暂无windows重启脚本...")
@restart.got('flag', prompt='确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)')
@restart.got("flag", prompt="确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)")
async def _(bot: Bot, event: MessageEvent, state: T_State):
flag = state['flag']
if flag.lower() in ['true', '是', '好']:
await restart.send('开始重启真寻..请稍等...')
open('is_restart', 'w')
os.system('./restart.sh')
flag = state["flag"]
if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
await restart.send("开始重启真寻..请稍等...")
open("is_restart", "w")
os.system("./restart.sh")
else:
await restart.send('已取消操作...')
await restart.send("已取消操作...")
@scheduler.scheduled_job(
@@ -63,7 +87,10 @@ async def _():
_version_file = Path() / "__version__"
if _version_file.exists():
_version = (
open(_version_file, "r", encoding="utf8").readline().split(":")[-1].strip()
open(_version_file, "r", encoding="utf8")
.readline()
.split(":")[-1]
.strip()
)
data = await get_latest_version_data()
if data:
@@ -72,24 +99,21 @@ async def _():
bot = get_bot()
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f'检测到真寻版本更新\n'
f'当前版本:{_version},最新版本:{latest_version}\n'
f'尝试自动更新...'
message=f"检测到真寻版本更新\n"
f"当前版本:{_version},最新版本:{latest_version}\n"
f"尝试自动更新...",
)
try:
code = await check_update(bot)
except Exception as e:
logger.error(f'更新真寻未知错误 {type(e)}:{e}')
logger.error(f"更新真寻未知错误 {type(e)}:{e}")
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f'更新真寻未知错误 {type(e)}:{e}\n'
message=f"更新真寻未知错误 {type(e)}:{e}\n",
)
else:
if code == 200:
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f'更新完毕,请重启真寻....'
message=f"更新完毕,请重启真寻....",
)
+70 -59
View File
@@ -1,9 +1,10 @@
from aiohttp.client_exceptions import ClientConnectorError
from nonebot.adapters.cqhttp import Bot
from nonebot.adapters.cqhttp import Bot, Message
from utils.user_agent import get_user_agent
from utils.utils import get_local_proxy
from utils.image_utils import CreateImg
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from typing import List
from services.log import logger
from pathlib import Path
@@ -58,7 +59,7 @@ async def remind(bot: Bot):
is_restart_file.unlink()
async def check_update(bot: Bot) -> int:
async def check_update(bot: Bot) -> 'int, str':
logger.info("开始检查更新真寻酱....")
_version = "v0.0.0"
if _version_file.exists():
@@ -78,28 +79,32 @@ async def check_update(bot: Bot) -> int:
logger.info(f"开始下载真寻最新版文件....")
if await download_latest_file(tar_gz_url):
logger.info("下载真寻最新版文件完成....")
await asyncio.get_event_loop().run_in_executor(
error = await asyncio.get_event_loop().run_in_executor(
None, _file_handle, latest_version
)
if error:
return 998, error
logger.info("真寻更新完毕,清理文件完成....")
logger.info("开始获取真寻更新日志.....")
update_info = data["body"]
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"真寻更新完成,版本:{_version} -> {latest_version}\n"
f"更新日期:{data['created_at']}\n"
f"更新日志:\n"
f"{update_info}",
)
width = 0
height = len(update_info.split('\n')) * 24
for m in update_info.split('\n'):
if len(m) * 20 > width:
width = len(m) * 18
A = CreateImg(width, height, font_size=20)
for m in update_info.split('\n'):
w, h = A.getsize(m)
if w > width:
width = w
A = CreateImg(width + 50, height, font_size=20)
A.text((10, 10), update_info)
A.save(f'{IMAGE_PATH}/update_info.png')
return 200
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=Message(f"真寻更新完成,版本:{_version} -> {latest_version}\n"
f"更新日期:{data['created_at']}\n"
f"更新日志:\n"
f"{image('update_info.png')}"),
)
return 200, ''
else:
logger.warning(f"下载真寻最新版本失败...版本号:{latest_version}")
await bot.send_private_msg(
@@ -117,57 +122,62 @@ async def check_update(bot: Bot) -> int:
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]), message=f"自动获取真寻版本失败...."
)
return 999
return 999, ''
def _file_handle(latest_version: str):
def _file_handle(latest_version: str) -> str:
if not temp_dir.exists():
temp_dir.mkdir(exist_ok=True, parents=True)
if backup_dir.exists():
shutil.rmtree(backup_dir)
backup_dir.mkdir(exist_ok=True, parents=True)
logger.info("开始解压真寻文件压缩包....")
tf = tarfile.open(zhenxun_latest_tar_gz)
tf.extractall(temp_dir)
logger.info("解压真寻文件压缩包完成....")
zhenxun_latest_file = Path(temp_dir) / os.listdir(temp_dir)[0]
update_info_file = Path(zhenxun_latest_file) / "update_info.json"
update_info = json.load(open(update_info_file, "r", encoding="utf8"))
update_file = update_info["update_file"]
add_file = update_info["add_file"]
delete_file = update_info["delete_file"]
config_file = Path() / "configs" / "config.py"
config_path_file = Path() / "configs" / "config_path.py"
for file in delete_file + update_file:
file = Path() / file
backup_file = Path(backup_dir) / file
if file.exists():
backup_file.parent.mkdir(parents=True, exist_ok=True)
if backup_file.exists():
backup_file.unlink()
if file not in [config_file, config_path_file]:
os.rename(file.absolute(), backup_file.absolute())
tf = None
error = ''
try:
backup_dir.mkdir(exist_ok=True, parents=True)
logger.info("开始解压真寻文件压缩包....")
tf = tarfile.open(zhenxun_latest_tar_gz)
tf.extractall(temp_dir)
logger.info("解压真寻文件压缩包完成....")
zhenxun_latest_file = Path(temp_dir) / os.listdir(temp_dir)[0]
update_info_file = Path(zhenxun_latest_file) / "update_info.json"
update_info = json.load(open(update_info_file, "r", encoding="utf8"))
update_file = update_info["update_file"]
add_file = update_info["add_file"]
delete_file = update_info["delete_file"]
config_file = Path() / "configs" / "config.py"
config_path_file = Path() / "configs" / "config_path.py"
for file in delete_file + update_file:
file = Path() / file
backup_file = Path(backup_dir) / file
if file.exists():
backup_file.parent.mkdir(parents=True, exist_ok=True)
if backup_file.exists():
backup_file.unlink()
if file not in [config_file, config_path_file]:
os.rename(file.absolute(), backup_file.absolute())
else:
with open(file, "r", encoding="utf8") as rf:
data = rf.read()
with open(backup_file, "w", encoding="utf8") as wf:
wf.write(data)
logger.info(f"已备份文件:{file}")
for file in add_file + update_file:
new_file = Path(zhenxun_latest_file) / file
old_file = Path() / file
if old_file not in [config_file, config_path_file]:
if not old_file.exists() and new_file.exists():
os.rename(new_file.absolute(), old_file.absolute())
logger.info(f"已更新文件:{file}")
else:
with open(file, "r", encoding="utf8") as rf:
data = rf.read()
with open(backup_file, "w", encoding="utf8") as wf:
wf.write(data)
logger.info(f"已备份文件:{file}")
for file in add_file + update_file:
new_file = Path(zhenxun_latest_file) / file
old_file = Path() / file
if old_file not in [config_file, config_path_file]:
if not old_file.exists() and new_file.exists():
os.rename(new_file.absolute(), old_file.absolute())
logger.info(f"已更新文件:{file}")
else:
tmp = ""
new_lines = open(new_file, "r", encoding="utf8").readlines()
old_lines = open(old_file, "r", encoding="utf8").readlines()
for nl in new_lines:
tmp += check_old_lines(old_lines, nl)
with open(file, "w", encoding="utf8") as f:
f.write(tmp)
tmp = ""
new_lines = open(new_file, "r", encoding="utf8").readlines()
old_lines = open(old_file, "r", encoding="utf8").readlines()
for nl in new_lines:
tmp += check_old_lines(old_lines, nl)
with open(file, "w", encoding="utf8") as f:
f.write(tmp)
except Exception as e:
error = f'{type(e)}:{e}'
if tf:
tf.close()
if temp_dir.exists():
@@ -179,6 +189,7 @@ def _file_handle(latest_version: str):
local_update_info_file.unlink()
with open(_version_file, "w", encoding="utf8") as f:
f.write(f"__version__: {latest_version}")
return error
# 获取最新版本号
@@ -215,6 +226,6 @@ def check_old_lines(lines: List[str], line: str) -> str:
return line
for l in lines:
if "=" in l and l.split("=")[0].strip() == line.split("=")[0].strip():
if len(l) > len(line):
if l.split("=")[1].strip() == 'None':
return l
return line
+53 -11
View File
@@ -2,26 +2,68 @@ from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from services.log import logger
from asyncio.exceptions import TimeoutError
from utils.message_builder import image
import requests
__plugin_name__ = "coser"
__plugin_usage__ = "用法:发送‘coser’"
from configs.path_config import IMAGE_PATH
from utils.utils import get_local_proxy
import aiohttp
import aiofiles
__zx_plugin_name__ = "coser"
__plugin_usage__ = """
usage:
三次元也不戳,嘿嘿嘿
指令:
cos/coser
""".strip()
__plugin_des__ = "三次元也不戳,嘿嘿嘿"
__plugin_cmd__ = ["cos/coser"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["cos", "coser", "括丝", "COS", "Cos", "cOS", "coS"],
}
coser = on_command(
"cos", aliases={"coser", "括丝", "COS", "Cos", "cOS", "coS"}, priority=5, block=True
)
url_2 = "http://api.rosysun.cn/cos"
url = "http://ovooa.com/API/cosplay/api.php"
@coser.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
img_url = requests.get(url_2).text
await coser.send(image(img_url))
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送COSER"
)
async with aiohttp.ClientSession() as session:
try:
for _ in range(3):
try:
async with session.get(url, proxy=get_local_proxy(), timeout=2) as response:
_url = (await response.json())['text']
async with session.get(
_url, timeout=5, proxy=get_local_proxy(), verify_ssl=False
) as res:
if res.status == 200:
async with aiofiles.open(
f"{IMAGE_PATH}/temp/{event.user_id}_coser.jpg", "wb"
) as f:
await f.write(await res.read())
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送COSER"
)
await coser.send(
image(f"{event.user_id}_coser.jpg", "temp")
)
break
except (TimeoutError, KeyError):
pass
else:
await coser.send("你cos给我看!")
except Exception as e:
await coser.send("发生了预料之外的错误..请稍后再试或联系管理员修复...")
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
+43 -13
View File
@@ -8,9 +8,46 @@ from services.log import logger
from utils.message_builder import at
__plugin_name__ = "联系管理员"
__plugin_usage__ = "用法:滴滴滴- [消息]"
__zx_plugin_name__ = "联系管理员"
__plugin_usage__ = """
usage:
有什么话想对管理员说嘛?
指令:
[滴滴滴]/滴滴滴- ?[文本] ?[图片]
示例:滴滴滴- 我喜欢你
""".strip()
__plugin_superuser_usage__ = """
superuser usage:
管理员对消息的回复
指令[以下qq与group均为乱打]:
/t: 查看当前存储的消息
/t [qq] [group] [文本]: 在group回复指定用户
/t [qq] [文本]: 私聊用户
/t -1 [group] [文本]: 在group内发送消息
/t [id] [文本]: 回复指定id的对话,id在 /t 中获取
示例:/t 73747222 32848432 你好啊
示例:/t 73747222 你好不好
示例:/t -1 32848432 我不太好
示例:/t 0 我收到你的话了
"""
__plugin_des__ = "跨越空间与时间跟管理员对话"
__plugin_cmd__ = [
"滴滴滴-/[滴滴滴] ?[文本] ?[图片]",
"/t [_superuser]",
"t [qq] [group] [文本] [_superuser]",
"/t [qq] [文本] [_superuser]",
"/t -1 [group] [_superuser]",
"/t [id] [文本] [_superuser]",
]
__plugin_type__ = ("联系管理员",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["滴滴滴-", "滴滴滴"],
}
dialogue_data = {}
@@ -57,7 +94,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
"user_id": event.user_id,
"group_id": group_id,
"group_name": group_name,
"msg": f'{text} {img_msg}',
"msg": f"{text} {img_msg}",
}
# print(dialogue_data)
logger.info(f"Q{uid}@群{group_id} 联系管理员:{coffee} text:{text}")
@@ -66,22 +103,15 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@reply.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if msg in ["帮助"]:
await reply.finish(
f"/t [qq] [group] [text] -> 回复指定用户\n"
f"/t [qq] [text] -> 私聊用户\n"
f"/t -1 [group] -> 在某群发送消息\n"
f"/t [id] [text] -> 回复指定id的对话"
)
if not msg:
result = "*****待回复消息总览*****\n"
for key in dialogue_data.keys():
result += (
f'id:{key}\n'
f"id:{key}\n"
f'\t昵称:{dialogue_data[key]["nickname"]}({dialogue_data[key]["user_id"]})\n'
f'\t群群:{dialogue_data[key]["group_name"]}({dialogue_data[key]["group_id"]})\n'
f'\t消息:{dialogue_data[key]["msg"]}'
f'\n--------------------\n'
f"\n--------------------\n"
)
await reply.finish(Message(result[:-1]))
msg = msg.split()
+209 -84
View File
@@ -1,8 +1,13 @@
from nonebot import on_regex, on_keyword
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from .genshin_handle import genshin_draw, update_genshin_info, reset_count, reload_genshin_pool
from .genshin_handle import (
genshin_draw,
update_genshin_info,
reset_count,
reload_genshin_pool,
)
from .prts_handle import update_prts_info, prts_draw, reload_prts_pool
from .pretty_handle import update_pretty_info, pretty_draw, reload_pretty_pool
from .guardian_handle import update_guardian_info, guardian_draw
@@ -13,52 +18,164 @@ from .onmyoji_handle import update_onmyoji_info, onmyoji_draw
from .update_game_info import update_info
from .util import is_number, check_num
from .rule import is_switch
from .config import PRTS_FLAG, PRETTY_FLAG, GUARDIAN_FLAG, GENSHIN_FLAG, PCR_FLAG, AZUR_FLAG, FGO_FLAG, ONMYOJI_FLAG
from .config import (
PRTS_FLAG,
PRETTY_FLAG,
GUARDIAN_FLAG,
GENSHIN_FLAG,
PCR_FLAG,
AZUR_FLAG,
FGO_FLAG,
ONMYOJI_FLAG,
)
from .async_update_game_info import async_update_game
import re
import asyncio
from utils.utils import scheduler
from services.log import logger
__plugin_name__ = '游戏抽卡'
__zx_plugin_name__ = "游戏抽卡"
__plugin_usage__ = """
usage:
模拟赛马娘,原神,明日方舟,坎公骑冠剑,公主连结(国/台),碧蓝航线,FGO,阴阳师进行抽卡
指令:
原神[1-300]抽: 原神常驻池
原神角色[1-300]抽: 原神角色UP池子
原神武器[1-300]抽: 原神武器UP池子
重置原神抽卡: 清空当前卡池的抽卡次数[即从0开始计算UP概率]
方舟[1-300]抽: 方舟卡池,当有当期UP时指向UP池
赛马娘[1-200]抽: 赛马娘卡池,当有当期UP时指向UP池
坎公骑冠剑[1-300]抽: 坎公骑冠剑卡池,当有当期UP时指向UP池
pcr/公主连接[1-300]抽: 公主连接卡池
碧蓝航线/碧蓝[重型/轻型/特型][1-300]抽: 碧蓝航线重型/轻型/特型卡池
fgo[1-300]抽: fgo卡池
阴阳师[1-300]抽: 阴阳师卡池
* 以上指令可以通过 XX一井 来指定最大抽取数量 *
* 示例:原神一井 *
""".strip()
__plugin_superuser_usage__ = """
usage:
卡池方面的更新
指令:
更新方舟信息
重载方舟卡池
更新原神信息
重载原神卡池
更新赛马娘信息
重载赛马娘卡池
更新坎公骑冠剑信息
更新碧蓝航线信息
更新fgo信息
更新阴阳师信息
""".strip()
__plugin_des__ = "就算是模拟抽卡也不能改变自己是个非酋"
__plugin_cmd__ = [
"原神[1-300]抽",
"原神角色[1-300]抽",
"原神武器[1-300]抽",
"重置原神抽卡",
"方舟[1-300]抽",
"赛马娘[1-200]抽",
"坎公骑冠剑[1-300]抽",
"pcr/公主连接[1-300]抽",
"fgo[1-300]抽",
"阴阳师[1-300]抽",
"更新方舟信息 [_superuser]",
"重载方舟卡池 [_superuser]",
"更新原神信息 [_superuser]",
"重载原神卡池 [_superuser]",
"更新赛马娘信息 [_superuser]",
"重载赛马娘卡池 [_superuser]",
"更新坎公骑冠剑信息 [_superuser]",
"更新碧蓝航线信息 [_superuser]",
"更新fgo信息 [_superuser]",
"更新阴阳师信息 [_superuser]",
]
__plugin_type__ = ("抽卡相关", 1)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["游戏抽卡", "抽卡"],
}
prts = on_regex(r'.*?方舟[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('prts'), priority=5, block=True)
prts_update = on_keyword({'更新方舟信息', '更新明日方舟信息'}, permission=SUPERUSER, priority=1, block=True)
prts_up_reload = on_keyword({'重载方舟卡池'}, priority=1, block=True)
prts = on_regex(
r".*?方舟[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("prts"), priority=5, block=True
)
prts_update = on_keyword(
{"更新方舟信息", "更新明日方舟信息"}, permission=SUPERUSER, priority=1, block=True
)
prts_up_reload = on_keyword({"重载方舟卡池"}, priority=1, block=True)
genshin = on_regex('.*?原神(武器|角色)?池?[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('genshin'), priority=5, block=True)
genshin_update = on_keyword({'更新原神信息'}, permission=SUPERUSER, priority=1, block=True)
genshin_reset = on_keyword({'重置原神抽卡'}, priority=1, block=True)
genshin_up_reload = on_keyword({'重载原神卡池'}, priority=1, block=True)
genshin = on_regex(
".*?原神(武器|角色)?池?[1-9|一][0-9]{0,2}[抽|井]",
rule=is_switch("genshin"),
priority=5,
block=True,
)
genshin_update = on_keyword({"更新原神信息"}, permission=SUPERUSER, priority=1, block=True)
genshin_reset = on_keyword({"重置原神抽卡"}, priority=1, block=True)
genshin_up_reload = on_keyword({"重载原神卡池"}, priority=1, block=True)
pretty = on_regex('.*?马娘卡?[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('pretty'), priority=5, block=True)
pretty_update = on_keyword({'更新马娘信息', '更新赛马娘信息'}, permission=SUPERUSER, priority=1, block=True)
pretty_up_reload = on_keyword({'重载赛马娘卡池'}, priority=1, block=True)
pretty = on_regex(
".*?马娘卡?[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("pretty"), priority=5, block=True
)
pretty_update = on_keyword(
{"更新马娘信息", "更新赛马娘信息"}, permission=SUPERUSER, priority=1, block=True
)
pretty_up_reload = on_keyword({"重载赛马娘卡池"}, priority=1, block=True)
guardian = on_regex('.*?坎公骑冠剑武?器?[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('guardian'), priority=5, block=True)
guardian_update = on_keyword({'更新坎公骑冠剑信息'}, permission=SUPERUSER, priority=1, block=True)
guardian = on_regex(
".*?坎公骑冠剑武?器?[1-9|一][0-9]{0,2}[抽|井]",
rule=is_switch("guardian"),
priority=5,
block=True,
)
guardian_update = on_keyword(
{"更新坎公骑冠剑信息"}, permission=SUPERUSER, priority=1, block=True
)
pcr = on_regex('.*?(pcr|公主连结|公主连接|公主链接|公主焊接)[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('pcr'), priority=5, block=True)
pcr_update = on_keyword({'更新pcr信息', '更新公主连结信息'}, permission=SUPERUSER, priority=1, block=True)
pcr = on_regex(
".*?(pcr|公主连结|公主连接|公主链接|公主焊接)[1-9|一][0-9]{0,2}[抽|井]",
rule=is_switch("pcr"),
priority=5,
block=True,
)
pcr_update = on_keyword(
{"更新pcr信息", "更新公主连结信息"}, permission=SUPERUSER, priority=1, block=True
)
azur = on_regex('.*?碧蓝航?线?(轻型|重型|特型)池?[1-9|一][0-9]{0,2}[抽]', rule=is_switch('azur'), priority=5, block=True)
azur_update = on_keyword({'更新碧蓝信息', '更新碧蓝航线信息'}, permission=SUPERUSER, priority=1, block=True)
azur = on_regex(
".*?碧蓝航?线?(轻型|重型|特型)池?[1-9|一][0-9]{0,2}[抽]",
rule=is_switch("azur"),
priority=5,
block=True,
)
azur_update = on_keyword(
{"更新碧蓝信息", "更新碧蓝航线信息"}, permission=SUPERUSER, priority=1, block=True
)
fgo = on_regex('.*?fgo[1-9|一][0-9]{0,2}[抽]', rule=is_switch('fgo'), priority=5, block=True)
fgo_update = on_keyword({'更新fgo信息'}, permission=SUPERUSER, priority=1, block=True)
fgo = on_regex(
".*?fgo[1-9|一][0-9]{0,2}[抽]", rule=is_switch("fgo"), priority=5, block=True
)
fgo_update = on_keyword({"更新fgo信息"}, permission=SUPERUSER, priority=1, block=True)
onmyoji = on_regex('.*?阴阳师[1-9|一][0-9]{0,2}[抽]', rule=is_switch('onmyoji'), priority=5, block=True)
onmyoji_update = on_keyword({'更新阴阳师信息'}, permission=SUPERUSER, priority=1, block=True)
onmyoji = on_regex(
".*?阴阳师[1-9|一][0-9]{0,2}[抽]", rule=is_switch("onmyoji"), priority=5, block=True
)
onmyoji_update = on_keyword({"更新阴阳师信息"}, permission=SUPERUSER, priority=1, block=True)
@prts.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = str(event.get_message()).strip()
if msg in ['方舟一井', '方舟1井']:
if msg in ["方舟一井", "方舟1井"]:
num = 300
else:
rmsg = re.search(r'.*?方舟(.*)抽', msg)
rmsg = re.search(r".*?方舟(.*)抽", msg)
if rmsg:
num, flag = check_num(rmsg.group(1), 300)
if not flag:
@@ -67,29 +184,30 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
return
await prts.send(await prts_draw(int(num)), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 方舟 {num}抽")
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 方舟 {num}抽"
)
@prts_up_reload.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
text = await reload_prts_pool()
await prts_up_reload.finish(Message(f'重载完成!\n{text}'))
await prts_up_reload.finish(Message(f"重载完成!\n{text}"))
@genshin.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = str(event.get_message()).strip()
rmsg = re.search(r'.*?原神(武器|角色)?池?(.*)[抽|井]', msg)
rmsg = re.search(r".*?原神(武器|角色)?池?(.*)[抽|井]", msg)
if rmsg:
pool_name = rmsg.group(1)
if pool_name == '武器':
pool_name = 'arms'
elif pool_name == '角色':
pool_name = 'char'
if pool_name == "武器":
pool_name = "arms"
elif pool_name == "角色":
pool_name = "char"
else:
pool_name = ''
pool_name = ""
num = rmsg.group(2)
if msg.find('一井') != -1 or msg.find('1井') != -1:
if msg.find("一井") != -1 or msg.find("1井") != -1:
num = 180
else:
num, flag = check_num(num, 180)
@@ -97,41 +215,44 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
await genshin.finish(num, at_sender=True)
else:
return
await genshin.send(await genshin_draw(event.user_id, int(num), pool_name), at_sender=True)
await genshin.send(
await genshin_draw(event.user_id, int(num), pool_name), at_sender=True
)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 原神 {num}抽")
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 原神 {num}抽"
)
@genshin_up_reload.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
text = await reload_genshin_pool()
await genshin_reset.finish(Message(f'重载成功!\n{text}'))
await genshin_reset.finish(Message(f"重载成功!\n{text}"))
@genshin_reset.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
reset_count(event.user_id)
await genshin_reset.send('重置了原神抽卡次数', at_sender=True)
await genshin_reset.send("重置了原神抽卡次数", at_sender=True)
@pretty.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = str(event.get_message()).strip()
if msg.find('1井') != -1 or msg.find('一井') != -1:
if msg.find("1井") != -1 or msg.find("一井") != -1:
num = 200
if msg.find("卡") == -1:
pool_name = 'char'
pool_name = "char"
else:
pool_name = 'card'
pool_name = "card"
else:
rmsg = re.search(r'.*?马娘(.*)抽', msg)
rmsg = re.search(r".*?马娘(.*)抽", msg)
if rmsg:
num = rmsg.group(1)
if num[0] == '卡':
if num[0] == "卡":
num = num[1:]
pool_name = 'card'
pool_name = "card"
else:
pool_name = 'char'
pool_name = "char"
num, flag = check_num(num, 200)
if not flag:
await pretty.finish(num, at_sender=True)
@@ -139,30 +260,31 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
return
await pretty.send(await pretty_draw(int(num), pool_name), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 赛马娘 {num}抽")
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 赛马娘 {num}抽"
)
@pretty_up_reload.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
text = await reload_pretty_pool()
await genshin_reset.finish(Message(f'重载成功!\n{text}'))
await genshin_reset.finish(Message(f"重载成功!\n{text}"))
@guardian.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = str(event.get_message()).strip()
pool_name = 'char'
if msg.find('1井') != -1 or msg.find('一井') != -1:
pool_name = "char"
if msg.find("1井") != -1 or msg.find("一井") != -1:
num = 300
if msg.find('武器') != -1:
pool_name = 'arms'
if msg.find("武器") != -1:
pool_name = "arms"
else:
rmsg = re.search(r'.*?坎公骑冠剑(.*)抽', msg)
rmsg = re.search(r".*?坎公骑冠剑(.*)抽", msg)
if rmsg:
num = rmsg.group(1)
if num.find('武器') != -1:
pool_name = 'arms'
num = num.replace('武器', '')
if num.find("武器") != -1:
pool_name = "arms"
num = num.replace("武器", "")
num, flag = check_num(num, 300)
if not flag:
await guardian.finish(num, at_sender=True)
@@ -170,16 +292,17 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
return
await guardian.send(await guardian_draw(int(num), pool_name), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 坎公骑冠剑 {num}抽")
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 坎公骑冠剑 {num}抽"
)
@pcr.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = str(event.get_message()).strip()
if msg.find('1井') != -1 or msg.find('一井') != -1:
if msg.find("1井") != -1 or msg.find("一井") != -1:
num = 300
else:
rmsg = re.search(r'.*?(pcr|公主连结)(.*)[抽|井]', msg)
rmsg = re.search(r".*?(pcr|公主连结)(.*)[抽|井]", msg)
if rmsg:
num, flag = check_num(rmsg.group(2), 300)
if not flag:
@@ -188,13 +311,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
return
await pcr.send(await pcr_draw(int(num)), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 公主连结 {num}抽")
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 公主连结 {num}抽"
)
@azur.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = str(event.get_message()).strip()
rmsg = re.search('.*?碧蓝航?线?(轻型|重型|特型)池?(.*)[抽]', msg)
rmsg = re.search(".*?碧蓝航?线?(轻型|重型|特型)池?(.*)[抽]", msg)
if rmsg:
pool_name = rmsg.group(1)
num, flag = check_num(rmsg.group(2), 300)
@@ -204,13 +328,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
return
await azur.send(await azur_draw(int(num), pool_name), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 碧蓝航线 {num}抽")
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 碧蓝航线 {num}抽"
)
@fgo.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = str(event.get_message()).strip()
rmsg = re.search('.*?fgo(.*)抽', msg)
rmsg = re.search(".*?fgo(.*)抽", msg)
if rmsg:
num, flag = check_num(rmsg.group(1), 300)
if not flag:
@@ -219,13 +344,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
return
await fgo.send(await fgo_draw(int(num)), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) fgo {num}抽")
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) fgo {num}抽"
)
@onmyoji.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = str(event.get_message()).strip()
rmsg = re.search('.*?阴阳师(.*)抽', msg)
rmsg = re.search(".*?阴阳师(.*)抽", msg)
if rmsg:
num, flag = check_num(rmsg.group(1), 300)
if not flag:
@@ -234,60 +360,61 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
return
await onmyoji.send(await onmyoji_draw(int(num)), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 阴阳师 {num}抽")
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 阴阳师 {num}抽"
)
@prts_update.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await update_prts_info()
await prts_update.finish('更新完成!')
await prts_update.finish("更新完成!")
@genshin_update.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await update_genshin_info()
await genshin_update.finish('更新完成!')
await genshin_update.finish("更新完成!")
@pretty_update.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await update_pretty_info()
await genshin_update.finish('更新完成!')
await genshin_update.finish("更新完成!")
@guardian_update.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await update_guardian_info()
await genshin_update.finish('更新完成!')
await genshin_update.finish("更新完成!")
@pcr_update.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await update_pcr_info()
await genshin_update.finish('更新完成!')
await genshin_update.finish("更新完成!")
@azur_update.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await update_azur_info()
await genshin_update.finish('更新完成!')
await genshin_update.finish("更新完成!")
@fgo_update.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await update_fgo_info()
await genshin_update.finish('更新完成!')
await genshin_update.finish("更新完成!")
@onmyoji_update.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await update_onmyoji_info()
await genshin_update.finish('更新完成!')
await genshin_update.finish("更新完成!")
# 更新资源
@scheduler.scheduled_job(
'cron',
"cron",
hour=4,
minute=1,
)
@@ -310,42 +437,40 @@ async def _():
if ONMYOJI_FLAG:
tasks.append(asyncio.ensure_future(update_onmyoji_info()))
await asyncio.gather(*tasks)
logger.info('draw_card 抽卡自动更新完成...')
logger.info("draw_card 抽卡自动更新完成...")
# 每天四点重载方舟up卡池
@scheduler.scheduled_job(
'cron',
"cron",
hour=4,
minute=1,
)
async def _():
if PRTS_FLAG:
await reload_prts_pool()
logger.info('自动重载方舟卡池UP成功')
logger.info("自动重载方舟卡池UP成功")
# 每天四点重载赛马娘up卡池
@scheduler.scheduled_job(
'cron',
"cron",
hour=4,
minute=1,
)
async def _():
if PRETTY_FLAG:
await reload_pretty_pool()
logger.info('自动重载赛马娘UP成功')
logger.info("自动重载赛马娘UP成功")
# 每天下午六点点重载原神up卡池
@scheduler.scheduled_job(
'cron',
"cron",
hour=18,
minute=1,
)
async def _():
if PRTS_FLAG:
await reload_genshin_pool()
logger.info('自动重载原神卡池UP成功')
logger.info("自动重载原神卡池UP成功")
+6 -1
View File
@@ -1,7 +1,7 @@
import aiohttp
from bs4 import BeautifulSoup
import re
from datetime import datetime
from datetime import datetime, timedelta
from .config import DRAW_PATH
from pathlib import Path
from asyncio.exceptions import TimeoutError
@@ -177,6 +177,11 @@ class GenshinAnnouncement:
data[itype]['time'] = trs[1].find('td').text
if data[itype]['time'][-1] == '\n':
data[itype]['time'] = data[itype]['time'][:-1]
if '版本更新后' in data[itype]['time']:
sp = data[itype]['time'].split('~')
end_time = datetime.strptime(sp[1].strip(), "%Y/%m/%d %H:%M:%S")
start_time = end_time - timedelta(days=20)
data[itype]['time'] = start_time.strftime('%Y/%m/%d') + ' ~ ' + end_time.strftime('%Y/%m/%d')
tmp = ''
for tm in data[itype]['time'].split('~'):
date_time_sp = tm.split('/')
+7 -5
View File
@@ -1,5 +1,6 @@
from typing import Any
from .config import DATA_PATH
from utils.utils import is_number
from pathlib import Path
try:
import ujson as json
@@ -65,11 +66,12 @@ def init_game_pool(game: str, data: dict, Operator: Any):
tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), limited=limited))
if game == 'azur':
for key in data.keys():
limited = False
if '可以建造' not in data[key]['获取途径']:
limited = True
tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']),
limited=limited, itype=data[key]['类型']))
if is_number(data[key]['星级']):
limited = False
if '可以建造' not in data[key]['获取途径']:
limited = True
tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']),
limited=limited, itype=data[key]['类型']))
if game in ['fgo', 'fgo_card']:
for key in data.keys():
limited = False
+18 -23
View File
@@ -1,42 +1,37 @@
from nonebot.rule import Rule
from nonebot.adapters.cqhttp import Bot, MessageEvent
from nonebot.typing import T_State
from .config import GENSHIN_FLAG, PRTS_FLAG, PRETTY_FLAG, GUARDIAN_FLAG, PCR_FLAG, AZUR_FLAG, FGO_FLAG, ONMYOJI_FLAG
from .config import (
GENSHIN_FLAG,
PRTS_FLAG,
PRETTY_FLAG,
GUARDIAN_FLAG,
PCR_FLAG,
AZUR_FLAG,
FGO_FLAG,
ONMYOJI_FLAG,
)
def is_switch(game_name: str) -> Rule:
async def _is_switch(bot: Bot, event: MessageEvent, state: T_State) -> bool:
if game_name == 'prts':
if game_name == "prts":
return PRTS_FLAG
if game_name == 'genshin':
if game_name == "genshin":
return GENSHIN_FLAG
if game_name == 'pretty':
if game_name == "pretty":
return PRETTY_FLAG
if game_name == 'guardian':
if game_name == "guardian":
return GUARDIAN_FLAG
if game_name == 'pcr':
if game_name == "pcr":
return PCR_FLAG
if game_name == 'azur':
if game_name == "azur":
return AZUR_FLAG
if game_name == 'fgo':
if game_name == "fgo":
return FGO_FLAG
if game_name == 'onmyoji':
if game_name == "onmyoji":
return ONMYOJI_FLAG
else:
return False
return Rule(_is_switch)
+6 -2
View File
@@ -83,6 +83,8 @@ async def _last_check(data: dict, game_name: str, session: aiohttp.ClientSession
'-舰娘头像外框精锐.png',
'https://patchwiki.biligame.com/images/blhx/thumb/a/a2/ptog1j220x5q02hytpwc8al7f229qk9.png/60px-'
'舰娘头像外框超稀有.png'
'https://patchwiki.biligame.com/images/blhx/thumb/0/0f/n28p7p3opfn5mhgjyio55ljsllhknwz.png/60px-'
'舰娘头像外框精锐META.png'
]:
await download_img(url, 'azur', f'{idx}_star')
idx += 1
@@ -135,7 +137,7 @@ async def retrieve_char_data(char: bs4.element.Tag, game_name: str, data: dict,
member_dict['头像'] = unquote(str(avatar_img['src']).split(' ')[-2])
except TypeError:
member_dict['头像'] = "img link not find..."
logger(f'{member_dict["名称"]} 图片缺失....')
logger.warning(f'{member_dict["名称"]} 图片缺失....')
star = char.find('div').find('img')['alt']
if star == '舰娘头像外框普通.png':
star = 1
@@ -147,7 +149,9 @@ async def retrieve_char_data(char: bs4.element.Tag, game_name: str, data: dict,
star = 4
elif star == '舰娘头像外框海上传奇.png':
star = 5
elif star in ['舰娘头像外框最高方案.png', '舰娘头像外框决战方案.png', '舰娘头像外框超稀有META.png']:
elif star in ['舰娘头像外框最高方案.png', '舰娘头像外框决战方案.png', '舰娘头像外框超稀有META.png', '舰娘头像外框精锐META.png']:
star = 6
else:
star = 6
member_dict['星级'] = star
member_dict['类型'] = azur_type[str(index)]
+39 -18
View File
@@ -3,22 +3,41 @@ from services.log import logger
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State
from utils.utils import scheduler, get_bot
from .data_source import get_epic_game
from models.group_remind import GroupRemind
from nonebot.adapters.cqhttp.exception import ActionFailed
__plugin_name__ = "epic免费游戏提醒"
__plugin_usage__ = "用法:发送’epic‘"
from .data_source import get_epic_free
from utils.manager import group_manager
__zx_plugin_name__ = "epic免费游戏"
__plugin_usage__ = """
usage:
可以不玩,不能没有,每日白嫖
指令:
epic
""".strip()
__plugin_des__ = "可以不玩,不能没有,每日白嫖"
__plugin_cmd__ = ["epic"]
__plugin_version__ = 0.1
__plugin_author__ = "AkashiCoin"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["epic"],
}
__plugin_task__ = {"epic_free_game": "epic免费游戏"}
epic = on_command("epic", priority=5, block=True)
@epic.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
result, code = await get_epic_game()
await epic.send(result)
async def handle(bot: Bot, event: MessageEvent, state: T_State):
msg_list, code = await get_epic_free(bot, event)
if code == 404:
await epic.send(msg_list)
elif isinstance(event, GroupMessageEvent):
await bot.send_group_forward_msg(group_id=event.group_id, messages=msg_list)
else:
for msg in msg_list:
await bot.send_private_msg(user_id=event.user_id, message=msg)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 获取epic免费游戏"
@@ -33,13 +52,15 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
)
async def _():
bot = get_bot()
gl = await bot.get_group_list(self_id=bot.self_id)
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
if await GroupRemind.get_status(g, "epic"):
result, code = await get_epic_game()
if code == 200:
try:
await bot.send_group_msg(group_id=g, message=result)
except ActionFailed:
logger.error(f"{g}群 epic免费游戏推送错误")
if await group_manager.check_group_task_status(g, "epic_free_game"):
try:
msg_list, code = await get_epic_free(bot, GroupMessageEvent)
if code == 200:
await bot.send_group_forward_msg(group_id=g, messages=msg_list)
else:
await bot.send_group_msg(group_id=g, message=msg_list)
except Exception as e:
logger.error(f"GROUP {g} epic免费游戏推送错误 {type(e)}: {e}")
+154 -51
View File
@@ -1,56 +1,159 @@
import aiohttp
import aiofiles
from utils.utils import get_local_proxy
import feedparser
import platform
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from utils.user_agent import get_user_agent
from asyncio.exceptions import TimeoutError
from configs.config import RSSHUBAPP
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
from httpx import AsyncClient
from datetime import datetime
from nonebot.log import logger
from nonebot.adapters.cqhttp import (
Bot,
Event,
GroupMessageEvent,
)
from configs.config import NICKNAME
url = f"{RSSHUBAPP}/epicgames/freegames"
# 获取所有 Epic Game Store 促销游戏
# 方法参考:RSSHub /epicgames 路由
# https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js
async def get_epic_game():
epic_url = "https://www.epicgames.com/store/backend/graphql-proxy"
headers = {
"Referer": "https://www.epicgames.com/store/zh-CN/",
"Content-Type": "application/json; charset=utf-8",
}
data = {
"query": "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, $keywords: String, $locale: String, $namespace: String, $sortBy: String, $sortDir: String, $start: Int, $tag: String, $withPrice: Boolean = false, $withPromotions: Boolean = false) {\n Catalog {\n searchStore(allowCountries: $allowCountries, category: $category, count: $count, country: $country, keywords: $keywords, locale: $locale, namespace: $namespace, sortBy: $sortBy, sortDir: $sortDir, start: $start, tag: $tag) {\n elements {\n title\n id\n namespace\n description\n effectiveDate\n keyImages {\n type\n url\n }\n seller {\n id\n name\n }\n productSlug\n urlSlug\n url\n items {\n id\n namespace\n }\n customAttributes {\n key\n value\n }\n categories {\n path\n }\n price(country: $country) @include(if: $withPrice) {\n totalPrice {\n discountPrice\n originalPrice\n voucherDiscount\n discount\n currencyCode\n currencyInfo {\n decimals\n }\n fmtPrice(locale: $locale) {\n originalPrice\n discountPrice\n intermediatePrice\n }\n }\n lineOffers {\n appliedRules {\n id\n endDate\n discountSetting {\n discountType\n }\n }\n }\n }\n promotions(category: $category) @include(if: $withPromotions) {\n promotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n upcomingPromotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n }\n }\n paging {\n count\n total\n }\n }\n }\n}\n",
"variables": {
"allowCountries": "CN",
"category": "freegames",
"count": 1000,
"country": "CN",
"locale": "zh-CN",
"sortBy": "effectiveDate",
"sortDir": "asc",
"withPrice": True,
"withPromotions": True,
},
}
async with AsyncClient(headers=headers) as client:
try:
res = await client.post(epic_url, json=data, timeout=10.0)
res_json = res.json()
games = res_json["data"]["Catalog"]["searchStore"]["elements"]
return games
except Exception as e:
logger.error(str(e))
return None
async def get_epic_game() -> "str, int":
result = "今天没有游戏可以白嫖了!"
code = 999
try:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(url, proxy=get_local_proxy(), timeout=7) as response:
data = feedparser.parse(await response.text())["entries"]
if len(data) == 0:
return result
index = 0
for item in data:
title = item["title"]
img_url = item["summary"][
item["summary"].find('src="') + 5 : item["summary"].rfind('"')
]
async with session.get(
img_url, proxy=get_local_proxy(), timeout=7
) as res:
async with aiofiles.open(
IMAGE_PATH + f"temp/epic_{index}.jpg", "wb"
) as f:
await f.write(await res.read())
link = item["link"]
result += (
image(f"epic_{index}.jpg", "temp")
+ f"\n【游戏】| {title}\n【链接】 | {link}\n"
# 获取 Epic Game Store 免费游戏信息
# 处理免费游戏的信息方法借鉴 pip 包 epicstore_api 示例
# https://github.com/SD4RK/epicstore_api/blob/master/examples/free_games_example.py
async def get_epic_free(bot: Bot, event: Event):
games = await get_epic_game()
if not games:
return "Epic 可能又抽风啦,请稍后再试(", 404
else:
msg_list = []
for game in games:
game_name = game["title"]
game_corp = game["seller"]["name"]
game_price = game["price"]["totalPrice"]["fmtPrice"]["originalPrice"]
# 赋初值以避免 local variable referenced before assignment
game_dev, game_pub, game_thumbnail = (None, None, None)
try:
game_promotions = game["promotions"]["promotionalOffers"]
upcoming_promotions = game["promotions"]["upcomingPromotionalOffers"]
if not game_promotions and upcoming_promotions:
# 促销暂未上线,但即将上线
promotion_data = upcoming_promotions[0]["promotionalOffers"][0]
start_date_iso, end_date_iso = (
promotion_data["startDate"][:-1],
promotion_data["endDate"][:-1],
)
code = 200
index += 1
if result != "":
result = "epic限免游戏(速速白嫖):\n" + result
else:
result = "今天没有游戏可以白嫖了!"
except TimeoutError:
return "请求超时!", code
return result, code
# 删除字符串中最后一个 "Z" 使 Python datetime 可处理此时间
start_date = datetime.fromisoformat(start_date_iso).strftime(
"%b.%d %H:%M"
)
end_date = datetime.fromisoformat(end_date_iso).strftime(
"%b.%d %H:%M"
)
if isinstance(event, GroupMessageEvent):
_message = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format(
game_corp, game_name, game_price, start_date, end_date
)
data = {
"type": "node",
"data": {
"name": f"这里是{NICKNAME}酱",
"uin": f"{bot.self_id}",
"content": _message,
},
}
msg_list.append(data)
else:
msg = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format(
game_corp, game_name, game_price, start_date, end_date
)
msg_list.append(msg)
else:
for image in game["keyImages"]:
if image["type"] == "Thumbnail":
game_thumbnail = image["url"]
for pair in game["customAttributes"]:
if pair["key"] == "developerName":
game_dev = pair["value"]
if pair["key"] == "publisherName":
game_pub = pair["value"]
# 如 game['customAttributes'] 未找到则均使用 game_corp 值
game_dev = game_dev if game_dev is not None else game_corp
game_pub = game_pub if game_pub is not None else game_corp
game_desp = game["description"]
end_date_iso = game["promotions"]["promotionalOffers"][0][
"promotionalOffers"
][0]["endDate"][:-1]
end_date = datetime.fromisoformat(end_date_iso).strftime(
"%b.%d %H:%M"
)
# API 返回不包含游戏商店 URL,此处自行拼接,可能出现少数游戏 404 请反馈
game_url_part = (
(game["productSlug"].replace("/home", ""))
if ("/home" in game["productSlug"])
else game["productSlug"]
)
game_url = "https://www.epicgames.com/store/zh-CN/p/{}".format(
game_url_part
)
if isinstance(event, GroupMessageEvent):
_message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format(
game_thumbnail,
game_name,
game_price,
game_desp,
game_dev,
game_pub,
end_date,
game_url,
)
data = {
"type": "node",
"data": {
"name": f"这里是{NICKNAME}酱",
"uin": f"{bot.self_id}",
"content": _message,
},
}
msg_list.append(data)
else:
msg = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format(
game_thumbnail,
game_name,
game_price,
game_desp,
game_dev,
game_pub,
end_date,
game_url,
)
msg_list.append(msg)
except TypeError as e:
# logger.info(str(e))
pass
return msg_list, 200
+18 -6
View File
@@ -6,12 +6,24 @@ from utils.message_builder import share
from services.log import logger
__plugin_name = "假消息"
__plugin_usage__ = (
"用法:\n格式:假消息 [网址] [标题] [内容](可省) [图片](可省)\n"
"示例:假消息 www.4399.com 我喜欢萝莉 为什么我喜欢... [图片]"
)
__zx_plugin_name__ = "构造分享消息"
__plugin_usage__ = """
usage:
自定义的分享消息构造
指令:
假消息 [网址] [标题] ?[内容] ?[图片]
示例:假消息 www.4399.com 我喜欢萝莉 为什么我喜欢... [图片]
""".strip()
__plugin_des__ = "自定义的分享消息构造"
__plugin_cmd__ = ["假消息 [网址] [标题] ?[内容] ?[图片]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["假消息"],
}
fake_msg = on_command("假消息", priority=5, block=True)
+40 -22
View File
@@ -9,9 +9,21 @@ from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
import aiohttp
import aiofiles
from collections import defaultdict
from asyncio.exceptions import TimeoutError
from configs.config import FUDU_PROBABILITY
from utils.manager import group_manager
__zx_plugin_name__ = "复读"
__plugin_usage__ = """
usage:
重复3次相同的消息时会复读
""".strip()
__plugin_des__ = "群友的本质是什么?是复读机哒!"
__plugin_type__ = ("被动相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"fudu": "复读"}
class Fudu:
@@ -20,39 +32,39 @@ class Fudu:
def append(self, key, content):
self._create(key)
self.data[key]['data'].append(content)
self.data[key]["data"].append(content)
def clear(self, key):
self._create(key)
self.data[key]['data'] = []
self.data[key]['is_repeater'] = False
self.data[key]["data"] = []
self.data[key]["is_repeater"] = False
def size(self, key) -> int:
self._create(key)
return len(self.data[key]['data'])
return len(self.data[key]["data"])
def check(self, key, content) -> bool:
self._create(key)
return self.data[key]['data'][0] == content
return self.data[key]["data"][0] == content
def get(self, key):
self._create(key)
return self.data[key]['data'][0]
return self.data[key]["data"][0]
def is_repeater(self, key):
self._create(key)
return self.data[key]['is_repeater']
return self.data[key]["is_repeater"]
def set_repeater(self, key):
self._create(key)
self.data[key]['is_repeater'] = True
self.data[key]["is_repeater"] = True
def _create(self, key):
if self.data.get(key) is None:
self.data[key] = {'is_repeater': False, 'data': []}
self.data[key] = {"is_repeater": False, "data": []}
_fudulist = Fudu()
_fudu_list = Fudu()
fudu = on_message(permission=GROUP, priority=9)
@@ -60,7 +72,11 @@ fudu = on_message(permission=GROUP, priority=9)
@fudu.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if event.is_tome() or state["_prefix"]["raw_command"]:
if (
event.is_tome()
or state["_prefix"]["raw_command"]
or not await group_manager.check_group_task_status(event.group_id, "fudu")
):
return
if get_message_text(event.json()):
if get_message_text(event.json()).find("@可爱的小真寻") != -1:
@@ -74,17 +90,20 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
else:
img_hash = ""
add_msg = msg + "|-|" + img_hash
if _fudulist.size(event.group_id) == 0:
_fudulist.append(event.group_id, add_msg)
elif _fudulist.check(event.group_id, add_msg):
_fudulist.append(event.group_id, add_msg)
if _fudu_list.size(event.group_id) == 0:
_fudu_list.append(event.group_id, add_msg)
elif _fudu_list.check(event.group_id, add_msg):
_fudu_list.append(event.group_id, add_msg)
else:
_fudulist.clear(event.group_id)
_fudulist.append(event.group_id, add_msg)
if _fudulist.size(event.group_id) > 2:
if random.random() < FUDU_PROBABILITY and not _fudulist.is_repeater(event.group_id):
_fudu_list.clear(event.group_id)
_fudu_list.append(event.group_id, add_msg)
if _fudu_list.size(event.group_id) > 2:
if random.random() < FUDU_PROBABILITY and not _fudu_list.is_repeater(
event.group_id
):
if random.random() < 0.2:
await fudu.finish("打断施法!")
_fudu_list.set_repeater(event.group_id)
if imgs and msg:
rst = msg + image(f"compare_{event.group_id}_img.jpg", "temp")
elif imgs:
@@ -95,7 +114,6 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
rst = ""
if rst:
await fudu.send(rst)
_fudulist.set_repeater(event.group_id)
async def get_fudu_img_hash(url, group_id):
@@ -109,4 +127,4 @@ async def get_fudu_img_hash(url, group_id):
img_hash = get_img_hash(IMAGE_PATH + f"temp/compare_{group_id}_img.jpg")
return str(img_hash)
except TimeoutError:
return ''
return ""
+3
View File
@@ -0,0 +1,3 @@
import nonebot
nonebot.load_plugins("plugins/genshin")
+37 -24
View File
@@ -1,25 +1,44 @@
from .alc import get_almanac_base64_str, load_data
import os
from utils.utils import get_bot, scheduler
from nonebot import on_command
from models.level_user import LevelUser
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
from utils.message_builder import image
from services.log import logger
from models.group_remind import GroupRemind
from configs.path_config import IMAGE_PATH
from .data_source import get_alc_image
from utils.manager import group_manager
from pathlib import Path
FILE_PATH = os.path.dirname(__file__)
__zx_plugin_name__ = "原神老黄历"
__plugin_usage__ = """
usage:
有时候也该迷信一回!特别是运气方面
指令:
原神黄历
""".strip()
__plugin_des__ = "有时候也该迷信一回!特别是运气方面"
__plugin_cmd__ = ["原神黄历"]
__plugin_type__ = ("原神相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["原神黄历", "原神老黄历"],
}
__plugin_task__ = {"genshin_alc": "原神黄历提醒"}
almanac = on_command("原神黄历", priority=5, block=True)
reload = on_command("重载原神黄历数据", priority=5, block=True)
ALC_PATH = Path(IMAGE_PATH) / "genshin" / "alc"
ALC_PATH.mkdir(parents=True, exist_ok=True)
@almanac.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
almanac_base64 = get_almanac_base64_str()
mes = image(b64=almanac_base64) + "\n ※ 黄历数据来源于 genshin.pub"
alc_img = await get_alc_image(ALC_PATH)
mes = alc_img + "\n ※ 黄历数据来源于 genshin.pub"
await almanac.send(mes)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
@@ -27,13 +46,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
)
@reload.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if await LevelUser.check_level(event.user_id, event.group_id, 5):
load_data()
await reload.send("重载成功")
@scheduler.scheduled_job(
"cron",
hour=10,
@@ -42,10 +54,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
async def _():
# 每日提醒
bot = get_bot()
gl = await bot.get_group_list(self_id=bot.self_id)
gl = [g["group_id"] for g in gl]
almanac_base64 = get_almanac_base64_str()
mes = image(b64=almanac_base64) + "\n ※ 黄历数据来源于 genshin.pub"
for gid in gl:
if await GroupRemind.get_status(gid, "almanac"):
await bot.send_group_msg(group_id=int(gid), message=mes)
if bot:
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
alc_img = await get_alc_image(ALC_PATH)
mes = alc_img + "\n ※ 黄历数据来源于 genshin.pub"
for gid in gl:
if await group_manager.check_group_task_status(gid, "genshin_alc"):
await bot.send_group_msg(group_id=int(gid), message=mes)
-123
View File
@@ -1,123 +0,0 @@
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
import os
import json
import random
import base64
import time
FILE_PATH = os.path.dirname(__file__)
FONT_PATH = os.path.join(FILE_PATH, "汉仪文黑.ttf")
data = {} # configs.json里的数据
almanac_data = {
# 生成的黄历base64字符串和黄历更新日期
"date": "",
"almanac_base64_str": ""
}
chinese = {"0": "", "1": "一", "2": "二", "3": "三", "4": "四", "5": "五", "6": "六", "7": "七", "8": "八", "9": "九"}
def month_to_chinese(month: str):
# 把日期数字转成中文数字
m = int(month)
if m < 10:
return chinese[month[-1]]
elif m < 20:
return "十" + chinese[month[-1]]
else:
return chinese[month[0]] + "十" + chinese[month[-1]]
def load_data():
# 载入config.json文件的数据
global data
with open(os.path.join(FILE_PATH, 'config.json'), 'r', encoding='UTF-8') as f:
data = json.load(f)
almanac_data["date"] = ""
almanac_data["almanac_base64_str"] = ""
load_data()
def seed_random_list(seed: str, l: list):
# 使用随机种子随机选择列表中的元素,相同的种子和列表将返回同样的输出
seed = seed + str(l)
random.seed(seed)
index = random.random() * len(l)
return l[int(index)]
def generate_almanac():
# 生成黄历图片,然后转换成base64保存到 almanac_data["almanac_base64_str"]
seed = time.strftime("%Y-%m-%d")
offset = 1
today_luck = []
l = list(data.keys())
while len(today_luck) < 6:
# 随机6个不同的运势放到 today_luck
r = seed_random_list(str(offset) + seed, l)
if r in today_luck:
offset += 1
else:
today_luck.append(r)
back = Image.open(os.path.join(FILE_PATH, "back.png"))
year = time.strftime("%Y")
month = month_to_chinese(time.strftime("%m")) + "月"
day = month_to_chinese(time.strftime("%d")) + "日"
draw = ImageDraw.Draw(back)
draw.text((118, 165), year, fill="#8d7650ff", font=ImageFont.truetype(FONT_PATH, size=30), anchor="mm",
align="center")
draw.text((260, 165), day, fill="#f7f8f2ff", font=ImageFont.truetype(FONT_PATH, size=35), anchor="mm",
align="center")
draw.text((410, 165), month, fill="#8d7650ff", font=ImageFont.truetype(FONT_PATH, size=30), anchor="mm",
align="center")
buff = Image.new("RGBA", (325, 160))
debuff = Image.new("RGBA", (325, 160))
buff_draw = ImageDraw.Draw(buff)
debuff_draw = ImageDraw.Draw(debuff)
for i in range(3):
buff_name = today_luck[i]
debuff_name = today_luck[(i + 3)]
buff_effect = seed_random_list(seed, data[buff_name]["buff"])
debuff_effect = seed_random_list(seed, data[debuff_name]["debuff"])
buff_draw.text((0, i * 53), buff_name, fill="#756141ff", font=ImageFont.truetype(FONT_PATH, size=25))
debuff_draw.text((0, i * 53), debuff_name, fill="#756141ff", font=ImageFont.truetype(FONT_PATH, size=25))
buff_draw.text((0, i * 53 + 28), buff_effect, fill="#b5b3acff", font=ImageFont.truetype(FONT_PATH, size=19))
debuff_draw.text((0, i * 53 + 28), debuff_effect, fill="#b5b3acff", font=ImageFont.truetype(FONT_PATH, size=19))
back.paste(buff, (150, 230), buff)
back.paste(debuff, (150, 400), debuff)
bio = BytesIO()
back.save(bio, format='PNG')
base64_str = base64.b64encode(bio.getvalue()).decode()
almanac_data["date"] = time.strftime("%Y-%m-%d")
almanac_data["almanac_base64_str"] = 'base64://' + base64_str
def get_almanac_base64_str():
# if almanac_data["date"] == time.strftime("%Y-%m-%d"):
# return almanac_data["almanac_base64_str"]
# else:
# generate_almanac()
# return almanac_data["almanac_base64_str"]
generate_almanac()
return almanac_data["almanac_base64_str"]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

-70
View File
@@ -1,70 +0,0 @@
{
"抽卡":{
"buff": ["欧气满满,十连出金","出金不歪"],
"debuff": ["武器大师","保底出金","金色会是痛苦大剑"]
},
"刷世界boss":{
"buff": ["双攻双爆角斗士"],
"debuff": ["只有保底材料","贪生怕死角斗士"]
},
"刷风本":{
"buff": ["会有极品猎人套","会掉真正的少女心","治疗加成少女头"],
"debuff": ["勇往直前少女心","少女飘摇的杀意","少女暴怒的容颜"]
},
"刷火本":{
"buff": ["魔女帽子火伤杯","暴伤魔女帽!","火伤魔女心!"],
"debuff": ["幡 然 醒 悟","这么阴间的地方真的会有魔女套吗?","不务正业火魔女","会匹配到3个卢姥爷"]
},
"刷岩本":{
"buff": ["悠久的磐岩伴你左右","岩神的庇护常在"],
"debuff": ["防御流星杯,你值得拥有"]
},
"刷宗室":{
"buff": ["物理伤害骑士道,元素精通宗室套"],
"debuff": ["贪生怕死骑士道,物理伤害宗室杯"]
},
"刷冰本":{
"buff": ["双暴词条概率up"],
"debuff": ["防御力船帽,无人可及"]
},
"刷雷本":{
"buff": ["愿雷鸟伴你左右"],
"debuff": ["来表演一个只掉平雷套的绝活","风神忽悠雷凶兆"]
},
"锄大地":{
"buff": ["会掉一大堆紫色材料"],
"debuff": ["深渊法师爱你哟","会被冰水法控到死"]
},
"挖矿":{
"buff": ["开矿出双材料"],
"debuff": ["去别人世界会被拒"]
},
"刷天赋本":{
"buff": ["金色!我看到了金色的书!"],
"debuff": ["2蓝2绿不会变"]
},
"刷突破材料":{
"buff": ["金色!我看到了金色的材料!"],
"debuff": ["2蓝2绿不会变"]
},
"升级圣遗物":{
"buff": ["稀有词条跳跳跳","会双爆拉满"],
"debuff": ["女 仆 狂 喜","无中生有防御力","生命拉满","完美避开双爆"]
},
"打风魔龙":{
"buff": ["看我一箭一个风魔鸡","今天特瓦林可以给想要的突破材料","5金加原胚!"],
"debuff": ["会不小心掉下平台","不小心被地板烫死了"]
},
"打狼王":{
"buff": ["今天安德琉斯的心情不错,可以py一下","5金加原胚!"],
"debuff": ["狼尾巴*1"]
},
"打公子":{
"buff": ["今天可以和公子py想要的突破材料","5金加原胚!"],
"debuff": ["要角没有!要命一条!"]
}
}
+43
View File
@@ -0,0 +1,43 @@
from utils.browser import get_browser
from utils.message_builder import image
from datetime import datetime
from services.log import logger
from pathlib import Path
import os
url = "https://genshin.pub"
async def get_alc_image(path: Path):
date = datetime.now().date()
for file in os.listdir(path):
if f'{date}.png' != file:
file = path / file
file.unlink()
if f'{date}.png' in os.listdir(path):
return image(f'{date}.png', 'genshin/alc')
page = None
try:
browser = await get_browser()
page = await browser.new_page()
await page.goto(url, wait_until="networkidle", timeout=10000)
await page.set_viewport_size({"width": 2560, "height": 1080})
card = await page.query_selector('.GSAlmanacs_gs_almanacs__3qT_A')
await card.screenshot(path=path / f'{date}.png', timeout=100000)
except Exception as e:
logger.error(f'获取原神黄历发生错误..{type(e)}: {e}')
finally:
if page:
await page.close()
return image(f'{date}.png', 'genshin/alc')
+78 -34
View File
@@ -12,14 +12,39 @@ from nonebot.permission import SUPERUSER
from typing import List
import os
import asyncio
import time
__zx_plugin_name__ = "原神今日素材"
__plugin_usage__ = """
usage:
看看原神今天要刷什么
指令:
今日素材/今天素材
""".strip()
__plugin_superuser_usage__ = """
usage:
更新原神今日素材
指令:
更新原神今日素材
""".strip()
__plugin_des__ = "看看原神今天要刷什么"
__plugin_cmd__ = ["今日素材/今天素材", "更新原神今日素材 [_superuser]"]
__plugin_type__ = ("原神相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["今日素材", "今天素材"],
}
driver: Driver = nonebot.get_driver()
material = on_command('今日素材', aliases={'今日材料', '今天素材', '今天材料'}, priority=5, block=True)
material = on_command("今日素材", aliases={"今日材料", "今天素材", "今天材料"}, priority=5, block=True)
super_cmd = on_command('更新原神今日素材', permission=SUPERUSER, priority=1, block=True)
super_cmd = on_command("更新原神今日素材", permission=SUPERUSER, priority=1, block=True)
@material.handle()
@@ -27,49 +52,62 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
if time.strftime("%w") == "0":
await material.send("今天是周日,所有材料副本都开放了。")
return
await material.send(Message(image('daily_material.png', 'genshin/material') + '\n※ 每日素材数据来源于 genshin.pub'))
await material.send(
Message(
image("daily_material.png", "genshin/material")
+ "\n※ 每日素材数据来源于 genshin.pub"
)
)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})"
f" 发送查看今日素材")
f" 发送查看今日素材"
)
@super_cmd.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
if await update_image():
await super_cmd.send('更新成功...')
logger.info(f'更新每日天赋素材成功...')
await super_cmd.send("更新成功...")
logger.info(f"更新每日天赋素材成功...")
else:
await super_cmd.send(f'更新失败...')
await super_cmd.send(f"更新失败...")
@driver.on_startup
async def update_image():
page = None
try:
if not os.path.exists(f'{IMAGE_PATH}/genshin/material'):
os.mkdir(f'{IMAGE_PATH}/genshin/material')
for file in os.listdir(f'{IMAGE_PATH}/genshin/material'):
os.remove(f'{IMAGE_PATH}/genshin/material/{file}')
if not os.path.exists(f"{IMAGE_PATH}/genshin/material"):
os.mkdir(f"{IMAGE_PATH}/genshin/material")
for file in os.listdir(f"{IMAGE_PATH}/genshin/material"):
os.remove(f"{IMAGE_PATH}/genshin/material/{file}")
browser = await get_browser()
if not browser:
logger.warning('获取 browser 失败,请部署至 linux 环境....')
logger.warning("获取 browser 失败,请部署至 linux 环境....")
return False
url = 'https://genshin.pub/daily'
url = "https://genshin.pub/daily"
page = await browser.new_page()
await page.goto(url, wait_until='networkidle', timeout=10000)
await page.goto(url, wait_until="networkidle", timeout=10000)
await page.set_viewport_size({"width": 2560, "height": 1080})
await page.evaluate("""
await page.evaluate(
"""
document.getElementsByClassName('GSTitleBar_gs_titlebar__2IJqy')[0].remove();
e = document.getElementsByClassName('GSContainer_gs_container__2FbUz')[0];
e.setAttribute("style", "height:880px");
""")
"""
)
await page.click("button")
div = await page.query_selector(".GSContainer_content_box__1sIXz")
for i, card in enumerate(await page.query_selector_all(".GSTraitCotainer_trait_section__1f3bc")):
for i, card in enumerate(
await page.query_selector_all(".GSTraitCotainer_trait_section__1f3bc")
):
index = 0
type_ = 'char' if not i else 'weapons'
type_ = "char" if not i else "weapons"
for x in await card.query_selector_all("xpath=child::*"):
await x.screenshot(path=f'{IMAGE_PATH}/genshin/material/{type_}_{index}.png', timeout=100000)
await x.screenshot(
path=f"{IMAGE_PATH}/genshin/material/{type_}_{index}.png",
timeout=100000,
)
# 下滑两次
for _ in range(3):
await div.press("PageDown")
@@ -77,13 +115,23 @@ async def update_image():
# 结束后上滑至顶
for _ in range(index * 3):
await div.press("PageUp")
file_list = os.listdir(f'{IMAGE_PATH}/genshin/material')
char_imgs = [f'{IMAGE_PATH}/genshin/material/{x}' for x in file_list if x.startswith('char')]
weapons_imgs = [f'{IMAGE_PATH}/genshin/material/{x}' for x in file_list if x.startswith('weapons')]
file_list = os.listdir(f"{IMAGE_PATH}/genshin/material")
char_imgs = [
f"{IMAGE_PATH}/genshin/material/{x}"
for x in file_list
if x.startswith("char")
]
weapons_imgs = [
f"{IMAGE_PATH}/genshin/material/{x}"
for x in file_list
if x.startswith("weapons")
]
char_imgs.sort()
weapons_imgs.sort()
height = await asyncio.get_event_loop().run_in_executor(None, get_background_height, weapons_imgs)
background_img = CreateImg(1200, height + 100, color='#f6f2ee')
height = await asyncio.get_event_loop().run_in_executor(
None, get_background_height, weapons_imgs
)
background_img = CreateImg(1200, height + 100, color="#f6f2ee")
current_width = 50
for imgs in [char_imgs, weapons_imgs]:
current_height = 20
@@ -92,11 +140,11 @@ async def update_image():
background_img.paste(x, (current_width, current_height))
current_height += x.size[1]
current_width += 600
background_img.save(f'{IMAGE_PATH}/genshin/material/daily_material.png')
background_img.save(f"{IMAGE_PATH}/genshin/material/daily_material.png")
await page.close()
return True
except Exception as e:
logger.error(f'原神每日素材更新出错... {type(e)}: {e}')
logger.error(f"原神每日素材更新出错... {type(e)}: {e}")
if page:
await page.close()
return False
@@ -116,7 +164,7 @@ def get_background_height(weapons_imgs: List[str]) -> int:
@scheduler.scheduled_job(
'cron',
"cron",
hour=4,
minute=1,
)
@@ -124,11 +172,7 @@ async def _():
for _ in range(5):
try:
await update_image()
logger.info(f'更新每日天赋素材成功...')
logger.info(f"更新每日天赋素材成功...")
break
except Exception as e:
logger.error(f'更新每日天赋素材出错 e:{e}')
logger.error(f"更新每日天赋素材出错 e:{e}")
@@ -5,9 +5,24 @@ from nonebot import on_command
from utils.utils import get_message_text
from services.log import logger
__plugin_name__ = "丘丘语翻译"
__plugin_usage__ = "用法:丘丘翻译 [消息]"
__zx_plugin_name__ = "丘丘语翻译"
__plugin_usage__ = """
usage:
异世界旅游小助手,仅支持丘丘语翻译至中文
指令:
丘丘语翻译/丘丘一下 [文本]
""".strip()
__plugin_des__ = "其实我听得懂丘丘人讲话"
__plugin_cmd__ = ["丘丘语翻译/丘丘一下 [文本]"]
__plugin_type__ = ("原神相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["丘丘语翻译", "丘丘一下"],
}
qiuqiu = on_command("丘丘语翻译", aliases={"丘丘一下", "丘丘翻译"}, priority=5, block=True)
@@ -1,10 +1,10 @@
from nonebot import on_command, on_regex
from nonebot.rule import to_me
from .query_resource import get_resource_type_list, query_resource, init
from .query_resource import get_resource_type_list, query_resource, init, check_resource_exists
from utils.utils import get_message_text, scheduler
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message
from nonebot.typing import T_State
from services.log import logger
from configs.config import NICKNAME
from nonebot.permission import SUPERUSER
import re
@@ -13,28 +13,53 @@ try:
except ModuleNotFoundError:
import json
__plugin_name__ = "原神资源查询"
__zx_plugin_name__ = "原神资源查询"
__plugin_usage__ = """
usage:
不需要打开网页,就能帮你生成资源图片
指令:
原神资源查询 [资源名称]
原神资源列表
[资源名称]在哪
哪有[资源名称]
""".strip()
__plugin_superuser_usage__ = """
usage:
更新原神资源信息
指令:
更新原神资源信息
""".strip()
__plugin_des__ = "原神大地图资源速速查看"
__plugin_cmd__ = ["原神资源查询 [资源名称]", "原神资源列表", "[资源名称]在哪/哪有[资源名称]", "更新原神资源信息 [_superuser]"]
__plugin_type__ = ("原神相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["原神资源查询", "原神资源列表"],
}
__plugin_usage__ = (
"用法:\n" "\t原神资源查询 [消息]\n" "\t原神资源列表\n" "\t[消息]在哪\n" "\t哪有[消息]\n" "[消息] = 资源名称"
)
qr = on_command("原神资源查询", priority=5, block=True)
qr = on_command("原神资源查询", aliases={"原神资源查找"}, priority=5, block=True)
qr_lst = on_command("原神资源列表", priority=5, block=True)
rex_qr = on_regex(".*?(在哪|在哪里|哪有|哪里有).*?", rule=to_me(), priority=5, block=True)
update_info = on_command('更新原神资源信息', permission=SUPERUSER, priority=1, block=True)
rex_qr = on_regex(".*?(在哪|在哪里|哪有|哪里有).*?", priority=5, block=True)
update_info = on_command("更新原神资源信息", permission=SUPERUSER, priority=1, block=True)
@qr.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
resource_name = get_message_text(event.json())
await qr.send('正在生成位置....')
rst = await query_resource(resource_name)
await qr.send(Message(rst), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询原神材料:" + resource_name
)
if check_resource_exists(resource_name):
await qr.send("正在生成位置....")
resource = await query_resource(resource_name)
await qr.send(Message(resource), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询原神材料:" + resource_name
)
else:
await qr.send(f"未查找到 {resource_name} 资源,可通过 “原神资源列表” 获取全部资源名称..")
@rex_qr.handle()
@@ -46,33 +71,33 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
else:
rs = re.search(".*?(哪有|哪里有)(.*)", msg)
resource_name = rs.group(2) if rs else ""
if resource_name:
await qr.send('正在生成位置....')
msg = await query_resource(resource_name)
await rex_qr.send(Message(msg), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询原神材料:" + resource_name
)
if check_resource_exists(resource_name):
await qr.send("正在生成位置....")
resource = await query_resource(resource_name)
if resource:
await rex_qr.send(Message(resource), at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询原神材料:" + resource_name
)
@qr_lst.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
mes_list = []
txt = get_resource_type_list()
txt_list = txt.split("\n")
if event.message_type == "group":
if isinstance(event, GroupMessageEvent):
mes_list = []
for txt in txt_list:
data = {
"type": "node",
"data": {
"name": f"这里是{list(bot.config.nickname)[0]}酱",
"name": f"这里是{NICKNAME}酱",
"uin": f"{bot.self_id}",
"content": txt,
},
}
mes_list.append(data)
if isinstance(event, GroupMessageEvent):
await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
else:
rst = ""
@@ -87,17 +112,17 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@update_info.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await init(True)
await update_info.send('更新原神资源信息完成...')
await update_info.send("更新原神资源信息完成...")
@scheduler.scheduled_job(
'cron',
"cron",
hour=5,
minute=1,
)
async def _():
try:
await init()
logger.info(f'每日更新原神材料信息成功!')
logger.info(f"每日更新原神材料信息成功!")
except Exception as e:
logger.error(f'每日更新原神材料信息错误:{e}')
logger.error(f"每日更新原神材料信息错误:{e}")
+3 -3
View File
@@ -1,5 +1,5 @@
from pathlib import Path
from configs.path_config import IMAGE_PATH, TXT_PATH
from configs.path_config import IMAGE_PATH, TEXT_PATH
from utils.image_utils import CreateImg
from typing import Tuple, List
from math import sqrt, pow
@@ -12,8 +12,8 @@ except ModuleNotFoundError:
icon_path = Path(IMAGE_PATH) / "genshin" / "genshin_icon"
map_path = Path(IMAGE_PATH) / "genshin" / "map" / "map.png"
resource_label_file = Path(TXT_PATH) / "genshin" / "resource_label_file.json"
resource_point_file = Path(TXT_PATH) / "genshin" / "resource_point_file.json"
resource_label_file = Path(TEXT_PATH) / "genshin" / "resource_label_file.json"
resource_point_file = Path(TEXT_PATH) / "genshin" / "resource_point_file.json"
class Map:
@@ -1,5 +1,5 @@
from typing import Tuple, Optional, List
from configs.path_config import IMAGE_PATH, TXT_PATH
from configs.path_config import IMAGE_PATH, TEXT_PATH
from PIL.Image import UnidentifiedImageError
from utils.message_builder import image
from services.log import logger
@@ -30,9 +30,9 @@ MAP_URL = "https://api-static.mihoyo.com/common/map_user/ys_obc/v1/map/info?map_
icon_path = Path(IMAGE_PATH) / "genshin" / "genshin_icon"
map_path = Path(IMAGE_PATH) / "genshin" / "map"
resource_label_file = Path(TXT_PATH) / "genshin" / "resource_label_file.json"
resource_point_file = Path(TXT_PATH) / "genshin" / "resource_point_file.json"
resource_type_file = Path(TXT_PATH) / "genshin" / "resource_type_file.json"
resource_label_file = Path(TEXT_PATH) / "genshin" / "resource_label_file.json"
resource_point_file = Path(TEXT_PATH) / "genshin" / "resource_point_file.json"
resource_type_file = Path(TEXT_PATH) / "genshin" / "resource_type_file.json"
# 地图中心坐标
CENTER_POINT: Optional[Tuple[int, int]] = None
@@ -50,7 +50,8 @@ async def query_resource(resource_name: str) -> str:
resource_name = resource_name[:-2].strip()
planning_route = True
if not resource_name or resource_name not in resource_name_list:
return f"未查找到 {resource_name} 资源,可通过 “原神资源列表” 获取全部资源名称.."
# return f"未查找到 {resource_name} 资源,可通过 “原神资源列表” 获取全部资源名称.."
return ''
map_ = Map(
resource_name, CENTER_POINT, planning_route=planning_route, ratio=MAP_RATIO
)
@@ -81,23 +82,36 @@ def get_resource_type_list():
return mes
def check_resource_exists(resource: str) -> bool:
"""
检查资源是否存在
:param resource: 资源名称
"""
resource = resource.replace('路径', '').replace('路线', '')
return resource in resource_name_list
@driver.on_startup
async def init(flag: bool = False):
global CENTER_POINT, resource_name_list
semaphore = asyncio.Semaphore(10)
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
await download_map_init(session, semaphore, MAP_RATIO, flag)
await download_resource_data(session, semaphore)
await download_resource_type(session)
if not CENTER_POINT:
CENTER_POINT = json.load(open(resource_label_file, "r", encoding="utf8"))[
"CENTER_POINT"
]
with open(resource_type_file, "r", encoding="utf8") as f:
data = json.load(f)
for id_ in data:
for x in data[id_]["children"]:
resource_name_list.append(x["name"])
try:
semaphore = asyncio.Semaphore(10)
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
await download_map_init(session, semaphore, MAP_RATIO, flag)
await download_resource_data(session, semaphore)
await download_resource_type(session)
if not CENTER_POINT:
CENTER_POINT = json.load(open(resource_label_file, "r", encoding="utf8"))[
"CENTER_POINT"
]
with open(resource_type_file, "r", encoding="utf8") as f:
data = json.load(f)
for id_ in data:
for x in data[id_]["children"]:
resource_name_list.append(x["name"])
except TimeoutError:
logger.warning('原神资源查询信息初始化超时....')
pass
# 图标及位置资源
@@ -164,40 +178,18 @@ async def download_map_init(
if not _map.exists():
# padding_w, padding_h = data['padding']
data = data["slices"]
idx = 0
for x in data:
idj = 0
for j in x:
await download_image(
j["url"],
f"{map_path}/{idx}_{idj}.png",
session,
semaphore,
force_flag=flag,
)
idj += 1
idx += 1
map_width, map_height = CreateImg(
0, 0, background=f"{map_path}/0_0.png"
).size
map_width = map_width * MAP_RATIO
map_height = map_height * MAP_RATIO
lens = len(
[x for x in os.listdir(f"{map_path}") if x.startswith("0")]
map_url = data[0][0]['url']
await download_image(
map_url,
f"{map_path}/map.png",
session,
semaphore,
force_flag=flag,
)
background_image = CreateImg(
map_width * lens, map_height * lens, map_width, map_height
map_file = CreateImg(
0, 0, background=f"{map_path}/map.png", ratio=MAP_RATIO
)
for i in range(idx):
for j in range(idj):
x = CreateImg(
0,
0,
background=f"{map_path}/{i}_{j}.png",
ratio=MAP_RATIO,
)
background_image.paste(x)
background_image.save(f"{map_path}/map.png")
map_file.save(f"{map_path}/map.png")
else:
logger.warning(f'获取原神地图失败 msg: {data["message"]}')
else:
@@ -1,197 +1,195 @@
from utils.message_builder import image
from utils.utils import scheduler, get_bot
from services.log import logger
from models.group_remind import GroupRemind
from models.group_info import GroupInfo
from models.friend_user import FriendUser
from nonebot.adapters.cqhttp.exception import ActionFailed
from configs.config import NICKNAME
__name__ = "早晚安 [Hidden]"
# 早上好
@scheduler.scheduled_job(
"cron",
# year=None,
# month=None,
# day=None,
# week=None,
# day_of_week="mon,tue,wed,thu,fri",
hour=6,
minute=1,
# second=None,
# start_date=None,
# end_date=None,
# timezone=None,
)
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list(self_id=bot.self_id)
gl = [g["group_id"] for g in gl]
for g in gl:
if await GroupRemind.get_status(g, "zwa"):
result = image("zao.jpg", "zhenxun")
try:
await bot.send_group_msg(group_id=g, message="早上好" + result)
except ActionFailed:
logger.warning(f"{g} 群被禁言中,无法发送早安")
except Exception as e:
logger.error(f"早晚安错误 e:{e}")
# 睡觉了
@scheduler.scheduled_job(
"cron",
hour=23,
minute=59,
)
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list(self_id=bot.self_id)
gl = [g["group_id"] for g in gl]
for g in gl:
if await GroupRemind.get_status(g, "zwa"):
result = image("sleep.jpg", "zhenxun")
try:
await bot.send_group_msg(
group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result
)
except ActionFailed:
logger.warning(f"{g} 群被禁言中,无法发送晚安")
except Exception as e:
logger.error(f"早晚安错误 e:{e}")
# 自动更新群组信息
@scheduler.scheduled_job(
"cron",
hour=3,
minute=1,
)
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list(self_id=bot.self_id)
gl = [g["group_id"] for g in gl]
for g in gl:
group_info = await bot.get_group_info(group_id=g)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
)
logger.info(f"自动更新群组 {g} 信息成功")
except Exception as e:
logger.error(f"自动更新群组信息错误 e:{e}")
# 自动更新好友信息
@scheduler.scheduled_job(
"cron",
hour=3,
minute=1,
)
async def _():
try:
bot = get_bot()
fl = await bot.get_friend_list(self_id=bot.self_id)
for f in fl:
if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
else:
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
except Exception as e:
logger.error(f"自动更新群组信息错误 e:{e}")
# 一次性任务
# 固定时间触发,仅触发一次:
#
# from datetime import datetime
#
# @nonebot.scheduler.scheduled_job(
# 'date',
# run_date=datetime(2021, 1, 1, 0, 0),
# # timezone=None,
# )
# async def _():
# await bot.send_group_msg(group_id=123456,
# message="2021,新年快乐!")
# 定期任务
# 从 start_date 开始到 end_date 结束,根据类似 Cron
#
# 的规则触发任务:
#
# @nonebot.scheduler.scheduled_job(
# 'cron',
# # year=None,
# # month=None,
# # day=None,
# # week=None,
# day_of_week="mon,tue,wed,thu,fri",
# hour=7,
# # minute=None,
# # second=None,
# # start_date=None,
# # end_date=None,
# # timezone=None,
# )
# async def _():
# await bot.send_group_msg(group_id=123456,
# message="起床啦!")
# 间隔任务
#
# interval 触发器
#
# 从 start_date 开始,每间隔一段时间触发,到 end_date 结束:
#
# @nonebot.scheduler.scheduled_job(
# 'interval',
# # weeks=0,
# # days=0,
# # hours=0,
# minutes=5,
# # seconds=0,
# # start_date=time.now(),
# # end_date=None,
# )
# async def _():
# has_new_item = check_new_item()
# if has_new_item:
# await bot.send_group_msg(group_id=123456,
# message="XX有更新啦!")
# 动态的计划任务
# import datetime
#
# from apscheduler.triggers.date import DateTrigger # 一次性触发器
# # from apscheduler.triggers.cron import CronTrigger # 定期触发器
# # from apscheduler.triggers.interval import IntervalTrigger # 间隔触发器
# from nonebot import on_command, scheduler
#
# @on_command('赖床')
# async def _(session: CommandSession):
# await session.send('我会在5分钟后再喊你')
#
# # 制作一个“5分钟后”触发器
# delta = datetime.timedelta(minutes=5)
# trigger = DateTrigger(
# run_date=datetime.datetime.now() + delta
# )
#
# # 添加任务
# scheduler.add_job(
# func=session.send, # 要添加任务的函数,不要带参数
# trigger=trigger, # 触发器
# args=('不要再赖床啦!',), # 函数的参数列表,注意:只有一个值时,不能省略末尾的逗号
# # kwargs=None,
# misfire_grace_time=60, # 允许的误差时间,建议不要省略
# # jobstore='default', # 任务储存库,在下一小节中说明
# )
from utils.message_builder import image
from utils.utils import scheduler, get_bot
from nonebot import on_message
from services.log import logger
from models.group_info import GroupInfo
from models.friend_user import FriendUser
from nonebot.adapters.cqhttp.exception import ActionFailed
from configs.config import NICKNAME
from utils.manager import group_manager
__zx_plugin_name__ = "群定时任务相关 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {'zwa': '早晚安'}
x = on_message(priority=9, block=False)
# 早上好
@scheduler.scheduled_job(
"cron",
hour=6,
minute=1,
)
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
if await group_manager.check_group_task_status(g, 'zwa'):
result = image("zao.jpg", "zhenxun")
try:
await bot.send_group_msg(group_id=g, message="早上好" + result)
except ActionFailed:
logger.warning(f"{g} 群被禁言中,无法发送早安")
except Exception as e:
logger.error(f"早晚安错误 e:{e}")
# 睡觉了
@scheduler.scheduled_job(
"cron",
hour=23,
minute=59,
)
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
if await group_manager.check_group_task_status(g, 'zwa'):
result = image("sleep.jpg", "zhenxun")
try:
await bot.send_group_msg(
group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result
)
except ActionFailed:
logger.warning(f"{g} 群被禁言中,无法发送晚安")
except Exception as e:
logger.error(f"早晚安错误 e:{e}")
# 自动更新群组信息
@scheduler.scheduled_job(
"cron",
hour=3,
minute=1,
)
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
group_info = await bot.get_group_info(group_id=g)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
)
logger.info(f"自动更新群组 {g} 信息成功")
except Exception as e:
logger.error(f"自动更新群组信息错误 e:{e}")
# 自动更新好友信息
@scheduler.scheduled_job(
"cron",
hour=3,
minute=1,
)
async def _():
try:
bot = get_bot()
fl = await bot.get_friend_list()
for f in fl:
if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
else:
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
except Exception as e:
logger.error(f"自动更新群组信息错误 e:{e}")
# 一次性任务
# 固定时间触发,仅触发一次:
#
# from datetime import datetime
#
# @nonebot.scheduler.scheduled_job(
# 'date',
# run_date=datetime(2021, 1, 1, 0, 0),
# # timezone=None,
# )
# async def _():
# await bot.send_group_msg(group_id=123456,
# message="2021,新年快乐!")
# 定期任务
# 从 start_date 开始到 end_date 结束,根据类似 Cron
#
# 的规则触发任务:
#
# @nonebot.scheduler.scheduled_job(
# 'cron',
# # year=None,
# # month=None,
# # day=None,
# # week=None,
# day_of_week="mon,tue,wed,thu,fri",
# hour=7,
# # minute=None,
# # second=None,
# # start_date=None,
# # end_date=None,
# # timezone=None,
# )
# async def _():
# await bot.send_group_msg(group_id=123456,
# message="起床啦!")
# 间隔任务
#
# interval 触发器
#
# 从 start_date 开始,每间隔一段时间触发,到 end_date 结束:
#
# @nonebot.scheduler.scheduled_job(
# 'interval',
# # weeks=0,
# # days=0,
# # hours=0,
# minutes=5,
# # seconds=0,
# # start_date=time.now(),
# # end_date=None,
# )
# async def _():
# has_new_item = check_new_item()
# if has_new_item:
# await bot.send_group_msg(group_id=123456,
# message="XX有更新啦!")
# 动态的计划任务
# import datetime
#
# from apscheduler.triggers.date import DateTrigger # 一次性触发器
# # from apscheduler.triggers.cron import CronTrigger # 定期触发器
# # from apscheduler.triggers.interval import IntervalTrigger # 间隔触发器
# from nonebot import on_command, scheduler
#
# @on_command('赖床')
# async def _(session: CommandSession):
# await session.send('我会在5分钟后再喊你')
#
# # 制作一个“5分钟后”触发器
# delta = datetime.timedelta(minutes=5)
# trigger = DateTrigger(
# run_date=datetime.datetime.now() + delta
# )
#
# # 添加任务
# scheduler.add_job(
# func=session.send, # 要添加任务的函数,不要带参数
# trigger=trigger, # 触发器
# args=('不要再赖床啦!',), # 函数的参数列表,注意:只有一个值时,不能省略末尾的逗号
# # kwargs=None,
# misfire_grace_time=60, # 允许的误差时间,建议不要省略
# # jobstore='default', # 任务储存库,在下一小节中说明
# )
+73 -59
View File
@@ -1,20 +1,20 @@
from nonebot import on_notice, on_request
from configs.path_config import IMAGE_PATH, DATA_PATH
from utils.message_builder import image
import os
import random
from models.group_member_info import GroupInfoUser
from datetime import datetime
from services.log import logger
from models.group_remind import GroupRemind
from nonebot.adapters.cqhttp import (
Bot,
GroupIncreaseNoticeEvent,
GroupDecreaseNoticeEvent,
)
from nonebot.adapters.cqhttp.exception import ActionFailed
from pathlib import Path
from utils.manager import group_manager, plugins2settings_manager
from models.group_info import GroupInfo
from pathlib import Path
import random
import os
try:
import ujson as json
@@ -22,9 +22,13 @@ except ModuleNotFoundError:
import json
__plugin_name__ = "群事件处理 [Hidden]"
__usage__ = "用法:无"
__zx_plugin_name__ = "群事件处理 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {
'group_welcome': '进群欢迎',
'refund_group_remind': '退群提醒'
}
# 群员增加处理
@@ -37,46 +41,55 @@ add_group = on_request(priority=1, block=False)
@group_increase_handle.handle()
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
join_time = datetime.now()
user_info = await bot.get_group_member_info(
group_id=event.group_id, user_id=event.user_id
)
if await GroupInfoUser.add_member_info(
user_info["user_id"],
user_info["group_id"],
user_info["nickname"],
join_time,
):
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
if event.user_id == int(bot.self_id):
if event.group_id not in group_manager["group_manager"].keys():
data = plugins2settings_manager.get_data()
for plugin in data.keys():
if not data[plugin]["default_status"]:
group_manager.block_plugin(plugin, event.group_id)
else:
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
# 群欢迎消息
if await GroupRemind.get_status(event.group_id, "hy"):
msg = ""
img = ""
at_flag = False
custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
join_time = datetime.now()
user_info = await bot.get_group_member_info(
group_id=event.group_id, user_id=event.user_id
)
if custom_welcome_msg_json.exists():
data = json.load(open(custom_welcome_msg_json, "r"))
if data.get(str(event.group_id)):
msg = data[str(event.group_id)]
if msg.find("[at]") != -1:
msg = msg.replace("[at]", "")
at_flag = True
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"):
img = image(abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg")
if msg or img:
await group_increase_handle.send(
"\n" + msg.strip() + img, at_sender=at_flag
)
if await GroupInfoUser.add_member_info(
user_info["user_id"],
user_info["group_id"],
user_info["nickname"],
join_time,
):
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
else:
await group_increase_handle.send(
"新人快跑啊!!本群现状↓(快使用自定义!)"
+ image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz")
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
# 群欢迎消息
if await group_manager.check_group_task_status(event.group_id, 'group_welcome'):
msg = ""
img = ""
at_flag = False
custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
)
if custom_welcome_msg_json.exists():
data = json.load(open(custom_welcome_msg_json, "r"))
if data.get(str(event.group_id)):
msg = data[str(event.group_id)]
if msg.find("[at]") != -1:
msg = msg.replace("[at]", "")
at_flag = True
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"):
img = image(
abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"
)
if msg or img:
await group_increase_handle.send(
"\n" + msg.strip() + img, at_sender=at_flag
)
else:
await group_increase_handle.send(
"新人快跑啊!!本群现状↓(快使用自定义!)"
+ image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz")
)
@group_decrease_handle.handle()
@@ -97,9 +110,9 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
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]}",
f"我被 {operator_name}({operator_id})\n"
f"踢出了 {group_name}({group_id})\n"
f"日期:{str(datetime.now()).split('.')[0]}",
)
return
try:
@@ -108,20 +121,21 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
).user_name
except AttributeError:
user_name = str(event.user_id)
rst = ""
if event.sub_type == "leave":
rst = 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"] if operator["card"] else operator["nickname"]
rst = f"{user_name} 被 {operator_name} 送走了."
if await GroupInfoUser.delete_member_info(event.user_id, event.group_id):
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除成功")
else:
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败")
try:
await group_decrease_handle.send(f"{rst}")
except ActionFailed:
return
if await group_manager.check_group_task_status(event.group_id, 'refund_group_remind'):
rst = ""
if event.sub_type == "leave":
rst = 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"] if operator["card"] else operator["nickname"]
rst = f"{user_name} 被 {operator_name} 送走了."
try:
await group_decrease_handle.send(f"{rst}")
except ActionFailed:
return
@@ -1,35 +1,35 @@
from nonebot import on_message
from nonebot.adapters.cqhttp.permission import GROUP
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
import time
from .data_source import cancel_all_notice, save_data, get_data, set_data_value
from services.log import logger
__plugin_name__ = "查看群最后聊天时间 [Hidden]"
__plugin_usage__ = "用法:无"
last_chat = on_message(priority=1, block=False, permission=GROUP)
@last_chat.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
time_data = await get_data()
set_data_value(event.group_id, time.time())
if event.group_id in time_data["_group"]:
time_data["_group"].remove(event.group_id)
set_data_value("_group", time_data["_group"])
for key in time_data.keys():
if key not in ["check_time", "_group"]:
if key not in time_data["_group"]:
if time.time() - time_data[key] > 60 * 60 * 36:
await cancel_all_notice(key)
time_data["_group"].append(key)
set_data_value("_group", time_data["_group"])
logger.info(f"GROUP {event.group_id} 因群内发言时间大于36小时被取消全部通知")
if time.time() - time_data["check_time"] > 60 * 60 * 1:
set_data_value("check_time", time.time())
save_data()
from nonebot import on_message
from nonebot.adapters.cqhttp.permission import GROUP
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
import time
from .data_source import cancel_all_notice, save_data, get_data, set_data_value
from services.log import logger
__zx_plugin_name__ = "群聊最后聊天时间记录 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
last_chat = on_message(priority=1, block=False, permission=GROUP)
@last_chat.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
time_data = await get_data()
set_data_value(event.group_id, time.time())
if event.group_id in time_data["_group"]:
time_data["_group"].remove(event.group_id)
set_data_value("_group", time_data["_group"])
for key in time_data.keys():
if key not in ["check_time", "_group"]:
if key not in time_data["_group"]:
if time.time() - time_data[key] > 60 * 60 * 36:
await cancel_all_notice(key)
time_data["_group"].append(key)
set_data_value("_group", time_data["_group"])
logger.info(f"GROUP {event.group_id} 因群内发言时间大于36小时被取消全部通知")
if time.time() - time_data["check_time"] > 60 * 60 * 1:
set_data_value("check_time", time.time())
save_data()
@@ -1,71 +1,67 @@
from configs.path_config import DATA_PATH
from utils.utils import get_bot
from models.group_remind import GroupRemind
from datetime import datetime
import time
from services.log import logger
try:
import ujson as json
except ModuleNotFoundError:
import json
time_data = {}
async def init():
global time_data
bot = get_bot()
gl = await bot.get_group_list(self_id=bot.self_id)
gl = [g["group_id"] for g in gl]
data = read_data("group_last_chat_time.json")
for g in gl:
if not data.get(g):
time_data[g] = time.time()
if not time_data.get("check_time"):
time_data["check_time"] = time.time()
if not time_data.get("_group"):
time_data["_group"] = []
save_data()
return time_data
def read_data(file_name: str):
try:
with open(DATA_PATH + file_name, "r", encoding="utf8") as f:
return json.load(f)
except (ValueError, FileNotFoundError):
return {}
def save_data():
with open(DATA_PATH + "group_last_chat_time.json", "w") as f:
json.dump(time_data, f, indent=4)
logger.info(
f'自动存储 group_last_chat_time.json 时间:{str(datetime.now()).split(".")[0]}'
)
command_list = ["zwa", "hy", "kxcz", "blpar", "epic", "pa", "gb"]
# 取消全部通知
async def cancel_all_notice(group_id):
group_id = int(group_id)
for command in command_list:
if await GroupRemind.get_status(group_id, command):
await GroupRemind.set_status(group_id, command, False)
logger.info(f"关闭了 {group_id} 群的全部通知")
async def get_data():
global time_data
if not time_data:
time_data = await init()
return time_data
def set_data_value(key, value):
global time_data
time_data[key] = value
from configs.path_config import DATA_PATH
from utils.utils import get_bot
from datetime import datetime
import time
from services.log import logger
from utils.manager import group_manager
try:
import ujson as json
except ModuleNotFoundError:
import json
time_data = {}
async def init():
global time_data
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
data = read_data("group_last_chat_time.json")
for g in gl:
if not data.get(g):
time_data[g] = time.time()
if not time_data.get("check_time"):
time_data["check_time"] = time.time()
if not time_data.get("_group"):
time_data["_group"] = []
save_data()
return time_data
def read_data(file_name: str):
try:
with open(DATA_PATH + file_name, "r", encoding="utf8") as f:
return json.load(f)
except (ValueError, FileNotFoundError):
return {}
def save_data():
with open(DATA_PATH + "group_last_chat_time.json", "w") as f:
json.dump(time_data, f, indent=4)
logger.info(
f'自动存储 group_last_chat_time.json 时间:{str(datetime.now()).split(".")[0]}'
)
# 取消全部通知
async def cancel_all_notice(group_id):
group_id = int(group_id)
for command in group_manager.get_task_data():
if await group_manager.check_group_task_status(group_id, command):
await group_manager.close_group_task(group_id, command)
logger.info(f"关闭了 {group_id} 群的全部通知")
async def get_data():
global time_data
if not time_data:
time_data = await init()
return time_data
def set_data_value(key, value):
global time_data
time_data[key] = value
+41 -11
View File
@@ -5,16 +5,28 @@ from services.log import logger
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP
from nonebot.typing import T_State
from nonebot.permission import SUPERUSER
from configs.config import plugins2info_dict, NICKNAME
from utils.static_data import group_manager
from configs.config import NICKNAME
from utils.manager import group_manager, plugins2settings_manager
try:
import ujson as json
except ModuleNotFoundError:
import json
__plugin_name__ = "群权限操作"
__plugin_usage__ = "区分权限功能"
__zx_plugin_name__ = "群权限操作 [Superuser]"
__plugin_usage__ = """
usage:
对群权限 | 群白名单 的操作
指令:
修改群权限 [group] [等级]
添加群白名单 *[group]
删除群白名单 *[group]
查看群白名单
""".strip()
__plugin_des__ = "对群权限 | 群白名单 的操作"
__plugin_cmd__ = ["修改群权限 [group] [等级]", "添加群白名单 *[group]", "删除群白名单 *[group]", "查看群白名单"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
add_group_level = on_command("修改群权限", priority=1, permission=SUPERUSER, block=True)
@@ -33,10 +45,16 @@ manager_group_whitelist = on_command(
"添加群白名单", aliases={"删除群白名单"}, priority=1, permission=SUPERUSER, block=True
)
show_group_whitelist = on_command(
"查看群白名单", priority=1, permission=SUPERUSER, block=True
)
@add_group_level.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
group_id = 0
level = 0
if not msg:
await add_group_level.finish("用法:修改群权限 [group] [level]")
msg = msg.split(" ")
@@ -50,19 +68,21 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
old_level = group_manager.get_group_level(group_id)
group_manager.set_group_level(group_id, level)
await add_group_level.send("修改成功...", at_sender=True)
await bot.send_group_msg(
group_id=int(group_id), message=f"管理员修改了此群权限:{old_level} -> {level}"
)
if level > -1:
await bot.send_group_msg(
group_id=int(group_id), message=f"管理员修改了此群权限:{old_level} -> {level}"
)
logger.info(f"{event.user_id} 修改了 {group_id} 的权限:{level}")
@my_group_level.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
level = group_manager.get_group_level(str(event.group_id))
level = group_manager.get_group_level(event.group_id)
tmp = ""
for plugin in plugins2info_dict:
if plugins2info_dict[plugin]["level"] > level:
plugin_name = plugins2info_dict[plugin]["cmd"][0]
data = plugins2settings_manager.get_data()
for module in data:
if data[module]["level"] > level:
plugin_name = data[module]["cmd"][0]
if plugin_name == "pixiv":
plugin_name = "搜图 p站排行"
tmp += f"{plugin_name}\n"
@@ -100,3 +120,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
)
else:
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
@show_group_whitelist.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
x = group_manager.get_group_white_list()
x = [str(g) for g in x]
if x:
await show_group_whitelist.send("目前的群白名单:\n" + "\n".join(x))
else:
await show_group_whitelist.send("没有任何群在群白名单...")
+17 -3
View File
@@ -12,9 +12,23 @@ try:
except ModuleNotFoundError:
import json
__plugin_name__ = "查看群欢迎消息"
__plugin_usage__ = "无"
__zx_plugin_name__ = "查看群欢迎消息"
__plugin_usage__ = """
usage:
查看当前的群欢迎消息
指令:
查看群欢迎消息
""".strip()
__plugin_des__ = "查看群欢迎消息"
__plugin_cmd__ = ["查看群欢迎消息"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["查看群欢迎消息"],
}
view_custom_welcome = on_command(
"群欢迎消息", aliases={"查看群欢迎消息", "查看当前群欢迎消息"}, permission=GROUP, priority=5, block=True
+44 -26
View File
@@ -1,43 +1,61 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, PrivateMessageEvent
from nonebot.adapters.cqhttp import (
Bot,
MessageEvent,
)
from nonebot.typing import T_State
from nonebot.rule import to_me
from configs.path_config import DATA_PATH
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
import os
from .data_source import create_help_img, create_group_help_img, get_plugin_help
from .data_source import create_help_img, get_plugin_help
from utils.utils import get_message_text
from pathlib import Path
__plugin_name__ = "帮助"
__zx_plugin_name__ = "帮助"
if not os.path.exists(DATA_PATH + "group_help/"):
os.mkdir(DATA_PATH + "group_help/")
create_help_img()
for file in os.listdir(DATA_PATH + "group_help/"):
os.remove(DATA_PATH + "group_help/" + file)
help_image = Path(IMAGE_PATH) / "help.png"
simple_help_image = Path(IMAGE_PATH) / "simple_help.png"
if help_image.exists():
help_image.unlink()
if simple_help_image.exists():
simple_help_image.unlink()
_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True)
_help = on_command("详细功能", rule=to_me(), aliases={"详细帮助"}, priority=1, block=True)
simple_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True)
@_help.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg = get_message_text(event.json())
if not msg:
if not os.path.exists(DATA_PATH + f"group_help/{event.group_id}.png"):
create_group_help_img(event.group_id)
await _help.finish(
image(abspath=DATA_PATH + f"group_help/{event.group_id}.png")
)
else:
await _help.finish(get_plugin_help(msg))
async def _(bot: Bot, event: MessageEvent, state: T_State):
if not help_image.exists():
if help_image.exists():
help_image.unlink()
if simple_help_image.exists():
simple_help_image.unlink()
await create_help_img(help_image, simple_help_image)
await _help.finish(image("help.png"))
@_help.handle()
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
@simple_help.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if not msg:
await _help.finish(image("help.png"))
is_super = False
if msg:
if '-super' in msg:
if str(event.user_id) in bot.config.superusers:
is_super = True
msg = msg.replace('-super', '')
msg = get_plugin_help(msg, is_super)
if msg:
await _help.send(image(b64=msg))
else:
await _help.send("没有此功能的帮助信息...")
else:
await _help.finish(get_plugin_help(msg))
if not simple_help_image.exists():
if help_image.exists():
help_image.unlink()
if simple_help_image.exists():
simple_help_image.unlink()
await create_help_img(help_image, simple_help_image)
await _help.finish(image("simple_help.png"))
-71
View File
@@ -1,71 +0,0 @@
from configs.config import NICKNAME
# 实用
utility_help = {
"update_pic": "一些对图片的操作 --> 指令:操作图片/图片/修改图片(包含 10 种图片操作)",
"search_buff_skin_price": "BUFF皮肤底价查询 --> 指令:查询皮肤(代理ip不得劲)",
"weather": "天气查询 --> 指令:xx天气",
"yiqing": "实时疫情数据 --> 指令:疫情查询/疫情/查询疫情",
"bt": "bt(磁力搜索){仅支持私聊,懂的都懂} --> 指令:bt",
"reimu": "老司机必备!{仅支持私聊,懂的都懂}-> 指令:上车",
"what_anime": "靠图识番 --> 指令:识番",
"nonebot_plugin_picsearcher": "以图搜图 --> 指令:识图/这是什么/上一张图是什么",
"search_anime": "找不到想看的动漫吗? --> 指令:搜番",
"songpicker2": "来一首歌听听? --> 指令:点歌",
"epic": "epic速速白嫖 --> 指令:epic",
"pixiv_r": "P站排行榜直接冲 --> 指令:p站排行(可含参数)",
"pixiv_s": "P站的图随便搜搜 --> 指令:搜图(可含参数)",
"pid_search": "通过PID搜索图片 --> 指令:p搜 [pid]",
"translate": "出国旅游助手(狗头) --> 指令:英翻/翻英/日翻/翻日/韩翻/翻韩",
"cover": "快捷的b站封面获取方式 --> 指令:b封面 [连接/av/bv/cv/直播id]",
}
# 娱乐
entertainment_help = {
"sign_in": "签到(影响色图和开箱) --> 指令:签到/我的签到/好感度排行/好感度总榜/好感度总榜[屏蔽我/显示我]",
"send_img": "发送图片 --> 指令:美图/萝莉/壁纸/(美图/萝莉/壁纸[id])/N张图xx(N<=9)",
"send_setu": "不要小看涩图啊混蛋! --> 指令:色图/色图[id]/n张色图/n张xx色图/查色图/...(请查看 色图 帮助)",
"white2black_img": "黑白草图 --> 指令:黑白图/黑白草图",
"coser": "三次元也不戳 --> 指令:coser",
"jitang": "不喝点什么不舒服 --> 指令:鸡汤/语录",
"send_dinggong_voice": "骂我(傲娇?) --> 指令:骂老子",
"poke": "戳一戳发送语音美图萝莉图不美哉?",
"open_cases": "模拟开箱(戒赌) --> 指令:开箱(N连开箱[N<=30])/我的开箱/群开箱统计/我的金色",
"luxun": "鲁迅说过 --> 指令:鲁迅说",
"fake_msg": "构造一个假消息 --> 指令:假消息",
"shop_handle": "商店系统(初始送100金币) --> 指令:商店/我的金币/购买道具/使用道具",
"draw_card_prts": "换个地方当非酋TvT... --> 指令:方舟一井/方舟N抽(0<N<300)",
"draw_card_genshin": "提瓦特是个好地方! --> 指令:原神一井/原神N抽(0<N<180)/原神武器/角色N抽/重置原神抽卡次数",
"draw_card_pretty": "赛马娘!!!! --> 指令:赛马娘一井/赛马娘N抽/赛马娘卡一井/赛马娘卡N抽(0<N<200)",
"draw_card_guardian": "坎公骑冠剑.... --> 指令:坎公骑冠剑一井/坎公骑冠剑武器一井/坎公骑冠剑N抽/坎公骑冠剑武器N抽(0<N<300)",
"draw_card_pcr": "公主连结(国服)来几发 --> 指令:pcr一井/pcrN抽(0<N<300)",
"draw_card_azur": "我跟方舟坐狱友 --> 指令:碧蓝轻型/重型/特型N抽(0<N<300)",
"draw_card_fgo": "你就是我的马斯塔嘛 --> 指令:fgoN抽(0<N<300)",
"draw_card_onmyoji": "普通的阴阳师召唤 --> 指令:阴阳师N抽(0<N<300)",
"one_friend": "我有一个朋友想问问... --> 指令:我有一个朋友想问问xxx(内容)",
"nickname": "区区昵称! --> 指令:以后叫我xx(昵称)/我是谁/取消昵称",
"almanac": "这是一张正经的黄历 --> 指令:原神黄历",
"material_remind": "看看原神今天要刷什么 --> 指令:今日素材/今日材料/今天素材/今天材料",
"qiu_qiu_translation": "这家伙到底在说什么? --> 指令:丘丘翻译/丘丘一下/丘丘语翻译",
"query_resource_points": "地图资源速速查看 --> 指令:原神资源查询xx[路径]/原神资源列表/哪里有xx/xx在哪(xx=资源名称)",
"russian": "紧张刺激的俄罗斯轮盘 --> 指令:俄罗斯轮盘帮助",
"gold_redbag": f"运气项目又来啦! --> 指令:塞红包/ 抢红包指令: 开/抢/戳一戳{NICKNAME}/ 退回:退回未抢完的红包",
"poetry": f"突然文艺的{NICKNAME}是否搞错了什么 --> 指令:念诗/来首诗/念首诗",
"comments_163": "生了个人,我很抱歉 --> 指令:到点了/12点了/网易云热评/网易云评论",
"pix_gallery": "偶尔也想看看美图? --> 指令:PIX [关键词/uid/pid:pid] [num]/查看pix图库 [关键词]/显示pix关键词",
'nbnhhsh': "会说话就多说点! --> 指令:nbnhhsh/能不能好好说话 [文本](空格划分)",
"roll": f"让{NICKNAME}来帮你决定吧! --> 指令:roll/ roll [文本](空格划分)",
"wbtop": f"刚买完瓜,在吃瓜现场 --> 指令:微博热搜/微博热搜 [数字]"
}
# 其他
other_help = [
"查看当前的群欢迎消息 --> 指令:群欢迎消息",
"这是一份正经的自我介绍 --> 指令:自我介绍",
"不得看看自己权力多大? --> 指令:我的权限",
"有人记得你是什么时候加入我们的 --> 指令:我的信息",
"让我看看更新了什么 --> 指令:更新信息",
f"{NICKNAME}给我把话收回去! --> 指令:撤回 [id](默认0)",
"群拥有的权限 --> 指令:查看群权限",
"数据统计可视化_1 --> 指令:功能调用统计/日功能调用统计/周功能调用统计/月功能调用统计",
"数据统计可视化_2 --> 指令:周功能调用统计 [功能名称]/月功能调用统计 [功能名称]",
"这里是PIX图库! --> 指令:添加pix关键词 [关键词]/添加pixuid/pid [UID/PID]/我的pix关键词",
]
+274 -165
View File
@@ -1,180 +1,289 @@
from utils.image_utils import CreateImg
from configs.path_config import IMAGE_PATH, DATA_PATH
from configs.path_config import IMAGE_PATH
from utils.manager import plugins2settings_manager
from typing import Optional
from services.log import logger
from pathlib import Path
from .config import *
from configs.config import (
INITIAL_OPEN_CASE_COUNT,
INITIAL_SETU_PROBABILITY,
ADMIN_DEFAULT_AUTH,
)
from configs.config import plugins2info_dict, NICKNAME
from utils.static_data import group_manager
from utils.utils import get_matchers
import random
import asyncio
import nonebot
import os
width = 1600
e_height = 0
u_height = 950
o_height = 1500
# f_height =
random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help"
background = Path(IMAGE_PATH) / "background" / "0.png"
def create_help_img():
help_img_file = Path(IMAGE_PATH) / 'help.png'
if help_img_file.exists():
help_img_file.unlink()
h = (
100
+ len(utility_help) * 24
+ len(entertainment_help) * 24
+ len(other_help) * 24
) * 2
A = CreateImg(width, h - 200, font_size=24)
e = CreateImg(width, len(entertainment_help) * 42, font_size=24)
rst = ""
i = 0
for cmd in entertainment_help:
rst += f"{i + 1}.{entertainment_help[cmd]}\n"
i += 1
e.text((10, 10), "娱乐功能:")
e.text((40, 40), rst)
u = CreateImg(width, len(utility_help) * 40 + 50, font_size=24, color="black")
rst = ""
i = 0
for cmd in utility_help:
rst += f"{i + 1}.{utility_help[cmd]}\n"
i += 1
u.text((10, 10), "实用功能:", fill=(255, 255, 255))
u.text((40, 40), rst, fill=(255, 255, 255))
o = CreateImg(width, len(other_help) * 40, font_size=24)
rst = ""
i = 0
for i in range(len(other_help)):
rst += f"{i + 1}.{other_help[i]}\n"
i += 1
o.text((10, 10), "其他功能:")
o.text((40, 40), rst)
A.paste(e, (0, 0))
A.paste(u, (0, u_height))
A.paste(o, (0, o_height))
A.text(
(10, h * 0.68),
f"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对{NICKNAME}说 “{NICKNAME}帮助 指令名” 获取对应详细帮助\n"
"可以通过 “滴滴滴- [消息]” 联系管理员(有趣的想法尽管来吧!<还有Bug和建议>)"
"\n[群管理员请看 管理员帮助(群主与管理员自带 5 级权限)]\n\n"
f"\t「如果{NICKNAME}回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【QAQ】」",
async def create_help_img(help_image: Path, simple_help_image: Path):
"""
生成帮助图片
:param help_image: 图片路径
:param simple_help_image: 简易帮助图片路径
"""
return await asyncio.get_event_loop().run_in_executor(
None, _create_help_img, help_image, simple_help_image
)
A.save(IMAGE_PATH + "help.png")
def create_group_help_img(group_id: int):
group_id = str(group_id)
h = (
100
+ len(utility_help) * 24
+ len(entertainment_help) * 24
+ len(other_help) * 24
) * 2
A = CreateImg(width, h - 200, font_size=24)
u = CreateImg(width, len(utility_help) * 40, font_size=24, color="black")
o = CreateImg(width, len(other_help) * 40, font_size=24)
e = CreateImg(width, len(entertainment_help) * 42, font_size=24)
rst = ""
i = 1
for cmd in entertainment_help.keys():
flag, dfg = parse_cmd(cmd, group_id)
if dfg:
cmd = rcmd(dfg)
rst += f"【{flag}】{i}.{entertainment_help[cmd]}\n"
i += 1
e.text((10, 10), "娱乐功能:")
e.text((40, 40), rst)
rst = ""
i = 1
for cmd in utility_help.keys():
flag, dfg = parse_cmd(cmd, group_id)
rst += f"【{flag}】{i}.{utility_help[cmd]}\n"
i += 1
u.text((10, 10), "实用功能:", fill=(255, 255, 255))
u.text((40, 40), rst, fill=(255, 255, 255))
rst = ""
for i in range(len(other_help)):
rst += f"{i + 1}.{other_help[i]}\n"
o.text((10, 10), "其他功能:")
o.text((40, 40), rst)
A.paste(e, (0, 0))
A.paste(u, (0, u_height))
A.paste(o, (0, o_height))
# A.text((width, 10), f'总开关【{"√" if data["总开关"] else "×"}】')
A.text(
(10, h * 0.68),
f"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对{NICKNAME}说 “{NICKNAME}帮助 指令名” 获取对应详细帮助\n"
"可以通过 “滴滴滴- [消息]” 联系管理员(有趣的想法尽管来吧!<还有Bug和建议>)"
f"\n[群管理员请看 管理员帮助(群主与管理员自带 {ADMIN_DEFAULT_AUTH} 级权限)]",
def _create_help_img(help_image: Path, simple_help_image: Path):
"""
生成帮助图片
:param help_image: 图片路径
:param simple_help_image: 简易帮助图片路径
"""
_matchers = get_matchers()
width = 0
matchers_data = {}
_des_tmp = {}
_plugin_name_tmp = []
_tmp = []
tmp_img = CreateImg(0, 0, plain_text="1", font_size=24)
font_height = tmp_img.h
for matcher in _matchers:
plugin_name = None
_plugin = nonebot.plugin.get_plugin(matcher.module)
_module = _plugin.module
try:
plugin_name = _module.__getattribute__("__zx_plugin_name__")
try:
plugin_des = _module.__getattribute__("__plugin_des__")
except AttributeError:
plugin_des = "_"
if (
"[hidden]" in plugin_name.lower()
or "[admin]" in plugin_name.lower()
or "[superuser]" in plugin_name.lower()
or plugin_name in _plugin_name_tmp
or plugin_name == "帮助"
):
continue
plugin_type = ("normal",)
text_type = 0
if plugins2settings_manager.get(
matcher.module
) and plugins2settings_manager[matcher.module].get("plugin_type"):
plugin_type = tuple(
plugins2settings_manager.get_plugin_data(matcher.module)[
"plugin_type"
]
)
else:
try:
plugin_type = _module.__getattribute__("__plugin_type__")
except AttributeError:
pass
if len(plugin_type) > 1:
try:
text_type = int(plugin_type[1])
except ValueError as e:
logger.warning(f"生成列向帮助排列失败 {plugin_name}: {type(e)}: {e}")
plugin_type = plugin_type[0]
else:
plugin_type = plugin_type[0]
try:
plugin_cmd = _module.__getattribute__("__plugin_cmd__")
plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x]
except AttributeError:
plugin_cmd = []
if plugin_type not in matchers_data.keys():
matchers_data[plugin_type] = {}
if plugin_des in _des_tmp.keys():
try:
matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] = (
matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"]
+ plugin_cmd
)
except KeyError as e:
logger.warning(f"{type(e)}: {e}")
else:
matchers_data[plugin_type][plugin_name] = {
"des": plugin_des,
"cmd": plugin_cmd,
"text_type": text_type,
}
try:
if text_type == 0:
x = tmp_img.getsize(
f'{plugin_name}: {matchers_data[plugin_type][plugin_name]["des"]} ->'
+ " / ".join(matchers_data[plugin_type][plugin_name]["cmd"])
)[0]
width = width if width > x else x
except KeyError:
pass
if plugin_des not in _des_tmp:
_des_tmp[plugin_des] = plugin_name
except AttributeError as e:
if plugin_name not in _plugin_name_tmp:
logger.warning(f"获取功能 {matcher.module}: {plugin_name} 设置失败...e:{e}")
if plugin_name not in _plugin_name_tmp:
_plugin_name_tmp.append(plugin_name)
help_img_list = []
simple_help_img_list = []
types = list(matchers_data.keys())
types.sort()
ix = 0
for type_ in types:
keys = list(matchers_data[type_].keys())
keys.sort()
help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
simple_help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
for i, k in enumerate(keys):
simple_help_str += f"{i+1}.{k}\n"
if matchers_data[type_][k]["text_type"] == 1:
_x = tmp_img.getsize(
f"{i+1}".rjust(5)
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
)[0]
_str = (
f"{i+1}".rjust(5)
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
)
_str += matchers_data[type_][k]["cmd"][0] + "\n"
for c in matchers_data[type_][k]["cmd"][1:]:
_str += "".rjust(int(_x * 0.125) + 1) + f"{c}\n"
help_str += _str
else:
help_str += (
f"{i+1}".rjust(5)
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
+ " / ".join(matchers_data[type_][k]["cmd"])
+ "\n"
)
height = len(help_str.split("\n")) * (font_height + 5)
simple_height = len(simple_help_str.split("\n")) * (font_height + 5)
A = CreateImg(
width + 150, height, font_size=24, color="white" if not ix % 2 else "black"
)
A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
simple_width = 0
for x in [tmp_img.getsize(x)[0] for x in simple_help_str.split("\n")]:
simple_width = simple_width if simple_width > x else x
bk = CreateImg(
simple_width + 20, simple_height, font_size=24, color="#6495ED"
)
B = CreateImg(
simple_width + 20,
simple_height,
font_size=24,
color="white" if not ix % 2 else "black",
)
B.text((10, 10), simple_help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
bk.paste(B, center_type="center")
bk.transparent(2)
ix += 1
help_img_list.append(A)
simple_help_img_list.append(bk)
height = 0
for img in help_img_list:
height += img.h
A = CreateImg(width + 150, height + 50, font_size=24)
A.text((10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n')
current_height = 50
for img in help_img_list:
A.paste(img, (0, current_height))
current_height += img.h
A.save(help_image)
height = 0
width = 0
for img in simple_help_img_list:
if img.h > height:
height = img.h
width += img.w + 10
B = CreateImg(width + 100, height + 250, font_size=24)
width, _ = get_max_width_or_paste(simple_help_img_list, B)
bk = None
random_bk = os.listdir(random_bk_path)
if random_bk:
bk = random.choice(random_bk)
x = max(width + 50, height + 250)
B = CreateImg(
x,
x,
font_size=24,
color="#FFEFD5",
background=random_bk_path / bk,
)
A.text(
(10, h * 0.77),
f"【注】「色图概率:好感度 + {int(INITIAL_SETU_PROBABILITY*100)}%\n"
f"\t\t每 3 点好感度 + 1次开箱,初始 {INITIAL_OPEN_CASE_COUNT} 次\n"
f"\t\t开启/关闭功能只需输入‘开启/关闭 指令名’(每个功能的第一个指令)」\n"
f"\t\t示例:开启签到\n"
f"\t\t可以通过管理员开关自动发送消息(早晚安等)\n"
f"\t\t^请查看管理员帮助^\n\n"
f"\t「如果{NICKNAME}回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【QAQ】」",
)
A.save(DATA_PATH + f"group_help/{group_id}.png")
B.filter("GaussianBlur", 10)
_, B = get_max_width_or_paste(simple_help_img_list, B, True)
w = 10
h = 10
for msg in ['目前支持的功能列表:', '可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法', '或者使用 ‘详细帮助’ 来获取所有功能方法']:
text = CreateImg(
0,
0,
plain_text=msg,
font_size=24,
color=(255, 255, 255, 0),
font='yuanshen.ttf'
)
B.paste(text, (w, h), True)
h += 50
if msg == '目前支持的功能列表:':
w += 50
B.save(simple_help_image)
def parse_cmd(cmd, group_id):
flag = "√"
dfg = None
if cmd.find("draw_card") != -1:
lst = cmd.split("_")
cmd = lst[0] + "_" + lst[1]
dfg = lst[-1]
elif cmd == "pixiv_r":
cmd = "pixiv"
dfg = "r"
elif cmd == "pixiv_s":
cmd = "pixiv"
dfg = "s"
if not group_manager.get_plugin_status(cmd, group_id):
flag = "×"
if cmd in ["bt", "reimu", "nickname"]:
flag = "- "
return flag, dfg
def get_max_width_or_paste(
simple_help_img_list: list, B: CreateImg = None, is_paste: bool = False
) -> "int, CreateImg":
"""
获取最大宽度,或直接贴图
:param simple_help_img_list: 简单帮助图片列表
:param B: 背景图
:param is_paste: 是否直接贴图
"""
current_width = 50
current_height = 180
max_width = simple_help_img_list[0].w
for i in range(len(simple_help_img_list)):
try:
if is_paste and B:
B.paste(simple_help_img_list[i], (current_width, current_height), True)
current_height += simple_help_img_list[i].h + 40
if current_height + simple_help_img_list[i + 1].h > B.h - 10:
current_height = 180
current_width += max_width + 30
max_width = 0
elif simple_help_img_list[i].w > max_width:
max_width = simple_help_img_list[i].w
except IndexError:
pass
if current_width > simple_help_img_list[0].w + 50:
current_width += simple_help_img_list[-1].w
return current_width, B
def rcmd(dfg):
if dfg in [
"prts",
"genshin",
"pretty",
"guardian",
"pcr",
"azur",
"onmyoji",
"fgo",
]:
return "draw_card_" + dfg
if dfg == "r":
return "pixiv_r"
if dfg == "s":
return "pixiv_s"
def get_plugin_help(msg: str) -> str:
plugin = None
for p in plugins2info_dict.keys():
if msg in plugins2info_dict[p]["cmd"]:
plugin = nonebot.plugin.get_plugin(p)
break
if plugin:
result = plugin.module.__getattribute__("__plugin_usage__")
return result
else:
return "没有此功能的帮助信息..."
def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
"""
获取功能的帮助信息
:param msg: 功能cmd
:param is_super: 是否为超级用户
"""
module = plugins2settings_manager.get_plugin_module(msg)
if module:
try:
plugin = nonebot.plugin.get_plugin(module)
if plugin:
if is_super:
result = plugin.module.__getattribute__(
"__plugin_superuser_usage__"
)
else:
result = plugin.module.__getattribute__("__plugin_usage__")
width = 0
for x in result.split("\n"):
_width = len(x) * 24
width = width if width > _width else _width
height = len(result.split("\n")) * 45
A = CreateImg(width, height, font_size=24)
bk = CreateImg(
width, height, background=Path(IMAGE_PATH) / "background" / "1.png"
)
A.paste(bk, alpha=True)
A.text((int(width * 0.048), int(height * 0.21)), result)
return A.pic2bs4()
except AttributeError:
pass
return None
+241 -46
View File
@@ -1,30 +1,45 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
from nonebot.adapters.cqhttp.exception import ActionFailed
from models.group_member_info import GroupInfoUser
from utils.manager import (
plugins2cd_manager,
plugins2block_manager,
plugins2settings_manager,
admin_manager
)
from models.friend_user import FriendUser
from typing import Optional
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import (
Bot,
Event,
MessageEvent,
PrivateMessageEvent,
GroupMessageEvent,
PokeNotifyEvent
PokeNotifyEvent,
Message,
)
from configs.config import (
BAN_RESULT,
admin_plugins_auth,
MALICIOUS_BAN_TIME,
MALICIOUS_CHECK_TIME,
MALICIOUS_BAN_COUNT,
CHECK_NOTICE_INFO_CD,
plugins2info_dict,
)
from models.ban_user import BanUser
from utils.utils import is_number, static_flmt, BanCheckLimiter
from utils.utils import (
is_number,
static_flmt,
BanCheckLimiter,
FreqLimiter,
)
from utils.manager import withdraw_message_manager
from utils.message_builder import at
from services.log import logger
from models.level_user import LevelUser
from utils.static_data import group_manager
from utils.utils import FreqLimiter
from utils.manager import group_manager
import asyncio
try:
import ujson as json
@@ -35,6 +50,14 @@ except ModuleNotFoundError:
# 检查是否被ban
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
try:
if (
await BanUser.is_super_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
):
raise IgnoredException("用户处于超级黑名单中")
except AttributeError:
pass
if not isinstance(event, MessageEvent):
return
if matcher.type == "message" and matcher.priority not in [1, 9]:
@@ -48,9 +71,9 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
if time < 60:
time = str(time) + " 秒"
else:
time = str(int(time / 60)) + " 分"
time = str(int(time / 60)) + " 分钟"
else:
time = str(time) + " 分"
time = str(time) + " 分钟"
if isinstance(event, GroupMessageEvent):
if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中")
@@ -61,7 +84,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
group_id=event.group_id,
message=at(event.user_id)
+ BAN_RESULT
+ f" 在..在 {time}后才会理你喔",
+ f" 在..在 {time} 后才会理你喔",
)
except ActionFailed:
pass
@@ -92,15 +115,10 @@ async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State
return
if matcher.type == "message" and matcher.priority not in [1, 9]:
if state["_prefix"]["raw_command"]:
# print(state["_prefix"]["raw_command"])
if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
if await BanUser.ban(event.user_id, 9, MALICIOUS_BAN_TIME * 60):
logger.info(f"USER {event.user_id} 触发了恶意触发检测")
# await update_img.finish('检测到恶意触发命令,您将被封禁 30 分钟', at_sender=True)
if event.message_type == "group":
if not static_flmt.check(event.user_id):
return
static_flmt.start_cd(event.user_id)
if isinstance(event, GroupMessageEvent):
try:
await bot.send_group_msg(
group_id=event.group_id,
@@ -109,9 +127,6 @@ async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State
except ActionFailed:
pass
else:
if not static_flmt.check(event.user_id):
return
static_flmt.start_cd(event.user_id)
try:
await bot.send_private_msg(
user_id=event.user_id,
@@ -127,23 +142,37 @@ _flmt = FreqLimiter(CHECK_NOTICE_INFO_CD)
_flmt_g = FreqLimiter(CHECK_NOTICE_INFO_CD)
_flmt_s = FreqLimiter(CHECK_NOTICE_INFO_CD)
_flmt_c = FreqLimiter(CHECK_NOTICE_INFO_CD)
_exists_msg = {}
ignore_rst_module = ["ai", "poke"]
# 权限检测
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
global _exists_msg
module = matcher.module
plugins2info_dict = plugins2settings_manager.get_data()
if (
(not isinstance(event, MessageEvent) and matcher.module != "poke")
(not isinstance(event, MessageEvent) and module != "poke")
or await BanUser.is_ban(event.user_id)
or str(event.user_id) in bot.config.superusers
and str(event.user_id) not in bot.config.superusers
) or (
str(event.user_id) in bot.config.superusers
and plugins2info_dict.get(module)
and not plugins2info_dict[module]["limit_superuser"]
):
return
module = matcher.module
if module in admin_plugins_auth.keys() and matcher.priority not in [1, 9]:
# 黑名单检测
if isinstance(event, GroupMessageEvent):
if group_manager.get_group_level(event.group_id) < 0:
raise IgnoredException("群黑名单")
if module in admin_manager.keys() and matcher.priority not in [1, 9]:
if isinstance(event, GroupMessageEvent):
# 个人权限
if not await LevelUser.check_level(
event.user_id, event.group_id, admin_plugins_auth[module]
event.user_id, event.group_id, admin_manager.get_plugin_level(module)
):
try:
if _flmt.check(event.user_id):
@@ -151,73 +180,88 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
await bot.send_group_msg(
group_id=event.group_id,
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
f"{admin_plugins_auth[module]}",
f"{admin_manager.get_plugin_level(module)}",
)
except ActionFailed:
pass
raise IgnoredException("权限不足")
else:
if not await LevelUser.check_level(
event.user_id, 0, admin_plugins_auth[module]
event.user_id, 0, admin_manager.get_plugin_level(module)
):
try:
await bot.send_private_msg(
user_id=event.user_id,
message=f"你的权限不足喔,该功能需要的权限等级:{admin_plugins_auth[module]}",
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}",
)
except ActionFailed:
pass
raise IgnoredException("权限不足")
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
# 戳一戳单独判断
if isinstance(event, GroupMessageEvent) or (isinstance(event, PokeNotifyEvent) and event.group_id):
if isinstance(event, GroupMessageEvent) or (
isinstance(event, PokeNotifyEvent) and event.group_id
):
if _exists_msg.get(event.group_id) is None:
_exists_msg[event.group_id] = False
# 群权限
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
str(event.group_id)
event.group_id
):
try:
if _flmt_g.check(event.user_id):
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
_flmt_g.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id, message="群权限不足..."
)
except ActionFailed:
pass
_exists_msg[event.group_id] = True
raise IgnoredException("群权限不足")
# 插件状态
if not group_manager.get_plugin_status(module, str(event.group_id)):
if not group_manager.get_plugin_status(module, event.group_id):
try:
if module != "poke" and _flmt_s.check(event.group_id):
if module not in ignore_rst_module and _flmt_s.check(
event.group_id
):
_flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该群未开启此功能.."
)
except ActionFailed:
pass
_exists_msg[event.group_id] = True
print(123123)
raise IgnoredException("未开启此功能...")
# 管理员禁用
if not group_manager.get_plugin_status(
f"{module}:super", str(event.group_id)
):
if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
try:
if _flmt_s.check(event.group_id):
if (
_flmt_s.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="管理员禁用了此群该功能..."
)
except ActionFailed:
pass
_exists_msg[event.group_id] = True
raise IgnoredException("管理员禁用了此群该功能...")
# 群聊禁用
if not group_manager.get_plugin_status(module, block_type="group"):
try:
if _flmt_c.check(event.group_id):
if (
_flmt_c.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该功能在群聊中已被禁用..."
)
except ActionFailed:
pass
_exists_msg[event.group_id] = True
raise IgnoredException("该插件在群聊中已被禁用...")
else:
# 私聊禁用
@@ -238,21 +282,160 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
) and group_manager.check_group_is_white(event.group_id):
return
try:
if _flmt_c.check(event.user_id):
_flmt_c.start_cd(event.user_id)
if isinstance(event, GroupMessageEvent):
if isinstance(event, GroupMessageEvent):
if (
_flmt_c.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="此功能正在维护..."
)
else:
await bot.send_private_msg(
user_id=event.user_id, message="此功能正在维护..."
)
else:
await bot.send_private_msg(
user_id=event.user_id, message="此功能正在维护..."
)
except ActionFailed:
pass
if isinstance(event, GroupMessageEvent):
_exists_msg[event.group_id] = True
raise IgnoredException("此功能正在维护...")
# 命令cd 和 命令阻塞
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
global _exists_msg
if not isinstance(event, MessageEvent) and matcher.module != "poke":
return
module = matcher.module
if isinstance(event, GroupMessageEvent) and _exists_msg.get(event.group_id) is None:
_exists_msg[event.group_id] = False
if plugins2cd_manager.check_plugin_cd_status(module):
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
check_type = plugin_cd_data["check_type"]
limit_type = plugin_cd_data["limit_type"]
rst = plugin_cd_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
):
cd_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
cd_type_ = event.group_id
if not plugins2cd_manager.check(module, cd_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} 正在cd中...")
else:
plugins2cd_manager.start_cd(module, cd_type_)
if plugins2block_manager.check_plugin_block_status(module):
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
check_type = plugin_block_data["check_type"]
limit_type = plugin_block_data["limit_type"]
rst = plugin_block_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or check_type == "all"
):
block_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
block_type_ = event.group_id
if plugins2block_manager.check(block_type_, module):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{event.user_id}正在调用{module}....")
else:
plugins2block_manager.set_true(block_type_, module)
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
"""
发送信息
:param rst: pass
:param bot: pass
:param event: pass
"""
global _exists_msg
rst = await init_rst(rst, event)
try:
if isinstance(event, GroupMessageEvent):
_exists_msg[event.group_id] = True
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
else:
_exists_msg[event.user_id] = True
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
except ActionFailed:
pass
@run_postprocessor
async def _(
matcher: Matcher,
exception: Optional[Exception],
bot: Bot,
event: Event,
state: T_State,
):
if not isinstance(event, MessageEvent) and matcher.module != "poke":
return
module = matcher.module
if plugins2block_manager.check_plugin_block_status(module):
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
check_type = plugin_block_data["check_type"]
limit_type = plugin_block_data["limit_type"]
if not (
(isinstance(event, GroupMessageEvent) and check_type == "private")
or (isinstance(event, PrivateMessageEvent) and check_type == "group")
):
block_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
block_type_ = event.group_id
plugins2block_manager.set_false(block_type_, module)
async def init_rst(rst: str, event: MessageEvent):
if "[uname]" in rst:
uname = event.sender.card if event.sender.card else event.sender.nickname
rst = rst.replace("[uname]", uname)
if "[nickname]" in rst:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
rst = rst.replace("[nickname]", nickname)
if "[at]" in rst and isinstance(event, GroupMessageEvent):
rst = rst.replace("[at]", str(at(event.user_id)))
return rst
# 消息撤回
@run_postprocessor
async def _(
matcher: Matcher,
exception: Optional[Exception],
bot: Bot,
event: Event,
state: T_State,
):
tasks = []
for id_, time in withdraw_message_manager.data:
tasks.append(asyncio.ensure_future(_withdraw_message(bot, id_, time)))
withdraw_message_manager.remove((id_, time))
await asyncio.gather(*tasks)
async def _withdraw_message(bot: Bot, id_: int, time: int):
await asyncio.sleep(time)
await bot.delete_msg(message_id=id_, self_id=int(bot.self_id))
# 为什么AI会自己和自己聊天
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_State):
@@ -265,8 +448,20 @@ async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_Sta
# 有命令就别说话了
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
global _exists_msg
if not isinstance(event, MessageEvent):
return
if matcher.type == "message":
if state["_prefix"]["raw_command"] and matcher.module == "ai":
raise IgnoredException("有命令就别说话了")
if matcher.module == "ai":
if (
isinstance(event, GroupMessageEvent)
and _exists_msg.get(event.group_id) is True
):
_exists_msg[event.group_id] = False
raise IgnoredException("有命令就别说话了")
elif (
isinstance(event, PrivateMessageEvent)
and _exists_msg.get(event.user_id) is True
):
_exists_msg[event.user_id] = False
raise IgnoredException("有命令就别说话了")
+3
View File
@@ -0,0 +1,3 @@
import nonebot
nonebot.load_plugins("plugins/image_management")
@@ -1,86 +1,97 @@
from configs.path_config import IMAGE_PATH, TEMP_PATH
from utils.message_builder import image
from services.log import logger
from nonebot import on_command
from nonebot.rule import to_me
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from configs.config import IMAGE_DIR_LIST
from utils.utils import is_number, cn2py
from pathlib import Path
import os
__plugin_name__ = "删除图片"
__plugin_usage__ = (
"删除图片帮助:\n\t"
"1.查看列表 --> 指令: 删除图片 列表/目录\n\t"
"2.删除图片 图库 id, 即在相应目录下删除图片\n\t\t示例: 删除图片 色图 1 "
)
delete_img = on_command("删除图片", priority=5, rule=to_me(), block=True)
@delete_img.args_parser
async def parse(bot: Bot, event: MessageEvent, state: T_State):
if str(event.get_message()) in ["取消", "算了"]:
await delete_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["path"]:
if str(event.get_message()) not in IMAGE_DIR_LIST:
await delete_img.reject("此目录不正确,请重新输入目录!")
state[state["_current_key"]] = str(event.get_message())
if state["_current_key"] == "id":
if not is_number(str(event.get_message())):
await delete_img.reject("id不正确!请重新输入数字...")
state[state["_current_key"]] = str(event.get_message())
@delete_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
raw_arg = str(event.get_message()).strip()
if raw_arg:
args = raw_arg.split(" ")
if args[0] in ["帮助"]:
await delete_img.finish(__plugin_usage__)
if len(args) >= 2 and args[0] in IMAGE_DIR_LIST and is_number(args[1]):
state["path"] = args[0]
state["id"] = args[1]
@delete_img.got("path", prompt="请输入要删除的目标图库?")
@delete_img.got("id", prompt="请输入要删除的图片id?")
async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
path = cn2py(state["path"])
img_id = state["id"]
# path = IMAGE_PATH + path
path = Path(IMAGE_PATH) / path
temp = Path(IMAGE_PATH) / 'temp'
max_id = len(os.listdir(path)) - 1
if int(img_id) > max_id or int(img_id) < 0:
await delete_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True)
try:
if os.path.exists(temp / "delete.jpg"):
os.remove(temp / "delete.jpg")
logger.info("删除图片 delete.jpg 成功")
except Exception as e:
logger.warning(f"删除图片 delete.jpg 失败 e{e}")
try:
os.rename(path / f"{img_id}.jpg", temp / "delete.jpg")
logger.info(f"移动 {path}/{img_id}.jpg 移动成功")
except Exception as e:
logger.warning(f"{path}/{img_id}.jpg --> 移动失败 e:{e}")
if not os.path.exists(path / f"{img_id}.jpg"):
try:
if int(img_id) != max_id:
os.rename(path / f"{max_id}.jpg", path / f"{img_id}.jpg")
except FileExistsError as e:
logger.error(f"{path}/{max_id}.jpg 替换 {path}/{img_id}.jpg 失败 e:{e}")
logger.info(f"{path}/{max_id}.jpg 替换 {path}/{img_id}.jpg 成功")
logger.info(
f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}"
f" -> id: {img_id} 删除成功"
)
await delete_img.finish(
f"id: {img_id} 删除成功" + image("delete.jpg", TEMP_PATH), at_sender=True
)
await delete_img.finish(f"id: {img_id} 删除失败!")
from configs.path_config import IMAGE_PATH, TEMP_PATH
from utils.message_builder import image
from services.log import logger
from nonebot import on_command
from nonebot.rule import to_me
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from configs.config import DELETE_IMG_LEVEL
from configs.config import IMAGE_DIR_LIST
from utils.utils import is_number, cn2py, get_message_text
from pathlib import Path
import os
__zx_plugin_name__ = "删除图片 [Admin]"
__plugin_usage__ = """
usage:
删除图库指定图片
指令:
删除图片 [图库] [id]
查看图库
示例:删除图片 美图 666
""".strip()
__plugin_des__ = "不好看的图片删掉删掉!"
__plugin_cmd__ = ["删除图片 [图库] [id]", "查看公开图库"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"admin_level": DELETE_IMG_LEVEL
}
delete_img = on_command("删除图片", priority=5, rule=to_me(), block=True)
@delete_img.args_parser
async def parse(bot: Bot, event: MessageEvent, state: T_State):
if get_message_text(event.json()) in ["取消", "算了"]:
await delete_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["path"]:
if get_message_text(event.json()) not in IMAGE_DIR_LIST:
await delete_img.reject("此目录不正确,请重新输入目录!")
state[state["_current_key"]] = get_message_text(event.json())
if state["_current_key"] == "id":
if not is_number(get_message_text(event.json())):
await delete_img.reject("id不正确!请重新输入数字...")
state[state["_current_key"]] = get_message_text(event.json())
@delete_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
raw_arg = get_message_text(event.json()).strip()
if raw_arg:
args = raw_arg.split(" ")
if args[0] in ["帮助"]:
await delete_img.finish(__plugin_usage__)
if len(args) >= 2 and args[0] in IMAGE_DIR_LIST and is_number(args[1]):
state["path"] = args[0]
state["id"] = args[1]
@delete_img.got("path", prompt="请输入要删除的目标图库?")
@delete_img.got("id", prompt="请输入要删除的图片id?")
async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
path = cn2py(state["path"])
img_id = state["id"]
# path = IMAGE_PATH + path
path = Path(IMAGE_PATH) / path
temp = Path(IMAGE_PATH) / "temp"
max_id = len(os.listdir(path)) - 1
if int(img_id) > max_id or int(img_id) < 0:
await delete_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True)
try:
if os.path.exists(temp / "delete.jpg"):
os.remove(temp / "delete.jpg")
logger.info("删除图片 delete.jpg 成功")
except Exception as e:
logger.warning(f"删除图片 delete.jpg 失败 e{e}")
try:
os.rename(path / f"{img_id}.jpg", temp / "delete.jpg")
logger.info(f"移动 {path}/{img_id}.jpg 移动成功")
except Exception as e:
logger.warning(f"{path}/{img_id}.jpg --> 移动失败 e:{e}")
if not os.path.exists(path / f"{img_id}.jpg"):
try:
if int(img_id) != max_id:
os.rename(path / f"{max_id}.jpg", path / f"{img_id}.jpg")
except FileExistsError as e:
logger.error(f"{path}/{max_id}.jpg 替换 {path}/{img_id}.jpg 失败 e:{e}")
logger.info(f"{path}/{max_id}.jpg 替换 {path}/{img_id}.jpg 成功")
logger.info(
f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}"
f" -> id: {img_id} 删除成功"
)
await delete_img.finish(
f"id: {img_id} 删除成功" + image("delete.jpg", TEMP_PATH), at_sender=True
)
await delete_img.finish(f"id: {img_id} 删除失败!")
@@ -1,95 +1,105 @@
import os
from services.log import logger
from nonebot import on_command
from nonebot.rule import to_me
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from configs.config import IMAGE_DIR_LIST
from utils.utils import is_number, cn2py
from configs.path_config import IMAGE_PATH
from pathlib import Path
__plugin_name__ = "移动图片"
__plugin_usage__ = (
"移动图片帮助:\n\t"
"1.查看列表 --> 指令: 移动图片 列表/目录\n\t"
"2.移动图片 源 目的 id\n\t\t示例: 移动图片 色图 美图 1234"
)
move_img = on_command("移动图片", priority=5, rule=to_me(), block=True)
@move_img.args_parser
async def parse(bot: Bot, event: MessageEvent, state: T_State):
if str(event.get_message()) in ["取消", "算了"]:
await move_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["source_path", "destination_path"]:
if str(event.get_message()) not in IMAGE_DIR_LIST:
await move_img.reject("此目录不正确,请重新输入目录!")
state[state["_current_key"]] = str(event.get_message())
if state["_current_key"] == "id":
if not is_number(str(event.get_message())):
await move_img.reject("id不正确!请重新输入数字...")
state[state["_current_key"]] = str(event.get_message())
@move_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
raw_arg = str(event.get_message()).strip()
if raw_arg:
args = raw_arg.split(" ")
if args[0] in ["帮助"]:
await move_img.finish(__plugin_usage__)
if (
len(args) >= 3
and args[0] in IMAGE_DIR_LIST
and args[1] in IMAGE_DIR_LIST
and is_number(args[2])
):
state["source_path"] = args[0]
state["destination_path"] = args[1]
state["id"] = args[2]
else:
await move_img.finish("参数错误,请重试", at_sender=True)
@move_img.got("source_path", prompt="要从哪个图库移出?")
@move_img.got("destination_path", prompt="要移动到哪个图库?")
@move_img.got("id", prompt="要移动的图片id是?")
async def _(bot: Bot, event: MessageEvent, state: T_State):
img_id = state["id"]
source_path = Path(IMAGE_PATH) / cn2py(state["source_path"])
destination_path = Path(IMAGE_PATH) / cn2py(state["destination_path"])
destination_path.mkdir(parents=True, exist_ok=True)
max_id = len(os.listdir(source_path)) - 1
des_max_id = len(os.listdir(destination_path))
if int(img_id) > max_id or int(img_id) < 0:
await move_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True)
try:
os.rename(
source_path / f"{img_id}.jpg", destination_path / f"{des_max_id}.jpg"
)
logger.info(
f"移动 {source_path}/{img_id}.jpg ---> {destination_path}/{des_max_id} 移动成功"
)
except Exception as e:
logger.warning(
f"移动 {source_path}/{img_id}.jpg ---> {destination_path}/{des_max_id} 移动失败 e:{e}"
)
await move_img.finish(f"移动图片id:{img_id} 失败了...", at_sender=True)
if max_id > 0:
try:
os.rename(source_path / f"{max_id}.jpg", source_path / f"{img_id}.jpg")
logger.info(f"{source_path}/{max_id}.jpg 替换 {source_path}/{img_id}.jpg 成功")
except Exception as e:
logger.warning(
f"{source_path}/{max_id}.jpg 替换 {source_path}/{img_id}.jpg 失败 e:{e}"
)
await move_img.finish(f"替换图片id:{max_id} -> {img_id} 失败了...", at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'} ->"
f" {source_path} --> {destination_path} (id:{img_id}) 移动图片成功"
)
await move_img.finish(f"移动图片 id:{img_id} --> id:{des_max_id}成功", at_sender=True)
import os
from services.log import logger
from nonebot import on_command
from nonebot.rule import to_me
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from configs.config import IMAGE_DIR_LIST, MOVE_IMG_LEVEL
from utils.utils import is_number, cn2py
from configs.path_config import IMAGE_PATH
from pathlib import Path
__zx_plugin_name__ = "移动图片 [Admin]"
__plugin_usage__ = """
usage:
图库间的图片移动操作
指令:
移动图片 [源图库] [目标图库] [id]
查看图库
示例:移动图片 萝莉 美图 234
""".strip()
__plugin_des__ = "图库间的图片移动操作"
__plugin_cmd__ = ["移动图片 [源图库] [目标图库] [id]", "查看公开图库"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"admin_level": MOVE_IMG_LEVEL
}
move_img = on_command("移动图片", priority=5, rule=to_me(), block=True)
@move_img.args_parser
async def parse(bot: Bot, event: MessageEvent, state: T_State):
if str(event.get_message()) in ["取消", "算了"]:
await move_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["source_path", "destination_path"]:
if str(event.get_message()) not in IMAGE_DIR_LIST:
await move_img.reject("此目录不正确,请重新输入目录!")
state[state["_current_key"]] = str(event.get_message())
if state["_current_key"] == "id":
if not is_number(str(event.get_message())):
await move_img.reject("id不正确!请重新输入数字...")
state[state["_current_key"]] = str(event.get_message())
@move_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
raw_arg = str(event.get_message()).strip()
if raw_arg:
args = raw_arg.split(" ")
if args[0] in ["帮助"]:
await move_img.finish(__plugin_usage__)
if (
len(args) >= 3
and args[0] in IMAGE_DIR_LIST
and args[1] in IMAGE_DIR_LIST
and is_number(args[2])
):
state["source_path"] = args[0]
state["destination_path"] = args[1]
state["id"] = args[2]
else:
await move_img.finish("参数错误,请重试", at_sender=True)
@move_img.got("source_path", prompt="要从哪个图库移出?")
@move_img.got("destination_path", prompt="要移动到哪个图库?")
@move_img.got("id", prompt="要移动的图片id是?")
async def _(bot: Bot, event: MessageEvent, state: T_State):
img_id = state["id"]
source_path = Path(IMAGE_PATH) / cn2py(state["source_path"])
destination_path = Path(IMAGE_PATH) / cn2py(state["destination_path"])
destination_path.mkdir(parents=True, exist_ok=True)
max_id = len(os.listdir(source_path)) - 1
des_max_id = len(os.listdir(destination_path))
if int(img_id) > max_id or int(img_id) < 0:
await move_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True)
try:
os.rename(
source_path / f"{img_id}.jpg", destination_path / f"{des_max_id}.jpg"
)
logger.info(
f"移动 {source_path}/{img_id}.jpg ---> {destination_path}/{des_max_id} 移动成功"
)
except Exception as e:
logger.warning(
f"移动 {source_path}/{img_id}.jpg ---> {destination_path}/{des_max_id} 移动失败 e:{e}"
)
await move_img.finish(f"移动图片id:{img_id} 失败了...", at_sender=True)
if max_id > 0:
try:
os.rename(source_path / f"{max_id}.jpg", source_path / f"{img_id}.jpg")
logger.info(f"{source_path}/{max_id}.jpg 替换 {source_path}/{img_id}.jpg 成功")
except Exception as e:
logger.warning(
f"{source_path}/{max_id}.jpg 替换 {source_path}/{img_id}.jpg 失败 e:{e}"
)
await move_img.finish(f"替换图片id:{max_id} -> {img_id} 失败了...", at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'} ->"
f" {source_path} --> {destination_path} (id:{img_id}) 移动图片成功"
)
await move_img.finish(f"移动图片 id:{img_id} --> id:{des_max_id}成功", at_sender=True)
@@ -1,101 +1,127 @@
from nonebot import on_command
from nonebot.rule import to_me
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from utils.utils import get_message_imgs, get_message_text
from .data_source import upload_image_to_local
__plugin_name__ = "上传图片"
__plugin_usage__ = (
"上传图片帮助:\n\t"
"1.查看列表 --> 指令: 上传图片 列表/目录\n\t"
"2.上传图片 [序号] [图片], 即在相应目录下添加图片\n\t\t示例: 上传图片 1 [图片]"
)
upload_img = on_command("上传图片", rule=to_me(), priority=5, block=True)
continuous_upload_img = on_command('连续上传图片', rule=to_me(), priority=5, block=True)
@upload_img.args_parser
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if msg in ["取消", "算了"]:
await upload_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["path"]:
if msg not in IMAGE_DIR_LIST:
await upload_img.reject("此目录不正确,请重新输入目录!")
state['path'] = msg
if state["_current_key"] in ["imgs"]:
if not get_message_imgs(event.json()):
await upload_img.reject("图呢图呢图呢图呢!GKD!")
state['imgs'] = get_message_imgs(event.json())
@upload_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
raw_arg = get_message_text(event.json())
img_list = get_message_imgs(event.json())
if raw_arg:
if raw_arg in IMAGE_DIR_LIST:
state["path"] = raw_arg
if img_list:
state["imgs"] = img_list
@upload_img.got('path', prompt='要将图片上传至什么图库呢?')
async def _(bot: Bot, event: MessageEvent, state: T_State):
pass
@upload_img.got("imgs", prompt="图呢图呢图呢图呢!GKD!")
async def _(bot: Bot, event: MessageEvent, state: T_State):
path = state['path']
img_list = state['imgs']
group_id = 0
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
await upload_img.send(await upload_image_to_local(img_list, path, event.user_id, group_id))
@continuous_upload_img.args_parser
async def _(bot: Bot, event: MessageEvent, state: T_State):
if str(event.get_message()) in ["取消", "算了"]:
await continuous_upload_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["path"]:
if str(event.get_message()) not in IMAGE_DIR_LIST:
await continuous_upload_img.reject("此目录不正确,请重新输入目录!")
state[state["_current_key"]] = str(event.get_message())
else:
if get_message_text(event.json()) not in ['stop']:
img = get_message_imgs(event.json())
if img:
state['tmp'].extend(img)
await continuous_upload_img.reject('图再来!!')
else:
state['imgs'] = state['tmp']
@continuous_upload_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
path = get_message_imgs(event.json())
if path in IMAGE_DIR_LIST:
state['path'] = path
await continuous_upload_img.send('图来!!')
state['tmp'] = []
@continuous_upload_img.got("path", prompt="要将图片上传至什么图库呢?")
async def _(bot: Bot, event: MessageEvent, state: T_State):
pass
@continuous_upload_img.got("imgs", prompt="图呢图呢图呢图呢!GKD!")
async def _(bot: Bot, event: MessageEvent, state: T_State):
path = state['path']
img_list = state['imgs']
group_id = 0
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
await continuous_upload_img.send(await upload_image_to_local(img_list, path, event.user_id, group_id))
from nonebot import on_command
from nonebot.rule import to_me
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from configs.config import IMAGE_DIR_LIST, UPLOAD_IMG_LEVEL
from utils.utils import get_message_imgs, get_message_text
from .data_source import upload_image_to_local
__zx_plugin_name__ = "上传图片 [Admin]"
__plugin_usage__ = """
usage:
上传图片至指定图库
指令:
查看图库
上传图片 [图库] [图片]
连续上传图片 [图库]
示例:上传图片 美图 [图片]
* 连续上传图片可以通过发送 “stop” 表示停止收集发送的图片,可以开始上传 *
""".strip()
__plugin_des__ = "指定图库图片上传"
__plugin_cmd__ = ["上传图片 [图库] [图片]", "连续上传图片 [图库]", "查看公开图库"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {"admin_level": UPLOAD_IMG_LEVEL}
upload_img = on_command("上传图片", rule=to_me(), priority=5, block=True)
continuous_upload_img = on_command("连续上传图片", rule=to_me(), priority=5, block=True)
show_gallery = on_command("查看公开图库", priority=1, block=True)
@show_gallery.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
x = '公开图库列表:\n'
for i, e in enumerate(IMAGE_DIR_LIST):
x += f'\t{i+1}.{e}\n'
await show_gallery.send(x[:-1])
@upload_img.args_parser
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if msg in ["取消", "算了"]:
await upload_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["path"]:
if msg not in IMAGE_DIR_LIST:
await upload_img.reject("此目录不正确,请重新输入目录!")
state["path"] = msg
if state["_current_key"] in ["imgs"]:
if not get_message_imgs(event.json()):
await upload_img.reject("图呢图呢图呢图呢!GKD!")
state["imgs"] = get_message_imgs(event.json())
@upload_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
raw_arg = get_message_text(event.json())
img_list = get_message_imgs(event.json())
if raw_arg:
if raw_arg in IMAGE_DIR_LIST:
state["path"] = raw_arg
if img_list:
state["imgs"] = img_list
@upload_img.got("path", prompt="要将图片上传至什么图库呢?")
async def _(bot: Bot, event: MessageEvent, state: T_State):
pass
@upload_img.got("imgs", prompt="图呢图呢图呢图呢!GKD!")
async def _(bot: Bot, event: MessageEvent, state: T_State):
path = state["path"]
img_list = state["imgs"]
group_id = 0
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
await upload_img.send(
await upload_image_to_local(img_list, path, event.user_id, group_id)
)
@continuous_upload_img.args_parser
async def _(bot: Bot, event: MessageEvent, state: T_State):
if str(event.get_message()) in ["取消", "算了"]:
await continuous_upload_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["path"]:
if str(event.get_message()) not in IMAGE_DIR_LIST:
await continuous_upload_img.reject("此目录不正确,请重新输入目录!")
state[state["_current_key"]] = str(event.get_message())
else:
if get_message_text(event.json()) not in ["stop"]:
img = get_message_imgs(event.json())
if img:
state["tmp"].extend(img)
await continuous_upload_img.reject("图再来!!")
else:
state["imgs"] = state["tmp"]
@continuous_upload_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
path = get_message_imgs(event.json())
if path in IMAGE_DIR_LIST:
state["path"] = path
await continuous_upload_img.send("图来!!")
state["tmp"] = []
@continuous_upload_img.got("path", prompt="要将图片上传至什么图库呢?")
async def _(bot: Bot, event: MessageEvent, state: T_State):
pass
@continuous_upload_img.got("imgs", prompt="图呢图呢图呢图呢!GKD!")
async def _(bot: Bot, event: MessageEvent, state: T_State):
path = state["path"]
img_list = state["imgs"]
group_id = 0
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
await continuous_upload_img.send(
await upload_image_to_local(img_list, path, event.user_id, group_id)
)
+36
View File
@@ -0,0 +1,36 @@
from .data_source import (
init_plugins_settings,
init_plugins_cd_limit,
init_plugins_block_limit,
init_group_manager,
)
from nonebot.adapters.cqhttp import Bot
from configs.path_config import DATA_PATH
from services.log import logger
from nonebot import Driver
import nonebot
__zx_plugin_name__ = "初始化插件数据 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
driver: Driver = nonebot.get_driver()
@driver.on_startup
def _():
"""
初始化数据
"""
init_plugins_settings(DATA_PATH)
init_plugins_cd_limit(DATA_PATH)
init_plugins_block_limit(DATA_PATH)
logger.info("初始化数据完成...")
@driver.on_bot_connect
async def _(bot: Bot):
await init_group_manager()
+289
View File
@@ -0,0 +1,289 @@
from pathlib import Path
from ruamel.yaml import YAML, round_trip_load, round_trip_dump
from utils.manager import (
plugins2settings_manager,
plugins2cd_manager,
plugins2block_manager,
group_manager,
admin_manager
)
from services.db_context import db
from asyncpg.exceptions import DuplicateColumnError
from services.log import logger
from utils.utils import get_matchers
import nonebot
try:
import ujson as json
except ModuleNotFoundError:
import json
try:
from models.group_remind import GroupRemind
except ModuleNotFoundError:
pass
yaml = YAML(typ="safe")
def init_plugins_settings(data_path: str):
"""
初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
"""
plugins2config_file = Path(data_path) / "configs" / "plugins2settings.yaml"
plugins2config_file.parent.mkdir(exist_ok=True, parents=True)
_matchers = get_matchers()
_data = {}
if plugins2config_file.exists():
with open(plugins2config_file, "r", encoding="utf8") as f:
_data = yaml.load(f)
_data = _data["PluginSettings"] if _data else {}
_tmp_module = {}
_tmp = []
for matcher in _matchers:
if matcher.module in _data.keys():
plugins2settings_manager.add_plugin_settings(
matcher.module,
plugin_type=_data[matcher.module]["plugin_type"],
data_dict=_data[matcher.module],
)
if _data[matcher.module]['cmd']:
_tmp_module[matcher.module] = _data[matcher.module]['cmd'][0]
else:
_plugin = nonebot.plugin.get_plugin(matcher.module)
_module = _plugin.module
try:
plugin_name = _module.__getattribute__("__zx_plugin_name__")
if "[admin]" in plugin_name.lower():
try:
level = (_module.__getattribute__("__plugin_settings__"))['admin_level']
except (AttributeError, KeyError):
level = 5
admin_manager.add_admin_command(matcher.module, level)
if (
"[hidden]" in plugin_name.lower()
or "[admin]" in plugin_name.lower()
or "[superuser]" in plugin_name.lower()
or matcher.module in plugins2settings_manager.keys()
):
continue
except AttributeError:
if matcher.module not in _tmp:
logger.warning(
f"获取插件 {matcher.module} __zx_plugin_name__ 失败...,插件控制未加载."
)
else:
try:
_tmp_module[matcher.module] = plugin_name
plugin_settings = _module.__getattribute__("__plugin_settings__")
if plugin_settings['cmd'] and plugin_name not in plugin_settings['cmd']:
plugin_settings['cmd'].append(plugin_name)
if plugins2settings_manager.get(
matcher.module
) and plugins2settings_manager[matcher.module].get("plugin_type"):
plugin_type = tuple(
plugins2settings_manager.get_plugin_data(matcher.module)[
"plugin_type"
]
)
else:
try:
plugin_type = _module.__getattribute__("__plugin_type__")
except AttributeError:
plugin_type = ("normal",)
if plugin_settings and matcher.module:
plugins2settings_manager.add_plugin_settings(
matcher.module,
plugin_type=plugin_type,
data_dict=plugin_settings,
)
except AttributeError:
pass
_tmp.append(matcher.module)
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
with open(plugins2config_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf)
_data = round_trip_load(open(plugins2config_file, encoding="utf8"))
_data["PluginSettings"].yaml_set_start_comment(
"""# 模块与对应命令和对应群权限
# 用于生成帮助图片 和 开关功能
# key:模块名称
# level:需要的群等级
# default_status:加入群时功能的默认开关状态
# limit_superuser: 功能状态是否限制超级用户
# cmd: 关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称
# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1),1代表帮助命令列向排列,否则为横向排列""",
indent=2,
)
for plugin in _data["PluginSettings"].keys():
_data["PluginSettings"][plugin].yaml_set_start_comment(
f"{plugin}:{_tmp_module[plugin]}", indent=2
)
with open(plugins2config_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf)
logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")
def init_plugins_cd_limit(data_path):
"""
加载 cd 限制
"""
plugins2cd_file = Path(data_path) / "configs" / "plugins2cd.yaml"
plugins2cd_file.parent.mkdir(exist_ok=True, parents=True)
_data = {}
_matchers = get_matchers()
for matcher in _matchers:
if not plugins2cd_manager.get_plugin_cd_data(matcher.module):
_plugin = nonebot.plugin.get_plugin(matcher.module)
_module = _plugin.module
try:
plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
plugins2cd_manager.add_cd_limit(
matcher.module, data_dict=plugin_cd_limit
)
except AttributeError:
pass
if plugins2cd_file.exists():
with open(plugins2cd_file, "r", encoding="utf8") as f:
_data = yaml.load(f)
_data = _data if _data else {}
if _data.get("PluginCdLimit"):
for plugin in _data["PluginCdLimit"].keys():
plugins2cd_manager.add_cd_limit(
plugin, data_dict=_data["PluginCdLimit"][plugin]
)
_tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()}
with open(plugins2cd_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf)
_data = round_trip_load(open(plugins2cd_file, encoding="utf8"))
_data["PluginCdLimit"].yaml_set_start_comment(
"""# 需要cd的功能
# 自定义的功能需要cd也可以在此配置
# key:模块名称
# cd:cd 时长(秒)
# status:此限制的开关状态
# check_type:'private'/'group'/'all',限制私聊/群聊/全部
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(plugins2cd_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf)
plugins2cd_manager.reload_cd_limit()
def init_plugins_block_limit(data_path):
"""
加载阻塞限制
"""
plugins2block_file = Path(data_path) / "configs" / "plugins2block.yaml"
plugins2block_file.parent.mkdir(exist_ok=True, parents=True)
_data = {}
_matchers = get_matchers()
for matcher in _matchers:
if not plugins2block_manager.get_plugin_block_data(matcher.module):
_plugin = nonebot.plugin.get_plugin(matcher.module)
_module = _plugin.module
try:
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
plugins2block_manager.add_block_limit(
matcher.module, data_dict=plugin_block_limit
)
except AttributeError:
pass
if plugins2block_file.exists():
with open(plugins2block_file, "r", encoding="utf8") as f:
_data = yaml.load(f)
_data = _data if _data else {}
if _data.get("PluginBlockLimit"):
for plugin in _data["PluginBlockLimit"].keys():
plugins2block_manager.add_block_limit(
plugin, data_dict=_data["PluginBlockLimit"][plugin]
)
_tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()}
with open(plugins2block_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf)
_data = round_trip_load(open(plugins2block_file, encoding="utf8"))
_data["PluginBlockLimit"].yaml_set_start_comment(
"""# 用户调用阻塞
# 即 当用户调用此功能还未结束时
# 用发送消息阻止用户重复调用此命令直到该命令结束
# key:模块名称
# cd:cd 时长(秒)
# status:此限制的开关状态
# check_type:'private'/'group'/'all',限制私聊/群聊/全部
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(plugins2block_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf)
plugins2block_manager.reload_block_limit()
async def init_group_manager():
"""
旧数据格式替换为新格式
初始化数据
"""
old_group_level_file = Path() / "data" / "manager" / "group_level.json"
old_plugin_list_file = Path() / "data" / "manager" / "plugin_list.json"
if old_group_level_file.exists():
data = json.load(open(old_group_level_file, "r", encoding="utf8"))
for key in data.keys():
group = key
level = data[key]
group_manager.set_group_level(group, level)
old_group_level_file.unlink()
group_manager.save()
if old_plugin_list_file.exists():
data = json.load(open(old_plugin_list_file, "r", encoding="utf8"))
for plugin in data.keys():
for group in data[plugin].keys():
if group == "default" and not data[plugin]["default"]:
group_manager.block_plugin(plugin)
elif not data[plugin][group]:
group_manager.block_plugin(plugin, group)
old_plugin_list_file.unlink()
old_data_table = Path() / "models" / "group_remind.py"
try:
if old_data_table.exists():
b = {
"hy": "group_welcome",
"kxcz": "open_case_reset_remind",
"zwa": "zwa",
"blpar": "bilibili_parse",
"epic": "epic_free_game",
"pa": "pa",
"almanac": "genshin_alc",
}
for group in group_manager.get_data()["group_manager"]:
for remind in b:
try:
status = await GroupRemind.get_status(int(group), remind)
if status is not None:
if status:
await group_manager.open_group_task(group, b[remind])
logger.info(f"读取旧数据-->{group} 开启 {b[remind]}")
else:
await group_manager.close_group_task(group, b[remind])
logger.info(f"读取旧数据-->{group} 关闭 {b[remind]}")
except Exception as e:
pass
query = db.text("DROP TABLE group_reminds;")
await db.first(query)
old_data_table.unlink()
logger.info("旧数据读取完毕,删除了舍弃表 group_reminds...")
except (ModuleNotFoundError, DuplicateColumnError):
pass
group_manager.save()
+17 -3
View File
@@ -5,11 +5,25 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State
import aiohttp
from asyncio.exceptions import TimeoutError
from configs.config import NICKNAME
__plugin_name__ = "鸡汤"
__plugin_usage__ = f"用法: 发送’鸡汤‘,{NICKNAME}亲自为你喝鸡汤"
__zx_plugin_name__ = "鸡汤"
__plugin_usage__ = """
usage:
不喝点什么感觉有点不舒服
指令:
鸡汤
""".strip()
__plugin_des__ = "喏,亲手为你煮的鸡汤"
__plugin_cmd__ = ["鸡汤"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["鸡汤", "毒鸡汤"],
}
url = "https://v2.alapi.cn/api/soul"
+44 -46
View File
@@ -1,28 +1,41 @@
from PIL import ImageFont, ImageDraw, Image
import textwrap
from configs.path_config import IMAGE_PATH, TTF_PATH
from configs.path_config import IMAGE_PATH
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from utils.message_builder import image
from services.log import logger
from utils.utils import UserExistLimiter, get_message_text
from utils.image_utils import pic2b64
__plugin_name__ = "鲁迅说"
__plugin_usage__ = "用法:鲁迅说 [消息]"
_ulmt = UserExistLimiter()
from utils.utils import get_message_text
from utils.image_utils import CreateImg
__zx_plugin_name__ = "鲁迅说"
__plugin_usage__ = """
usage:
鲁迅说了啥?
指令:
鲁迅说 [文本]
""".strip()
__plugin_des__ = "鲁迅说他没说过这话!"
__plugin_cmd__ = ["鲁迅说"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["鲁迅说"],
}
__plugin_block_limit__ = {
"rst": "你的鲁迅正在说,等会"
}
luxun = on_command("鲁迅说过", aliases={"鲁迅说"}, priority=5, block=True)
luxun_author = CreateImg(0, 0, plain_text="--鲁迅", font_size=30, font='msyh.ttf', font_color=(255, 255, 255))
@luxun.handle()
async def handle(bot: Bot, event: MessageEvent, state: T_State):
if _ulmt.check(event.user_id):
await luxun.finish("你的鲁迅正在说,等会", at_sender=True)
args = get_message_text(event.json())
if args:
state["content"] = args if args else "烦了,不说了"
@@ -30,39 +43,24 @@ async def handle(bot: Bot, event: MessageEvent, state: T_State):
@luxun.got("content", prompt="你让鲁迅说点啥?")
async def handle_event(bot: Bot, event: MessageEvent, state: T_State):
filename = str(event.user_id) + "_.jpg"
content = state["content"].strip()
if content.startswith(",") or content.startswith(","):
content = content[1:]
_ulmt.set_True(event.user_id)
if len(content) > 20:
_ulmt.set_False(event.user_id)
await luxun.finish("太长了, 鲁迅说不完!", at_sender=True)
else:
if len(content) >= 12:
content = content[:12] + "\n" + content[12:]
img = image(b64=process_pic(content, filename))
logger.info(
f"USER {event.user_id} GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'} 鲁迅说过 {content}"
)
await luxun.send(img)
_ulmt.set_False(event.user_id)
def process_pic(content, filename) -> str:
text = content
para = textwrap.wrap(text, width=15)
MAX_W, MAX_H = 480, 280
bk_img = Image.open(IMAGE_PATH + "other/luxun.jpg")
font_path = TTF_PATH + "/msyh.ttf"
font = ImageFont.truetype(font_path, 37)
font2 = ImageFont.truetype(font_path, 30)
draw = ImageDraw.Draw(bk_img)
current_h, pad = 300, 10
for line in para:
w, h = draw.textsize(line, font=font)
draw.text(((MAX_W - w) / 2, current_h), line, font=font)
current_h += h + pad
draw.text((320, 400), "——鲁迅", font=font2, fill=(255, 255, 255))
return pic2b64(bk_img)
A = CreateImg(0, 0, font_size=37, background=f'{IMAGE_PATH}/other/luxun.jpg', font='msyh.ttf')
x = ""
if len(content) > 40:
await luxun.finish('太长了,鲁迅说不完...')
while A.getsize(content)[0] > A.w - 50:
n = int(len(content) / 2)
x += content[:n] + '\n'
content = content[n:]
x += content
if len(x.split('\n')) > 2:
await luxun.finish('太长了,鲁迅说不完...')
A.text((int((480 - A.getsize(x.split("\n")[0])[0]) / 2), 300), x, (255, 255, 255))
A.paste(luxun_author, (320, 400), True)
await luxun.send(image(b64=A.pic2bs4()))
logger.info(
f"USER {event.user_id} GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'} 鲁迅说过 {content}"
)
+29 -6
View File
@@ -9,26 +9,47 @@ from nonebot.adapters.cqhttp.exception import ActionFailed
from configs.path_config import DATA_PATH, IMAGE_PATH
from utils.image_utils import get_img_hash
from services.log import logger
from configs.config import MUTE_LEVEL
import aiohttp
import aiofiles
from configs.config import MUTE_DEFAULT_COUNT, MUTE_DEFAULT_TIME, MUTE_DEFAULT_DURATION, NICKNAME
from configs.config import (
MUTE_DEFAULT_COUNT,
MUTE_DEFAULT_TIME,
MUTE_DEFAULT_DURATION,
NICKNAME,
)
try:
import ujson as json
except ModuleNotFoundError:
import json
__plugin_name__ = "刷屏禁言"
__plugin_usage__ = "刷屏禁言检测"
__zx_plugin_name__ = "刷屏禁言 [Admin]"
__plugin_usage__ = f"""
usage:
刷屏禁言相关操作,需要 {NICKNAME} 有群管理员权限
指令:
设置刷屏检测时间 [秒]
设置刷屏检测次数 [次数]
设置刷屏禁言时长 [分钟]
刷屏检测设置: 查看当前的刷屏检测设置
* 即 X 秒内发送同样消息 N 次,禁言 M 分钟 *
""".strip()
__plugin_des__ = "刷屏禁言相关操作"
__plugin_cmd__ = ["设置刷屏检测时间 [秒]", "设置刷屏检测次数 [次数]", "设置刷屏禁言时长 [分钟]", "刷屏检测设置"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {"admin_level": MUTE_LEVEL}
mute = on_message(priority=1, block=False)
mute_setting = on_command(
"mute_setting",
aliases={"设置检测时间", "设置检测次数", "设置禁言时长", "刷屏检测设置"},
aliases={"设置刷屏检测时间", "设置刷屏检测次数", "设置刷屏禁言时长", "刷屏检测设置"},
permission=GROUP,
block=True,
priority=5,
)
@@ -50,14 +71,16 @@ def save_data():
async def download_img_and_hash(url, group_id):
try:
async with aiohttp.ClientSession() as session:
async with session.get(url, proxy=get_local_proxy(), timeout=10) as response:
async with session.get(
url, proxy=get_local_proxy(), timeout=10
) as response:
async with aiofiles.open(
IMAGE_PATH + f"temp/mute_{group_id}_img.jpg", "wb"
) as f:
await f.write(await response.read())
return str(get_img_hash(IMAGE_PATH + f"temp/mute_{group_id}_img.jpg"))
except TimeoutError:
return ''
return ""
mute_dict = {}
+13 -2
View File
@@ -6,8 +6,19 @@ from models.group_member_info import GroupInfoUser
from datetime import timedelta
from models.level_user import LevelUser
__plugin_name__ = "更新群组成员列表 [Hidden]"
__plugin_usage__ = "用法:\n" "更新群员的信息"
__zx_plugin_name__ = "个人信息权限查看"
__plugin_usage__ = """
usage:
个人信息权限查看
指令:
我的信息
我的权限
""".strip()
__plugin_des__ = "我们还记得你和你的权利"
__plugin_cmd__ = ["我的信息", "我的权限"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
get_my_group_info = on_command("我的信息", permission=GROUP, priority=1, block=True)
+19 -2
View File
@@ -6,9 +6,24 @@ from services.log import logger
import ujson as json
import aiohttp
__plugin_name__ = "能不能好好说话"
__plugin_usage__ = "用法:\n nbnhhsh [文本]"
__zx_plugin_name__ = "能不能好好说话"
__plugin_usage__ = """
usage:
说人话
指令:
nbnhhsh [文本]
""".strip()
__plugin_des__ = "能不能好好说话,说人话"
__plugin_cmd__ = ["nbnhhsh [文本]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["能不能好好说话", "nbnhhsh"],
}
HHSH_GUESS_URL = "https://lab.magiconch.com/api/nbnhhsh/guess"
@@ -18,6 +33,8 @@ nbnhhsh = on_command("nbnhhsh", aliases={"能不能好好说话"}, priority=5, b
@nbnhhsh.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if not msg:
await nbnhhsh.finish('没话说就别说话!')
async with aiohttp.ClientSession(
headers={"content-type": "application/json"}
) as session:
+12 -3
View File
@@ -11,9 +11,18 @@ from services.log import logger
from configs.config import NICKNAME
__plugin_name__ = "昵称系统"
__plugin_usage__ = f"用法:\n以后叫我 [名称]\n{NICKNAME}我是谁"
__zx_plugin_name__ = "昵称系统"
__plugin_usage__ = f"""
usage:
个人昵称系统,群聊 与 私聊 昵称相互独立
指令:
以后叫我 [昵称]
{NICKNAME}我是谁
""".strip()
__plugin_des__ = "区区昵称,才不想叫呢!"
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
nickname = on_command(
"nickname",
+27 -11
View File
@@ -19,16 +19,31 @@ from .trace import get_des as get_des_trace
from .yandex import get_des as get_des_yandex
__plugin_name__ = "识图"
__plugin_usage__ = "用法:识图 [参数](默认nao) [图片]\n" "参数列表:\n" "\t1.nao\n" "\t2.asc"
__zx_plugin_name__ = "识图"
__plugin_usage__ = """
usage:
识别图片 [二次元图片]
指令:
识图 [图片]
""".strip()
__plugin_des__ = "以图搜图,看破本源"
__plugin_cmd__ = ["识图"]
__plugin_type__ = ("一些工具",)
__plugin_version__ = 0.1
__plugin_author__ = "synodriver"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["识图"],
}
async def get_des(url: str, mode: str, user_id: int):
"""
:param url: 图片链接
:param mode: 图源
:return:
:param user_id: 用户 id
"""
if mode == "iqdb":
async for msg in get_des_iqdb(url):
@@ -57,8 +72,6 @@ setu = on_command("识图", aliases={"search"}, block=True, priority=5)
async def handle_first_receive(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
imgs = get_message_imgs(event.json())
if msg in ["帮助"]:
await setu.finish("示例:\n\t识图 (图片)\n\t识图asc (图片)")
if imgs:
state["setu"] = imgs[0]
if msg:
@@ -94,13 +107,16 @@ async def get_setu(bot: Bot, event: MessageEvent, state: T_State):
await bot.send(event=event, message="正在处理图片")
idx = 1
async for msg in get_des(url, mod, event.user_id):
await bot.send(event=event, message=msg)
if idx == MAX_FIND_IMG_COUNT:
break
idx += 1
if msg:
await bot.send(event=event, message=msg)
if idx == MAX_FIND_IMG_COUNT:
break
idx += 1
if id == 1:
await bot.send(event=event, message='没找着.')
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if event.message_type != 'private' else 'private'}) 识图:{url}"
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 识图:{url}"
)
# image_data: List[Tuple] = await get_pic_from_url(url)
# await setu.finish("hso")
@@ -93,12 +93,13 @@ async def get_des(url: str, user_id: int):
return
for pic in image_data:
# print(pic)
msg = await download_img(pic[0], user_id) \
+ f"\n相似度:{pic[1]}" \
f"\n标题:{pic[2] if (str(pic[2]).strip() != 'Creator:' and len(str(pic[2]).split('-')) < 3) else '未知'}" \
f"\nPID:{pic[3]}" \
f"\nmember:{pic[4]}\n"
yield msg
if int(str(pic[1]).split('.')[0]) > 80:
msg = await download_img(pic[0], user_id) \
+ f"\n相似度:{pic[1]}" \
f"\n标题:{pic[2] if (str(pic[2]).strip() != 'Creator:' and len(str(pic[2]).split('-')) < 3) else '未知'}" \
f"\nPID:{pic[3]}" \
f"\nmember:{pic[4]}\n"
yield msg
pass
@@ -1,85 +0,0 @@
from typing import Any, Dict
from nonebot import get_driver, on_command
from nonebot.adapters.cqhttp import Bot, Event, GroupMessageEvent, PrivateMessageEvent
from nonebot.rule import to_me
from nonebot.typing import T_State, T_CalledAPIHook
from .config import Config
global_config = get_driver().config
withdraw_config = Config(**global_config.dict())
msg_ids = {}
max_size = withdraw_config.withdraw_max_size
__plugin_name__ = "撤回"
__plugin_usage__ = (
"用法:撤回 [消息位置](默认0)\n" "示例:\n" "\t撤回0 -> 撤回倒数第一条消息(即最新发送的消息)" "\t撤回1 -> 撤回倒数第2条消息"
)
def get_key(msg_type, id):
return f"{msg_type}_{id}"
async def save_msg_id(
bot: Bot, e: Exception, api: str, data: Dict[str, Any], result: Any
) -> T_CalledAPIHook:
try:
if api == "send_msg":
msg_type = data["message_type"]
id = data["group_id"] if msg_type == "group" else data["user_id"]
elif api == "send_private_msg":
msg_type = "private"
id = data["user_id"]
elif api == "send_group_msg":
msg_type = "group"
id = data["group_id"]
else:
return
key = get_key(msg_type, id)
msg_id = result["message_id"]
if key not in msg_ids:
msg_ids[key] = []
msg_ids[key].append(msg_id)
if len(msg_ids) > max_size:
msg_ids[key].pop(0)
except:
pass
Bot._called_api_hook.add(save_msg_id)
withdraw = on_command("withdraw", aliases={"撤回"}, rule=to_me(), priority=1, block=True)
@withdraw.handle()
async def _(bot: Bot, event: Event, state: T_State):
if isinstance(event, GroupMessageEvent):
msg_type = "group"
id = event.group_id
elif isinstance(event, PrivateMessageEvent):
msg_type = "private"
id = event.user_id
else:
return
key = get_key(msg_type, id)
num = event.get_plaintext().strip()
if not num:
num = 0
elif num.isdigit() and 0 <= int(num) < len(msg_ids[key]):
num = int(num)
else:
return
try:
idx = -num - 1
await bot.delete_msg(message_id=msg_ids[key][idx])
msg_ids[key].pop(idx)
except:
await withdraw.finish("撤回失败,可能已超时")
@@ -1,8 +0,0 @@
from pydantic import BaseSettings
class Config(BaseSettings):
withdraw_max_size: int = 50
class Config:
extra = 'ignore'
+36 -13
View File
@@ -1,31 +1,50 @@
import aiohttp
from utils.user_agent import get_user_agent
from io import BytesIO
from random import choice
from nonebot import on_regex
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from utils.utils import get_message_text, get_local_proxy, get_message_at
from utils.utils import get_message_text, get_message_at
from utils.message_builder import image
import re
from utils.image_utils import CreateImg
from asyncio.exceptions import TimeoutError
__plugin_name__ = "我有一个朋友"
__plugin_usage__ = "用法:我有一个朋友说/问 [消息] [at](不艾特则群员随机)"
__zx_plugin_name__ = "我有一个朋友"
__plugin_usage__ = """
usage:
我有一个朋友他...,不知道是不是你
指令:
我有一个朋友想问问 [文本] ?[at]: 当at时你的朋友就是艾特对象
""".strip()
__plugin_des__ = "我有一个朋友想问问..."
__plugin_cmd__ = ["我有一个朋友想问问[文本] ?[at]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["我有一个朋友想问问", "我有一个朋友"],
}
one_friend = on_regex(
"^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问).*",
priority=5,
priority=4,
block=True,
)
async def get_pic(qq):
url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=100"
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(url, proxy=get_local_proxy(), timeout=5) as response:
return await response.read()
async with aiohttp.ClientSession() as session:
for _ in range(3):
try:
async with session.get(url, timeout=5) as response:
return await response.read()
except TimeoutError:
pass
return None
@one_friend.handle()
@@ -41,11 +60,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
)
]
)
user_name = '朋友'
user_name = "朋友"
else:
qq = qq[0]
at_user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
user_name = at_user['card'] if at_user['card'] else at_user['nickname']
user_name = at_user["card"] if at_user["card"] else at_user["nickname"]
msg = re.search(
r"^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问)(.*)", msg
)
@@ -53,13 +72,17 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if not msg:
msg = "都不知道问什么"
msg = msg.replace("他", "我").replace("她", "我").replace("它", "我")
ava = CreateImg(100, 100, background=BytesIO(await get_pic(qq)))
x = await get_pic(qq)
if x:
ava = CreateImg(100, 100, background=BytesIO(await get_pic(qq)))
else:
ava = CreateImg(100, 100, color=(0, 0, 0))
ava.circle()
text = CreateImg(300, 30, font_size=30)
text.text((0, 0), user_name)
A = CreateImg(700, 150, font_size=25, color="white")
A.paste(ava, (30, 25), True)
A.paste(text, (150, 40))
A.paste(text, (150, 38))
A.text((150, 85), msg, (125, 125, 125))
await one_friend.send(image(b64=A.pic2bs4()))
+61 -30
View File
@@ -1,5 +1,7 @@
from typing import Type
from nonebot import on_command
from utils.utils import FreqLimiter, scheduler, get_message_text, is_number
from nonebot.matcher import Matcher
from utils.utils import scheduler, get_message_text, is_number
from nonebot.adapters.cqhttp.permission import GROUP
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
@@ -15,25 +17,57 @@ from .open_cases_c import (
open_shilian_case,
)
from .utils import util_get_buff_price, util_get_buff_img, update_count_daily
from configs.config import NICKNAME
__plugin_name__ = "开箱"
__plugin_usage__ = (
"用法:\n"
"看看你的人品罢了\n"
"目前只支持\n\t"
"1.狂牙大行动武器箱\n\t"
"2.突围大行动武器箱\n\t"
"3.命悬一线武器箱\n\t"
"4.裂空武器箱\n\t"
"5.光谱武器箱\n"
f"示例:{NICKNAME}开箱 突围大行动(不输入指定武器箱则随机)\n"
"示例:我的开箱(开箱统计)\n"
"示例:群开箱统计\n"
"示例:我的金色"
)
_flmt = FreqLimiter(3)
__zx_plugin_name__ = "开箱"
__plugin_usage__ = """
usage:
看看你的人品罢了
模拟开箱,完美公布的真实概率,只想看看替你省了多少钱
指令:
开箱 ?[武器箱]
[1-30]连开箱 ?[武器箱]
我的开箱
我的金色
群开箱统计
* 不包含[武器箱]时随机开箱 *
目前支持的武器箱:
1.狂牙大行动武器箱
2.突围大行动武器箱
3.命悬一线武器箱
4.裂空武器箱
5.光谱武器箱
示例:开箱 命悬一线
""".strip()
__plugin_superuser_usage__ = """
usage:
更新皮肤指令
指令:
更新开箱图片 ?[武器箱]
更新开箱价格 ?[武器箱]
* 不指定武器箱时则全部更新 *
* 过多的爬取会导致账号API被封 *
""".strip()
__plugin_des__ = "csgo模拟开箱[戒赌]"
__plugin_cmd__ = [
"开箱 ?[武器箱]",
"[1-30]连开箱 ?[武器箱]",
"我的开箱",
"我的金色",
"群开箱统计",
"更新开箱图片 ?[武器箱] [_superuser]",
"更新开箱价格 ?[武器箱] [_superuser]",
]
__plugin_type__ = ("抽卡相关", 1)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["csgo开箱", "开箱"],
}
__plugin_task__ = {"open_case_reset_remind": "每日开箱重置提醒"}
__plugin_cd_limit__ = {"rst": "着什么急啊,慢慢来!"}
cases_name = ["狂牙大行动", "突围大行动", "命悬一线", "裂空", "光谱"]
@@ -45,12 +79,8 @@ k_open_case = cases_matcher_group.on_command("开箱")
@k_open_case.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if str(event.get_message()).strip() in ["帮助"]:
await k_open_case.finish(__plugin_usage__)
if not _flmt.check(event.user_id):
await k_open_case.finish("着什么急啊,慢慢来!", at_sender=True)
_flmt.start_cd(event.user_id)
case_name = get_message_text(event.json())
case_name = case_name.replace("武器箱", "").strip()
if case_name:
result = await open_case(event.user_id, event.group_id, case_name)
else:
@@ -91,14 +121,14 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
)
open_shilian = cases_matcher_group.on_regex(".*连开箱")
open_shilian: Type[Matcher] = cases_matcher_group.on_regex(".*连开箱")
@open_shilian.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
# if not _flmt.check(event.user_id):
# await k_open_case.finish('着什么急啊,慢慢来!', at_sender=True)
_flmt.start_cd(event.user_id)
# _flmt.start_cd(event.user_id)
msg = get_message_text(event.json())
rs = re.search(r"(.*)连开箱(.*)", msg)
if rs:
@@ -110,11 +140,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
num = int(num)
if num > 30:
await open_shilian.finish("开箱次数不要超过30啊笨蛋!", at_sender=True)
if num < 0:
await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True)
else:
await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True)
case_name = rs.group(2).strip()
if case_name.find("武器箱") != -1:
case_name = case_name.replace("武器箱", "").strip()
case_name = case_name.replace("武器箱", "").strip()
if not case_name:
case_name = random.choice(cases_name)
elif case_name not in cases_name:
@@ -159,7 +190,7 @@ num_dict = {
}
update_price = on_command("更新价格", priority=1, permission=SUPERUSER, block=True)
update_price = on_command("更新开箱价格", priority=1, permission=SUPERUSER, block=True)
@update_price.handle()
@@ -167,7 +198,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
await update_price.send(await util_get_buff_price(str(event.get_message())))
update_img = on_command("更新图片", priority=1, permission=SUPERUSER, block=True)
update_img = on_command("更新开箱图片", priority=1, permission=SUPERUSER, block=True)
@update_img.handle()

Some files were not shown because too many files have changed in this diff Show More