Compare commits

...
114 Commits
Author SHA1 Message Date
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
hibiki 6a8eb9e67a update admin_manager 2021-08-18 10:06:06 +08:00
hibiki 8b7adf0a6a update pa 2021-08-18 09:56:53 +08:00
hibiki 973182c27c update setu 2021-08-18 02:04:26 +08:00
hibiki 0dced0bc90 update check 2021-08-18 01:47:21 +08:00
hibiki fc34cd541a code 2021-08-18 01:33:43 +08:00
hibiki 8090ebe8ce update hook 2021-08-18 01:29:36 +08:00
hibiki f87c14595f update hook 2021-08-18 00:44:03 +08:00
hibiki 39bb5a9ab9 update check_zhenxun_update 2021-08-18 00:26:11 +08:00
hibiki f754ad1c76 update code 2021-08-18 00:17:57 +08:00
hibiki 37e1a06528 update checkup 2021-08-18 00:14:55 +08:00
hibiki 7096d258db update code 2021-08-17 23:49:07 +08:00
hibiki ab33fc3af1 update readme.md 2021-08-17 23:32:09 +08:00
hibiki 2df2a6faf3 update readme.md 2021-08-17 23:26:48 +08:00
hibiki 1996f0d96a update code 2021-08-17 23:17:08 +08:00
HibiKier 3c6a365718 Update __init__.py 2021-08-13 21:41:18 +08:00
HibiKier bf9176ccdb Update README.md 2021-08-12 14:23:03 +08:00
HibiKier c154c1d2a6 Update update_info.json 2021-08-11 12:40:02 +08:00
HibiKier 60da97790b Update README.md 2021-08-11 12:37:58 +08:00
HibiKier 1635637254 Update __init__.py 2021-08-11 12:35:05 +08:00
HibiKier 109b80b6ef Update data_source.py 2021-08-11 11:44:39 +08:00
hibiki 218147b771 fix rule 2021-08-11 11:16:58 +08:00
HibiKier eec810dc6a Update config.py 2021-08-11 11:09:02 +08:00
HibiKier c2e2dc5609 Update README.md 2021-08-11 11:06:53 +08:00
hibiki 8f46cffa44 fix rule 2021-08-11 11:06:17 +08:00
HibiKier db54df6ce5 Update README.md 2021-08-11 10:43:44 +08:00
hibiki e68b154ddc fix yiqing 2021-08-11 10:41:40 +08:00
hibiki 5ec89e7538 fix 2021-08-10 23:03:46 +08:00
HibiKier 96dc1d9851 Update data_source.py 2021-08-09 07:50:33 +08:00
HibiKier 7148940a2f Update data_source.py 2021-08-09 07:50:04 +08:00
HibiKier 0455cba221 Update README.md 2021-08-07 22:36:54 +08:00
HibiKier b5f1d1ac21 Update README.md 2021-08-06 23:02:43 +08:00
HibiKier a628f7ab26 Update data_source.py 2021-08-06 21:27:55 +08:00
HibiKier ee6e185df7 Update __init__.py 2021-08-06 21:05:24 +08:00
HibiKier e1d7f31456 Update __init__.py 2021-08-06 20:14:48 +08:00
HibiKier e4fdfd0a21 Update README.md 2021-08-06 19:53:02 +08:00
HibiKier edd55f94e9 Update config.py 2021-08-06 19:47:01 +08:00
hibiki ee90fc3c14 add auto_update 2021-08-06 19:42:02 +08:00
HibiKier c96969e86c Update config.py 2021-08-06 14:46:30 +08:00
HibiKier 88ac572d51 Update config.py 2021-08-06 14:40:52 +08:00
HibiKier 10b7cbaa71 Update update_info.json 2021-08-06 13:55:24 +08:00
HibiKier 3b649172a8 Update update_info.json 2021-08-06 12:25:40 +08:00
443 changed files with 10924 additions and 5398 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ NICKNAME=["真寻", "小真寻", "绪山真寻", "小寻子"]
SESSION_EXPIRE_TIMEOUT=30
DEBUG=true
DEBUG=False
# 服务器和端口
HOST = 127.0.0.1
PORT = 8080
+183 -402
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] 黑白草图生成器
@@ -41,11 +42,13 @@
- [x] 构造假消息(自定义的分享链接)
- [x] 商店/我的金币/购买道具/使用道具
- [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
- [x] 我有一个朋友想问问..(pcrbot插件..彻底重写)
- [x] 我有一个朋友想问问..(借鉴pcrbot插件)
- [x] 原神黄历 (使用[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 原神今日素材 (原[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件,彻底重写,实现方法改为网页截图)
- [x] 原神资源查询 (使用[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件,资源下载优化为异步下载)
- [x] 原神今日素材
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 金币红包
- [x] 微博热搜
- [x] B站主播/UP/番剧订阅
- [x] pil对图片的一些操作
- [x] BUFF饰品底价查询(需要session)
@@ -68,7 +71,7 @@
- [x] 我的信息(只是为了看看什么时候入群)
- [x] 更新信息(如果继续更新的话)
- [x] go-cqhttp最新版下载和上传(不需要请删除)
- [x] 撤回 (使用[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)插件)
- [x] 撤回
- [x] 滴滴滴-(用户对超级用户发送消息)
- [x] 金币红包/金币排行
- [x] 俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
@@ -80,17 +83,18 @@
### 已实现的管理员功能
- [x] 更新群组成员信息
- [x] 95%的群功能开关 (基于[nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager)插件修改)
- [x] 95%的群功能开关
- [x] 查看群内被动技能状态
- [x] 自定义群欢迎消息(是真寻的不是管家的!)
- [x] .ban/.unban(支持设置ban时长)= 黑白名单
- [x] 刷屏禁言相关:刷屏检测设置/设置禁言时长/设置检测次数
- [x] 上传图片 (上传图片至指定图库)
- [x] 上传图片/连续上传图片 (上传图片至指定图库)
- [x] 移动图片 (同上)
- [x] 删除图片 (同上)
- [x] 群内B站订阅
### 已实现的超级用户功能
- [x] 添加/删除管理(是真寻的管理员权限,不是群管理员)
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
- [x] 开启/关闭指定群的广播通知
- [x] 广播
- [x] 自检(检查系统状态)
@@ -101,6 +105,18 @@
- [x] 上传/删除/修改商品(需要编写对应的商品功能)
- [x] 节日红包发送
- [x] 修改群权限
- [x] ban
- [x] 更新色图
- [x] 更新价格/更加图片(csgo开箱)
- [x] 重载原神/方舟/赛马娘/坎公骑冠剑卡池
- [x] 更新原神今日素材/更新原神资源信息
- [x] PIX相关操作
- [x] 检查更新真寻
- [x] 重启
- [x] 添加/删除/查看群白名单
- [x] 功能开关(更多设置)
- [x] 功能状态
- [x] b了
#### 超级用户的被动技能
- [x] 邀请入群提醒(别人邀请真寻入群)
@@ -110,7 +126,7 @@
- [x] 进群欢迎消息
- [x] 群早晚安
- [x] 每日开箱重置提醒
- [x] b站转发解析(解析b站分享信息)
- [x] b站转发解析(解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv),且5分钟内不解析相同url
- [x] 丢人爬(爬表情包)
- [x] epic通知(每日发送epic免费游戏链接)
- [x] 原神黄历提醒
@@ -133,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图片,说实话挺失望的,太色了
@@ -144,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>示例:我有一个朋友想问问他喜不喜欢真寻
@@ -158,19 +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] | 快捷的封面获取方式
@@ -178,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动态和投稿
### 管理员功能
@@ -197,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帮助,省略群号则私聊用户(必须要有用户的好友)
@@ -218,237 +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的色图功能
| 群白名单 | 添加/删除群白名单 *[群号] / 查看群白名单 | 白名单内的群不会受到 维护 限制
| 功能状态 | 功能状态 | 查看功能开关状态
| 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>
## 部署
@@ -462,12 +277,12 @@
# 获取代码
git clone https://github.com/HibiKier/zhenxun_bot.git
# 安装依赖
pip install -r requirements.txt
# 进入目录
cd zhenxun_bot
# 安装依赖
pip install -r requirements.txt
# 进行基础配置
####请查看 配置 部分####
@@ -475,7 +290,7 @@ cd zhenxun_bot
python bot.py
```
## 配置(暂时不更新 json 配置,请将USE_CONFIG_FILE设置为False)
## 配置
在 configs/config.py 中的 USE_CONFIG_FILE,默认为False
```
@@ -491,167 +306,132 @@ 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/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
### 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
* 新增功能‘连续上传图片’功能,直到输入‘stop’停止
* 新增功能维护时白名单以及对应命令(白名单中的群聊不受维护限制)
* 新增ALAPI功能,微博热搜,可以通过序号来查看部分热搜内容
* 新增配置NICKNAME,偶尔也想换换名字的说(自我介绍仅当NICKNAME=真寻时生效)
* 提供 更新信息 命令,可以使群员查看更新内容(可开关,与其他功能无异,但不会被统计,该命令图片由自动更新生成)
* 超级用户可以通过私聊来对指定qq进行ban/unban
* 超级用户帮助改为图片形式
* 公开图库删除‘色图’
* 群权限检测,个人权限检测,功能开关检测合并,权限检测顺序:个人权限 > 群权限 > 插件开关 >超级用户禁用某群插件 > 超级用户限制群里插件 > 插件维护检测
* 重写群功能管理,超级用户可对群/私聊分别禁用,也可禁用指定群指定功能,新增命令‘功能状态’,超级用户关闭功能提供参数(默认ALL):group/g(群聊),private/p(私聊)
* 超级用户不会被任何权限等检测阻挡
* 不会重复复读,复读消息只会发送一次
* b站转发解析支持b23.tv,www.bilibili.com链接,cv专栏(playwright截图,压缩倍率0.5,较慢且文字可能不清晰,后优化)
* 我有一个朋友功能,当艾特一个对象时,‘朋友’改为艾特对象的群名片或昵称
* 修复‘上传/删除/移动图片’目录不正确
* 修复天气功能,当城市名在‘天气’后时报错
* 修复配置INITIAL_SETU_PROBABILITY不生效
### 2021/8/10
* 重复的好友请求和邀群提示在5分钟内不会重复提示
* 疫情会优先检查城市,城市省份市区重名时请添加‘市’
* 添加命令‘原神资源查找’,‘设置cookie’
* 添加配置AUTO_UPDATE_ZHENXUN,是否自动更新真寻,默认True
* 添加配置MAX_RUSSIAN_BET_GOLD,俄罗斯轮盘赌注最大金额,默认1000
* 检查更新真寻定时任务时间改为12 : 00
* 添加功能能不能好好说话(nbnhhsh)
* 添加功能随机roll,无参为数字,有参为随机参数
* 添加linux重启脚本以及重启命令‘重启’(建议首次生成restart.sh先查看命令是否正确)
* 修复管理员功能的权限检测
* 修复丢人爬开关
### 2021/8/6
* 天气查询会优先遍历城市
* 添加自动更新真寻命令
##### 如果你的版本为 2021/8/4,可以直接复制plugins/check_zhenxun_update后,通过指令来更新真寻
### 2021/8/4
* 修改天气与疫情城市数据,改为api获取,丰富疫情的回复消息
@@ -679,13 +459,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
@@ -797,3 +577,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 -5
View File
@@ -2,18 +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")
if __name__ == "__main__":
+23 -96
View File
@@ -1,16 +1,13 @@
from .utils.util import get_config_data
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 = "小真寻"
# API KEY(必要)
RSSHUBAPP: str = "https://rsshub.app" # rsshub
@@ -35,11 +32,14 @@ SYSTEM_PROXY: Optional[str] = None # 全局代理
BUFF_PROXY: Optional[str] = None # Buff代理
# 公开图库列表
IMAGE_DIR_LIST: List[str] = ["色图", "美图", "萝莉", "壁纸"]
IMAGE_DIR_LIST: List[str] = ["美图", "萝莉", "壁纸"]
# 对被ban用户发送的消息
BAN_RESULT: str = "才不会给你发消息."
# PIX图库下载的画质 可能的值:original:原图,master:缩略图(加快发送速度)
PIX_IMAGE_SIZE: str = "master"
# 插件配置
MAXINFO_REIMU: int = 7 # 上车(reimu)功能查找目的地的最大数
@@ -50,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 # 明日方舟
@@ -67,6 +72,7 @@ SEMAPHORE = 5 # 限制碧蓝航线和FGO并发数
ADMIN_DEFAULT_AUTH: int = 5 # 默认群管理员权限
MAX_SIGN_GOLD: int = 200 # 签到好感度加成额外获得的最大金币数
MAX_RUSSIAN_BET_GOLD: int = 1000 # 俄罗斯轮盘最大赌注金额
INITIAL_SETU_PROBABILITY: float = 0.7 # 色图概率
FUDU_PROBABILITY: float = 0.7 # 复读概率
@@ -76,19 +82,24 @@ MUTE_DEFAULT_COUNT: int = 10 # 刷屏禁言默认检测次数
MUTE_DEFAULT_TIME: int = 7 # 刷屏检测默认规定时间
MUTE_DEFAULT_DURATION: int = 10 # 刷屏检测默禁言时长(分钟)
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
@@ -109,82 +120,9 @@ AUTO_ADD_FRIEND: bool = True
ALAPI_AI_CHECK: bool = True
# 导入商店自带的三个商品
IMPORT_DEFAULT_SHOP_GOODS: bool = True
# 真寻是否自动更新
AUTO_UPDATE_ZHENXUN: bool = True
# 群管理员功能 与 对应权限
admin_plugins_auth = {
"admin_bot_manage": 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"],
},
}
if TL_M_KEY:
TL_KEY = TL_M_KEY
@@ -197,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 -37
View File
@@ -23,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
):
"""
说明:
@@ -64,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
@@ -96,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:
@@ -150,16 +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()
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
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]
+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 及对应 好感度
View File
+17 -13
View File
@@ -9,24 +9,27 @@ from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
from nonebot.adapters.cqhttp.permission import GROUP
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")
)
@@ -38,15 +41,16 @@ self_introduction = on_command(
@self_introduction.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
result = (
"我叫绪山真寻\n"
"你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n"
"年龄的话我还是个**岁初中生(至少现在是)\n"
"身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n"
"我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n"
"最好的朋友是椛!\n" + image("zhenxun")
)
await self_introduction.finish(result)
if NICKNAME.find('真寻') != -1:
result = (
"我叫绪山真寻\n"
"你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n"
"年龄的话我还是个**岁初中生(至少现在是)\n"
"身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n"
"我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n"
"最好的朋友是椛!\n" + image("zhenxun")
)
await self_introduction.finish(result)
my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True)
+3 -11
View File
@@ -1,11 +1,3 @@
from nonebot.plugin import export
from .data_source import update_member_info
from .custom_welcome_message import *
from .group_notification_state import *
from .switch_rule import *
from .update_group_member_info import *
from .timing_task import *
export = export()
export.update_member_info = update_member_info
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("发生了一些未知错误...")
+199 -137
View File
@@ -1,197 +1,261 @@
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 nonebot import require
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.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
except ModuleNotFoundError:
import json
export = require("nonebot_plugin_manager")
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()
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发送当日的原神黄历',
}
custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
)
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
custom_welcome_msg_json = Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
async def custom_group_welcome(msg, imgs, user_id, 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)
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")
if not custom_welcome_msg_json.exists():
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
data = {}
else:
try:
data = json.load(open(custom_welcome_msg_json, 'r'))
data = json.load(open(custom_welcome_msg_json, "r"))
except FileNotFoundError:
data = {}
try:
if msg:
data[str(group_id)] = str(msg)
json.dump(data, open(custom_welcome_msg_json, 'w'), indent=4, ensure_ascii=False)
logger.info(f'USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}')
json.dump(
data, open(custom_welcome_msg_json, "w"), indent=4, ensure_ascii=False
)
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}")
result += msg
if img:
async with aiohttp.ClientSession() as session:
async with session.get(img, proxy=get_local_proxy()) as response:
async with aiofiles.open(DATA_PATH + f'custom_welcome_msg/{group_id}.jpg', 'wb') as f:
async with aiofiles.open(
DATA_PATH + f"custom_welcome_msg/{group_id}.jpg", "wb"
) as f:
await f.write(await response.read())
img_result = image(abspath=DATA_PATH + f'custom_welcome_msg/{group_id}.jpg')
logger.info(f'USER {user_id} GROUP {group_id} 更换群欢迎消息图片')
img_result = image(abspath=DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片")
except Exception as e:
logger.error(f'GROUP {group_id} 替换群消息失败 e:{e}')
return '替换群消息失败..'
return f'替换群欢迎消息成功:\n{result}' + img_result
logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}")
return "替换群消息失败.."
return f"替换群欢迎消息成功:\n{result}" + img_result
async def change_group_switch(cmd: str, group_id: int):
group_id = str(group_id)
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"
status = cmd[:2]
cmd = cmd[2:]
try:
with open(DATA_PATH + 'manager/plugin_list.json', 'r', encoding='utf8') as f:
plugin_list = json.load(f)
except ValueError:
pass
except FileNotFoundError:
pass
for plugin_cmd in plugins2info_dict.keys():
if cmd in plugins2info_dict[plugin_cmd]['cmd']:
# print(plugin_list[plugin_cmd])
if status == '开启':
# if group_id in plugin_list[plugin_cmd]:
if group_id not in plugin_list[plugin_cmd] or plugin_list[plugin_cmd][group_id]:
return f'功能 {cmd} 正处于开启状态!不要重复开启.'
export.unblock_plugin(group_id, plugin_cmd)
type_ = 'plugin'
modules = plugins2settings_manager.get_plugin_module(cmd, True)
if cmd == '全部被动':
for task in task_data:
if status == "开启":
if not await group_manager.check_group_task_status(group_id, task):
await group_manager.open_group_task(group_id, task)
else:
if group_id in plugin_list[plugin_cmd]:
if not plugin_list[plugin_cmd][group_id]:
return f'功能 {cmd} 正处于关闭状态!不要重复关闭.'
export.block_plugin(group_id, plugin_cmd)
if os.path.exists(DATA_PATH + f'group_help/{group_id}.png'):
os.remove(DATA_PATH + f'group_help/{group_id}.png')
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(module, group_id)
if group_help_file.exists():
group_help_file.unlink()
return f"{status} {cmd} 功能!"
return f'{status} {cmd} 功能!'
return f'没有找到 {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:]
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() -> 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)
b.text((10, 10), flag_str)
A = CreateImg(380, height)
A.paste(a)
A.paste(b, (150, 0))
return image(b64=A.pic2bs4())
async def update_member_info(group_id: int) -> bool:
"""
更新群成员信息
:param group_id: 群号
"""
bot = get_bot()
_group_user_list = await bot.get_group_member_list(group_id=group_id)
_error_member_list = []
_exist_member_list = []
# try:
for user_info in _group_user_list:
if user_info['card'] == "":
nickname = user_info['nickname']
if user_info["card"] == "":
nickname = user_info["nickname"]
else:
nickname = user_info['card']
nickname = user_info["card"]
async with db.transaction():
# 更新权限
if user_info['role'] in ['owner', 'admin'] and not await LevelUser.is_group_flag(user_info['user_id'], group_id):
await LevelUser.set_level(user_info['user_id'], user_info['group_id'], ADMIN_DEFAULT_AUTH)
if str(user_info['user_id']) in bot.config.superusers:
await LevelUser.set_level(user_info['user_id'], user_info['group_id'], 9)
user = await GroupInfoUser.get_member_info(user_info['user_id'], user_info['group_id'])
if (
user_info["role"]
in [
"owner",
"admin",
]
and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
):
await LevelUser.set_level(
user_info["user_id"], user_info["group_id"], ADMIN_DEFAULT_AUTH
)
if str(user_info["user_id"]) in bot.config.superusers:
await LevelUser.set_level(
user_info["user_id"], user_info["group_id"], 9
)
user = await GroupInfoUser.get_member_info(
user_info["user_id"], user_info["group_id"]
)
if user:
if user.user_name != nickname:
await user.update(user_name=nickname).apply()
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功")
_exist_member_list.append(int(user_info['user_id']))
logger.info(
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功"
)
_exist_member_list.append(int(user_info["user_id"]))
continue
join_time = datetime.strptime(
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user_info['join_time'])), "%Y-%m-%d %H:%M:%S")
time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"])
),
"%Y-%m-%d %H:%M:%S",
)
if await GroupInfoUser.add_member_info(
user_info['user_id'],
user_info['group_id'],
nickname,
join_time,):
_exist_member_list.append(int(user_info['user_id']))
user_info["user_id"],
user_info["group_id"],
nickname,
join_time,
):
_exist_member_list.append(int(user_info["user_id"]))
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
else:
_error_member_list.append(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n")
_del_member_list = list(set(_exist_member_list).difference(set(await GroupInfoUser.get_group_member_id_list(group_id))))
_error_member_list.append(
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n"
)
_del_member_list = list(
set(_exist_member_list).difference(
set(await GroupInfoUser.get_group_member_id_list(group_id))
)
)
if _del_member_list:
for del_user in _del_member_list:
if await GroupInfoUser.delete_member_info(del_user, group_id):
@@ -202,9 +266,7 @@ async def update_member_info(group_id: int) -> bool:
result = ""
for error_user in _error_member_list:
result += error_user
await bot.send_private_msg(user_id=int(list(bot.config.superusers)[0]), message=result[:-1])
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
)
return True
@@ -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=1,
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
+93 -28
View File
@@ -1,41 +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
from .data_source import change_group_switch
from nonebot.adapters.cqhttp.permission import GROUP
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
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_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_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 = " ".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_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_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_matcher.send(f"已在群聊中{_cmd[:2]}功能:{_cmd[2:]}")
else:
await switch_rule_matcher.finish("格式错误:关闭[功能] [group]/[p/g]")
logger.info(f"USER {event.user_id} 使用功能管理命令 {_cmd} | {block_type}")
switch_rule = on_command(
"switch_rule", aliases=cmds, permission=GROUP, priority=4, block=True
)
@plugins_status.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await plugins_status.send(await get_plugin_status())
@switch_rule.handle()
@group_task_status.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await switch_rule.send(
await 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 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)
logger.info(f"快速更新群信息以及权限:{g}")
except (IndexError, ConnectionDoesNotExistError):
pass
@@ -1,18 +1,23 @@
from nonebot import on_command
from nonebot import on_command, on_notice
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
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,
}
from nonebot.adapters.cqhttp.permission import GROUP
refresh_member_group = on_command(
"更新群组成员列表", aliases={"更新群组成员信息"}, permission=GROUP, priority=5, block=True
@@ -25,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 -38
View File
@@ -2,52 +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 .data_source import create_help_image, admin_help_image
__plugin_name__ = '管理帮助 [Hidden]'
__plugin_usage__ = '''管理帮助(权限等级):
1.更新群组成员列表(1)
2.功能开关 --> 指令:开启/关闭xx功能(2)
3.查看群被动技能 --> 指令:群通知状态(2)
4.自定义群欢迎 --> 指令:自定义进群欢迎消息(2)
5.将用户拉入真寻黑名单 --> .ban/.unban(5)
6.刷屏禁言相关 --> 指令:刷屏检测设置/设置检测时间
\t\t/设置检测次数/设置禁言时长(5)
7.群员活跃度相关 --> 指令:群员活跃检测设置
设置群员活跃检测时长(天)
添加群员活跃检测白名单[at]...
查看群员活跃检测白名单(5)
8.上传图片(6)
9.移动图片(7)
10.删除图片(7)
对我说 “真寻帮助 指令” 获取对应详细帮助
群主与管理员默认 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))
+57 -19
View File
@@ -1,19 +1,21 @@
from configs.config import TL_KEY, ALAPI_TOKEN, ALAPI_AI_CHECK
from configs.path_config import IMAGE_PATH, DATA_PATH
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 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("菲菲", "真寻")
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,11 +177,14 @@ def hello() -> str:
# 没有回答时回复内容
def no_result() -> str:
"""
没有回答时的回复
"""
return (
random.choice(
[
"你在说啥子?",
f"纯洁的小真寻没听懂",
f"纯洁的{NICKNAME}没听懂",
"下次再告诉你(下次一定)",
"你觉得我听懂了吗?嗯?",
"我!不!知!道!",
@@ -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")
+33 -21
View File
@@ -1,36 +1,48 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, MessageEvent
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State
from configs.config import ALAPI_TOKEN
from .util import get_data
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 event.message_type != 'private' else 'private'})"
f" 发送网易云热评: {comment} \n\t\t————{song_name}")
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送网易云热评: {comment} \n\t\t————{song_name}"
)
+19 -6
View File
@@ -1,15 +1,28 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
from nonebot.typing import T_State
from configs.config import ALAPI_TOKEN
from utils.message_builder import image
from utils.utils import get_message_text
from .util import get_data
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)
@@ -33,7 +46,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
img = data['cover']
await cover.send(Message(f'title:{title}\n{image(img)}'))
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})"
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 获取b站封面: {title} url:{img}")
+49
View File
@@ -0,0 +1,49 @@
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) -> 'Union[dict, str], int':
"""
获取ALAPI数据
:param url: 请求链接
:param params: 参数
"""
async with aiohttp.ClientSession() as session:
try:
async with session.get(
url, timeout=2, params=params
) as response:
data = await response.json()
if data["code"] == 200:
if not data["data"]:
return "没有搜索到...", 997
return data, 200
else:
return f'发生了错误...code:{data["code"]}', 999
except TimeoutError:
return "超时了....", 998
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)
text_bk = CreateImg(700, 32 * 50, 700, 32, color='#797979')
for i, data in enumerate(data):
title = f"{i+1}. {data['hot_word']}"
hot = data['hot_word_num']
img = CreateImg(700, 30, font_size=20)
w, h = img.getsize(title)
img.text((10, int((30 - h) / 2)), title)
img.text((580, int((30 - h) / 2)), hot)
text_bk.paste(img)
bk.paste(text_bk, (0, 280))
return image(b64=bk.pic2bs4())
+18 -6
View File
@@ -1,13 +1,25 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, MessageEvent
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State
from configs.config import ALAPI_TOKEN
from services.log import logger
from .util import get_data
__plugin_name__ = '古诗'
__plugin_usage__ = '用法: 无'
from .data_source import get_data
__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)
@@ -29,7 +41,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
author = data['author']
await poetry.send(f'{content}\n\t——{author}《{title}》')
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})"
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送古诗: f'{content}\n\t--{author}《{title}》'")
-17
View File
@@ -1,17 +0,0 @@
import aiohttp
from utils.utils import get_local_proxy
async def get_data(url: str, params: dict):
async with aiohttp.ClientSession() as session:
try:
async with session.get(url, proxy=get_local_proxy(), timeout=2, params=params) as response:
data = await response.json()
if data['code'] == 200:
if not data['data']:
return '没有搜索到...', 997
return data, 200
else:
return f'发生了错误...code:{data["code"]}', 999
except TimeoutError:
return '超时了....', 998
+79
View File
@@ -0,0 +1,79 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State
from configs.config import ALAPI_TOKEN
from services.log import logger
from .data_source import get_data, gen_wbtop_pic
from utils.browser import get_browser
from utils.utils import get_message_text, is_number
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
import asyncio
__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)
wbtop_url = 'https://v2.alapi.cn/api/new/wbtop'
wbtop_data = []
@wbtop.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
global wbtop_data
msg = get_message_text(event.json())
if not wbtop_data or not msg:
params = {
'token': ALAPI_TOKEN
}
data, code = await get_data(wbtop_url, params)
if code != 200:
await wbtop.finish(data, at_sender=True)
wbtop_data = data['data']
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()
page = None
try:
if not browser:
logger.warning('获取 browser 失败,请部署至 linux 环境....')
await wbtop.finish('获取 browser 对象失败...')
page = await browser.new_page()
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/wbtop_{event.user_id}.png', timeout=100000)
await page.close()
await wbtop.send(image(f'wbtop_{event.user_id}.png', 'temp'))
except Exception as e:
logger.error(f'微博热搜截图出错... {type(e)}: {e}')
if page:
await page.close()
await wbtop.send('发生了一些错误.....')
+49 -38
View File
@@ -2,36 +2,41 @@ from nonebot import on_request
from nonebot.adapters.cqhttp import Bot, FriendRequestEvent, GroupRequestEvent
from models.friend_user import FriendUser
from datetime import datetime
from configs.config import AUTO_ADD_FRIEND
from configs.config import AUTO_ADD_FRIEND, NICKNAME
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)
exists_list = []
exists_data = {"private": {}, "group": {}}
@friend_req.handle()
async def _(bot: Bot, event: FriendRequestEvent, state: dict):
global exists_list
if f"{event.user_id}" not in exists_list:
exists_list.append(f"{event.user_id}")
user = await bot.get_stranger_info(user_id=event.user_id)
nickname = user["nickname"]
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份好友申请*****\n"
f"昵称:{nickname}({event.user_id})\n"
f"自动同意:{'√' if AUTO_ADD_FRIEND else '×'}\n"
f"日期:{str(datetime.now()).split('.')[0]}\n"
f"备注:{event.comment}",
)
if AUTO_ADD_FRIEND:
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.add_friend_info(user["user_id"], user["nickname"])
global exists_data
if exists_data["private"].get(event.user_id):
if time.time() - exists_data["private"][event.user_id] < 60 * 5:
return
exists_data["private"][event.user_id] = time.time()
user = await bot.get_stranger_info(user_id=event.user_id)
nickname = user["nickname"]
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份好友申请*****\n"
f"昵称:{nickname}({event.user_id})\n"
f"自动同意:{'√' if AUTO_ADD_FRIEND else '×'}\n"
f"日期:{str(datetime.now()).split('.')[0]}\n"
f"备注:{event.comment}",
)
if AUTO_ADD_FRIEND:
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.add_friend_info(user["user_id"], user["nickname"])
group_req = on_request(priority=5, block=True)
@@ -39,7 +44,7 @@ group_req = on_request(priority=5, block=True)
@group_req.handle()
async def _(bot: Bot, event: GroupRequestEvent, state: dict):
global exists_list
global exists_data
if event.sub_type == "invite":
if str(event.user_id) in bot.config.superusers:
try:
@@ -49,22 +54,28 @@ async def _(bot: Bot, event: GroupRequestEvent, state: dict):
except ActionFailed:
pass
else:
if f"{event.user_id}:{event.group_id}" not in exists_list:
exists_list.append(f"{event.user_id}:{event.group_id}")
nickname = await FriendUser.get_user_name(event.user_id)
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份入群申请*****\n"
f"申请人:{nickname}({event.user_id})\n"
f"群聊:{event.group_id}\n"
f"邀请日期:{str(datetime.now()).split('.')[0]}",
)
await bot.send_private_msg(
user_id=event.user_id,
message="想要邀请我偷偷入群嘛~已经提醒真寻的管理员大人了\n"
"请确保已经群主或群管理沟通过!\n"
"等待管理员处理吧!",
)
if exists_data["group"].get(f"{event.user_id}:{event.group_id}"):
if (
time.time()
- exists_data["group"][f"{event.user_id}:{event.group_id}"]
< 60 * 5
):
return
exists_data["group"][f"{event.user_id}:{event.group_id}"] = time.time()
nickname = await FriendUser.get_user_name(event.user_id)
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份入群申请*****\n"
f"申请人:{nickname}({event.user_id})\n"
f"群聊:{event.group_id}\n"
f"邀请日期:{str(datetime.now()).split('.')[0]}",
)
await bot.send_private_msg(
user_id=event.user_id,
message=f"想要邀请我偷偷入群嘛~已经提醒{NICKNAME}的管理员大人了\n"
"请确保已经群主或群管理沟通过!\n"
"等待管理员处理吧!",
)
@scheduler.scheduled_job(
@@ -72,5 +83,5 @@ async def _(bot: Bot, event: GroupRequestEvent, state: dict):
minutes=5,
)
async def _():
global exists_list
exists_list = []
global exists_data
exists_data = {"private": {}, "group": {}}
+111 -24
View File
@@ -3,38 +3,57 @@ from models.ban_user import BanUser
from models.level_user import LevelUser
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot
from nonebot.adapters.cqhttp import GroupMessageEvent
from nonebot.adapters.cqhttp.permission import GROUP
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent
from utils.utils import get_message_at, get_message_text, is_number
from configs.config import NICKNAME, BAN_LEVEL
from nonebot.permission import SUPERUSER
from services.log import logger
__plugin_name__ = "Ban/unBan"
__plugin_usage__ = (
"用法:\n"
"(不是禁言!是针对真寻是否处理封禁用户消息)\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(
".ban",
aliases={".unban", "/ban", "/unban"},
priority=5,
permission=GROUP,
block=True,
)
super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True)
@ban.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
result = ""
qq = get_message_at(event.json())[0]
qq = get_message_at(event.json())
if qq:
qq = qq[0]
user_name = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
user_name = user_name['card'] if user_name['card'] else user_name['nickname']
msg = get_message_text(event.json())
@@ -52,21 +71,21 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
time = -1
if state["_prefix"]["raw_command"] in [".ban", "/ban"]:
if (
await LevelUser.get_user_level(event.user_id, event.group_id)
<= await LevelUser.get_user_level(qq, event.group_id)
and str(event.user_id) not in bot.config.superusers
await LevelUser.get_user_level(event.user_id, event.group_id)
<= await LevelUser.get_user_level(qq, event.group_id)
and str(event.user_id) not in bot.config.superusers
):
await ban.finish(
f"您的权限等级比对方低或相等, {list(bot.config.nickname)[0]}不能为您使用此功能!",
f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!",
at_sender=True,
)
if await BanUser.ban(
qq, await LevelUser.get_user_level(event.user_id, event.group_id), time
qq, await LevelUser.get_user_level(event.user_id, event.group_id), time
):
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time/60} 分钟"
)
result = f"已经将 {user_name} 加入{list(bot.config.nickname)[0]}的黑名单了!"
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
if time != -1:
result += f"将在 {time/60} 分钟后解封"
else:
@@ -82,10 +101,10 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
result = f"{user_name} 已在黑名单!预计 {time}后解封"
else:
if (
await BanUser.check_ban_level(
qq, await LevelUser.get_user_level(event.user_id, event.group_id)
)
and str(event.user_id) not in bot.config.superusers
await BanUser.check_ban_level(
qq, await LevelUser.get_user_level(event.user_id, event.group_id)
)
and str(event.user_id) not in bot.config.superusers
):
await ban.finish(
f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True
@@ -100,3 +119,71 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
else:
await ban.finish("艾特人了吗??", at_sender=True)
await ban.finish(result, at_sender=True)
@ban.handle()
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
if str(event.user_id) in bot.config.superusers:
msg = get_message_text(event.json())
msg = msg.split()
if is_number(msg[0]):
qq = int(msg[0])
if state["_prefix"]["raw_command"] in [".ban", "/ban"]:
hour = 0
minute = 0
if len(msg) > 1 and is_number(msg[1]):
hour = int(msg[1])
if len(msg) > 2 and is_number(msg[2]):
minute = int(msg[2])
time = hour * 60 * 60 + minute * 60
time = time if time else -1
if await BanUser.ban(
qq, 9, time
):
logger.info(
f"USER {event.user_id} 将 USER {qq} 封禁 时长 {time/60} 分钟"
)
result = f"已经将 {qq} 加入{NICKNAME}的黑名单了!"
if time != -1:
result += f"将在 {time/60} 分钟后解封"
else:
result += f"将在 ∞ 分钟后解封"
await ban.send(result)
else:
time = await BanUser.check_ban_time(qq)
if is_number(time):
time = abs(int(time))
if time < 60:
time = str(time) + " 秒"
else:
time = str(int(time / 60)) + " 分钟"
else:
time += " 分钟"
await ban.send(f"{qq} 已在黑名单!预计 {time}后解封")
else:
if await BanUser.unban(qq):
logger.info(
f"USER {event.user_id} 将 USER {qq} 解禁"
)
result = f"已经把 {qq} 从黑名单中删除了!"
else:
result = f"{qq} 不在黑名单!"
await ban.send(result)
else:
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()
+119
View File
@@ -0,0 +1,119 @@
from nonebot.adapters.cqhttp import Bot, MessageEvent
from nonebot.typing import T_State
from nonebot.permission import SUPERUSER
from nonebot import on_command
from .data_source import check_update, get_latest_version_data
from services.log import logger
from utils.utils import scheduler, get_bot
from pathlib import Path
from configs.config import AUTO_UPDATE_ZHENXUN
from nonebot.rule import to_me
import platform
import os
__zx_plugin_name__ = "自动更新 [Superuser]"
__plugin_usage__ = """
usage:
检查更新真寻最新版本,包括了自动更新
指令:
检查更新真寻
重启
""".strip()
__plugin_des__ = "就算是真寻也会成长的"
__plugin_cmd__ = ["检查更新真寻", "重启"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
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, 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}")
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"更新真寻未知错误 {type(e)}:{e}",
)
else:
if code == 200:
await bot.send_private_msg(
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重启脚本...")
@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")
else:
await restart.send("已取消操作...")
@scheduler.scheduled_job(
"cron",
hour=12,
minute=0,
)
async def _():
if AUTO_UPDATE_ZHENXUN:
_version = "v0.0.0"
_version_file = Path() / "__version__"
if _version_file.exists():
_version = (
open(_version_file, "r", encoding="utf8")
.readline()
.split(":")[-1]
.strip()
)
data = await get_latest_version_data()
if data:
latest_version = data["name"]
if _version != latest_version:
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"尝试自动更新...",
)
try:
code = await check_update(bot)
except Exception as 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",
)
else:
if code == 200:
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"更新完毕,请重启真寻....",
)
+231
View File
@@ -0,0 +1,231 @@
from aiohttp.client_exceptions import ClientConnectorError
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
import ujson as json
import nonebot
import asyncio
import aiofiles
import aiohttp
import platform
import tarfile
import shutil
import os
if str(platform.system()).lower() == "windows":
policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy)
driver = nonebot.get_driver()
release_url = "https://api.github.com/repos/HibiKier/zhenxun_bot/releases/latest"
_version_file = Path() / "__version__"
zhenxun_latest_tar_gz = Path() / "zhenxun_latest_file.tar.gz"
temp_dir = Path() / "temp"
backup_dir = Path() / "backup"
@driver.on_bot_connect
async def remind(bot: Bot):
if str(platform.system()).lower() != "windows":
restart = Path() / "restart.sh"
if not restart.exists():
with open(restart, "w", encoding="utf8") as f:
f.write(
f"pid=$(netstat -tunlp | grep "
+ str(bot.config.port)
+ " | awk '{print $7}')\n"
"pid=${pid%/*}\n"
"kill -9 $pid\n"
"sleep 3\n"
"python3 bot.py"
)
os.system("chmod +x ./restart.sh")
logger.info("已自动生成 restart.sh(重启) 文件,请检查脚本是否与本地指令符合...")
is_restart_file = Path() / "is_restart"
if is_restart_file.exists():
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"真寻重启完毕...",
)
is_restart_file.unlink()
async def check_update(bot: Bot) -> 'int, str':
logger.info("开始检查更新真寻酱....")
_version = "v0.0.0"
if _version_file.exists():
_version = (
open(_version_file, "r", encoding="utf8").readline().split(":")[-1].strip()
)
data = await get_latest_version_data()
if data:
latest_version = data["name"]
if _version != latest_version:
tar_gz_url = data["tarball_url"]
logger.info(f"检测真寻已更新,当前版本:{_version},最新版本:{latest_version}")
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"检测真寻已更新,当前版本:{_version},最新版本:{latest_version}\n" f"开始更新.....",
)
logger.info(f"开始下载真寻最新版文件....")
if await download_latest_file(tar_gz_url):
logger.info("下载真寻最新版文件完成....")
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"]
width = 0
height = len(update_info.split('\n')) * 24
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')
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(
user_id=int(list(bot.config.superusers)[0]),
message=f"下载真寻最新版本失败...版本号:{latest_version}.",
)
else:
logger.info(f"自动获取真寻版本成功:{latest_version},当前版本为最新版,无需更新...")
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"自动获取真寻版本成功:{latest_version},当前版本为最新版,无需更新...",
)
else:
logger.warning("自动获取真寻版本失败....")
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]), message=f"自动获取真寻版本失败...."
)
return 999, ''
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)
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:
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():
shutil.rmtree(temp_dir)
if zhenxun_latest_tar_gz.exists():
zhenxun_latest_tar_gz.unlink()
local_update_info_file = Path() / "update_info.json"
if local_update_info_file.exists():
local_update_info_file.unlink()
with open(_version_file, "w", encoding="utf8") as f:
f.write(f"__version__: {latest_version}")
return error
# 获取最新版本号
async def get_latest_version_data() -> dict:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
for _ in range(3):
try:
async with session.get(release_url, proxy=get_local_proxy()) as res:
if res.status == 200:
return await res.json()
except (TimeoutError, ClientConnectorError):
pass
return {}
# 下载文件
async def download_latest_file(url_: str) -> bool:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
for _ in range(3):
try:
async with session.get(url_, proxy=get_local_proxy()) as res:
if res.status == 200:
async with aiofiles.open(zhenxun_latest_tar_gz, "wb") as f:
await f.write(await res.read())
return True
except (TimeoutError, ClientConnectorError):
pass
return False
# 逐行检测
def check_old_lines(lines: List[str], line: str) -> str:
if "=" not in line:
return line
for l in lines:
if "=" in l and l.split("=")[0].strip() == line.split("=")[0].strip():
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)]
+30 -15
View File
@@ -1,16 +1,31 @@
from nonebot import on_command
from services.log import logger
from nonebot.adapters.cqhttp import Bot, MessageEvent
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 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__ = "HibiKier"
__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)
@@ -20,7 +35,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
result, code = await get_epic_game()
await epic.send(result)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})"
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 获取epic免费游戏"
)
@@ -33,13 +48,13 @@ 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:
if await group_manager.check_group_task_status(g, 'epic_free_game'):
try:
result, code = await get_epic_game()
if code == 200:
await bot.send_group_msg(group_id=g, message=result)
except ActionFailed:
logger.error(f"{g}群 epic免费游戏推送错误")
except Exception as e:
logger.error(f"GROUP {g} epic免费游戏推送错误 {type(e)}: {e}")
+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)
+55 -19
View File
@@ -9,32 +9,62 @@ 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:
def __init__(self):
self.mlist = defaultdict(list)
self.data = {}
def append(self, key, content):
self.mlist[key].append(content)
self._create(key)
self.data[key]["data"].append(content)
def clear(self, key):
self.mlist[key] = []
self._create(key)
self.data[key]["data"] = []
self.data[key]["is_repeater"] = False
def size(self, key) -> int:
return len(self.mlist[key])
self._create(key)
return len(self.data[key]["data"])
def check(self, key, content) -> bool:
return self.mlist[key][0] == content
self._create(key)
return self.data[key]["data"][0] == content
def get(self, key):
return self.mlist[key][0]
self._create(key)
return self.data[key]["data"][0]
def is_repeater(self, key):
self._create(key)
return self.data[key]["is_repeater"]
def set_repeater(self, key):
self._create(key)
self.data[key]["is_repeater"] = True
def _create(self, key):
if self.data.get(key) is None:
self.data[key] = {"is_repeater": False, "data": []}
_fudulist = Fudu()
_fudu_list = Fudu()
fudu = on_message(permission=GROUP, priority=9)
@@ -42,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:
@@ -56,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:
_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:
@@ -77,7 +114,6 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
rst = ""
if rst:
await fudu.send(rst)
_fudulist.clear(event.group_id)
async def get_fudu_img_hash(url, group_id):
@@ -91,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,11 @@
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
try:
@@ -12,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('更新原神资源信息', 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()
@@ -45,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 = ""
@@ -86,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}")
+77 -37
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:
@@ -146,41 +146,81 @@ class Map:
# 生成最优路线(说是最优其实就是直线最短)
def _generate_best_route(self):
resources_route = []
# 先连上最近的资源路径
for res in self.resource_point:
# 拿到最近的资源
current_res, _ = res.get_resource_distance(
self.resource_point
+ self.teleport_anchor_point
+ self.teleport_god_point
)
self.map.line(
(current_res.x, current_res.y, res.x, res.y), (255, 0, 0), width=1
)
resources_route.append((current_res, res))
line_points = []
teleport_list = self.teleport_anchor_point + self.teleport_god_point
for res1, res2 in resources_route:
point_list = [x for x in resources_route if res1 in x or res2 in x]
if not list(set(point_list).intersection(set(teleport_list))):
if res1 not in teleport_list and res2 not in teleport_list:
# while True:
# tmp = [x for x in point_list]
# break
teleport1, distance1 = res1.get_resource_distance(teleport_list)
teleport2, distance2 = res2.get_resource_distance(teleport_list)
if distance1 > distance2:
self.map.line(
(teleport1.x, teleport1.y, res1.x, res1.y),
(255, 0, 0),
width=1,
)
else:
self.map.line(
(teleport2.x, teleport2.y, res2.x, res2.y),
(255, 0, 0),
width=1,
)
for teleport in teleport_list:
current_res, res_min_distance = teleport.get_resource_distance(self.resource_point)
current_teleport, teleport_min_distance = current_res.get_resource_distance(teleport_list)
if current_teleport == teleport:
self.map.line(
(current_teleport.x, current_teleport.y, current_res.x, current_res.y), (255, 0, 0), width=1
)
is_used_res_points = []
for res in self.resource_point:
if res in is_used_res_points:
continue
current_teleport, teleport_min_distance = res.get_resource_distance(teleport_list)
current_res, res_min_distance = res.get_resource_distance(self.resource_point)
if teleport_min_distance < res_min_distance:
self.map.line(
(current_teleport.x, current_teleport.y, res.x, res.y), (255, 0, 0), width=1
)
else:
is_used_res_points.append(current_res)
self.map.line(
(current_res.x, current_res.y, res.x, res.y), (255, 0, 0), width=1
)
res_cp = self.resource_point[:]
res_cp.remove(current_res)
# for _ in res_cp:
current_teleport_, teleport_min_distance = res.get_resource_distance(teleport_list)
current_res, res_min_distance = res.get_resource_distance(res_cp)
if teleport_min_distance < res_min_distance:
self.map.line(
(current_teleport.x, current_teleport.y, res.x, res.y), (255, 0, 0), width=1
)
else:
self.map.line(
(current_res.x, current_res.y, res.x, res.y), (255, 0, 0), width=1
)
is_used_res_points.append(current_res)
is_used_res_points.append(res)
# resources_route = []
# # 先连上最近的资源路径
# for res in self.resource_point:
# # 拿到最近的资源
# current_res, _ = res.get_resource_distance(
# self.resource_point
# + self.teleport_anchor_point
# + self.teleport_god_point
# )
# self.map.line(
# (current_res.x, current_res.y, res.x, res.y), (255, 0, 0), width=1
# )
# resources_route.append((current_res, res))
# teleport_list = self.teleport_anchor_point + self.teleport_god_point
# for res1, res2 in resources_route:
# point_list = [x for x in resources_route if res1 in x or res2 in x]
# if not list(set(point_list).intersection(set(teleport_list))):
# if res1 not in teleport_list and res2 not in teleport_list:
# # while True:
# # tmp = [x for x in point_list]
# # break
# teleport1, distance1 = res1.get_resource_distance(teleport_list)
# teleport2, distance2 = res2.get_resource_distance(teleport_list)
# if distance1 > distance2:
# self.map.line(
# (teleport1.x, teleport1.y, res1.x, res1.y),
# (255, 0, 0),
# width=1,
# )
# else:
# self.map.line(
# (teleport2.x, teleport2.y, res2.x, res2.y),
# (255, 0, 0),
# width=1,
# )
# self.map.line(xy, (255, 0, 0), width=3)
@@ -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
@@ -46,11 +46,12 @@ MAP_RATIO = 0.5
async def query_resource(resource_name: str) -> str:
global CENTER_POINT
planning_route: bool = False
if resource_name and resource_name[-2:] == "路径":
if resource_name and resource_name[-2:] in ["路径", "路线"]:
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,196 +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
__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="小真寻要睡觉了,你们也要早点睡呀" + 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', # 任务储存库,在下一小节中说明
# )
+74 -60
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,51 +41,60 @@ 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()
async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
# 真寻被踢出群
# 被踢出群
if event.sub_type == "kick_me":
group_id = event.group_id
operator_id = event.operator_id
@@ -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
-116
View File
@@ -1,116 +0,0 @@
from nonebot import on_command, on_regex
from utils.utils import get_message_text, is_number, FreqLimiter
from nonebot.rule import to_me
from services.log import logger
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP
from nonebot.typing import T_State
from nonebot.matcher import Matcher
from nonebot.permission import SUPERUSER
from pathlib import Path
from configs.config import plugins2info_dict
from nonebot.message import run_preprocessor, IgnoredException
try:
import ujson as json
except ModuleNotFoundError:
import json
__plugin_name__ = "群权限"
__plugin_usage__ = "区分权限功能"
flmt = FreqLimiter(60)
group_level_data = Path() / "data" / "manager" / "group_level.json"
group_level_data.parent.mkdir(exist_ok=True, parents=True)
group_data = {}
if group_level_data.exists():
group_data = json.load(open(group_level_data, "r", encoding="utf8"))
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State):
if not isinstance(event, MessageEvent):
return
if matcher.type == "message" and matcher.priority not in [1, 9]:
if isinstance(event, GroupMessageEvent):
if not group_data.get(str(event.group_id)):
group_data[str(event.group_id)] = 5
if not check_level_group(matcher.module, event.group_id):
try:
if flmt.check(event.group_id):
flmt.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="群权限不足..."
)
except AttributeError:
pass
raise IgnoredException("群权限不足")
add_group_level = on_command("修改群权限", priority=1, permission=SUPERUSER, block=True)
my_group_level = on_command(
"查看群权限", aliases={"群权限"}, priority=5, permission=GROUP, block=True
)
what_up_group_level = on_regex(
".*?(提高|提升|升高|增加|加上)(.*?)群权限.*?",
rule=to_me(),
priority=5,
permission=GROUP,
block=True,
)
@add_group_level.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if not msg:
await add_group_level.finish("用法:修改群权限 [group] [level]")
msg = msg.split(" ")
if len(msg) < 2:
await add_group_level.finish("参数不完全..[group] [level]")
if is_number(msg[0]) and is_number(msg[1]):
group_id = msg[0]
level = int(msg[1])
else:
await add_group_level.finish("参数错误...group和level必须是数字..")
if not group_data.get(group_id):
group_data[group_id] = 5
await add_group_level.send("修改成功...", at_sender=True)
await bot.send_group_msg(
group_id=int(group_id), message=f"管理员修改了此群权限:{group_data[group_id]} -> {level}"
)
group_data[group_id] = level
with open(group_level_data, "w", encoding="utf8") as f:
json.dump(group_data, f, ensure_ascii=False, indent=4)
logger.info(f"{event.user_id} 修改了 {group_id} 的权限:{level}")
@my_group_level.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if group_data.get(str(event.group_id)):
level = group_data[str(event.group_id)]
tmp = ""
for plugin in plugins2info_dict:
if plugins2info_dict[plugin]["level"] > level:
plugin_name = plugins2info_dict[plugin]["cmd"][0]
if plugin_name == "pixiv":
plugin_name = "搜图 p站排行"
tmp += f"{plugin_name}\n"
if tmp:
tmp = "\n目前无法使用的功能:\n" + tmp
await my_group_level.finish(f"当前群权限:{level}{tmp}")
@what_up_group_level.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await what_up_group_level.finish(
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限"
)
# 检查权限
def check_level_group(module: str, group_id: int) -> bool:
if plugins2info_dict.get(module):
if plugins2info_dict[module]["level"] > group_data[str(group_id)]:
return False
return True
+132
View File
@@ -0,0 +1,132 @@
from nonebot import on_command, on_regex
from utils.utils import get_message_text, is_number
from nonebot.rule import to_me
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 NICKNAME
from utils.manager import group_manager, plugins2settings_manager
try:
import ujson as json
except ModuleNotFoundError:
import json
__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)
my_group_level = on_command(
"查看群权限", aliases={"群权限"}, priority=5, permission=GROUP, block=True
)
what_up_group_level = on_regex(
".*?(提高|提升|升高|增加|加上)(.*?)群权限.*?",
rule=to_me(),
priority=5,
permission=GROUP,
block=True,
)
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(" ")
if len(msg) < 2:
await add_group_level.finish("参数不完全..[group] [level]")
if is_number(msg[0]) and is_number(msg[1]):
group_id = msg[0]
level = int(msg[1])
else:
await add_group_level.finish("参数错误...group和level必须是数字..")
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)
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(event.group_id)
tmp = ""
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"
if tmp:
tmp = "\n目前无法使用的功能:\n" + tmp
await my_group_level.finish(f"当前群权限:{level}{tmp}")
@what_up_group_level.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await what_up_group_level.finish(
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限"
)
@manager_group_whitelist.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json()).split()
all_group = [
g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id))
]
group_list = []
for group in msg:
if is_number(group) and int(group) in all_group:
group_list.append(int(group))
if group_list:
for group in group_list:
if state["_prefix"]["raw_command"] in ["添加群白名单"]:
group_manager.add_group_white_list(group)
else:
group_manager.delete_group_white_list(group)
group_list = [str(x) for x in group_list]
await manager_group_whitelist.send(
"已成功将 " + "\n".join(group_list) + " " + state["_prefix"]["raw_command"]
)
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 -29
View File
@@ -1,46 +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 nonebot import require
from .data_source import create_help_img, get_plugin_help
from utils.utils import get_message_text
from pathlib import Path
export = require("nonebot_plugin_manager")
__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"))
-66
View File
@@ -1,66 +0,0 @@
# 实用
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": "运气项目又来啦! --> 指令:塞红包/ 抢红包指令: 开/抢/戳一戳真寻/ 退回:退回未抢完的红包",
"poetry": "突然文艺的真寻是否搞错了什么 --> 指令:念诗/来首诗/念首诗",
"comments_163": "生了个人,我很抱歉 --> 指令:到点了/12点了/网易云热评/网易云评论",
"pix_gallery": "偶尔也想看看美图? --> 指令:PIX [关键词/uid/pid:pid] [num]/查看pix图库 [关键词]/显示pix关键词",
}
# 其他
other_help = [
"查看当前的群欢迎消息 --> 指令:群欢迎消息",
"这是一份正经的自我介绍 --> 指令:自我介绍",
"不得看看自己权力多大? --> 指令:我的权限",
"有人记得你是什么时候加入我们的 --> 指令:我的信息",
"让我看看更新了什么 --> 指令:更新信息",
"真寻给我把话收回去! --> 指令:撤回 [id](默认0)",
"群拥有的权限 --> 指令:查看群权限",
"数据统计可视化_1 --> 指令:功能调用统计/日功能调用统计/周功能调用统计/月功能调用统计",
"数据统计可视化_2 --> 指令:周功能调用统计 [功能名称]/月功能调用统计 [功能名称]",
"这里是PIX图库! --> 指令:添加pix关键词 [关键词]/添加pixuid/pid [UID/PID]/我的pix关键词",
]
+277 -175
View File
@@ -1,187 +1,289 @@
from utils.image_utils import CreateImg
from configs.path_config import IMAGE_PATH, DATA_PATH
import ujson as json
import os
from .config import *
from nonebot import require
from configs.config import (
INITIAL_OPEN_CASE_COUNT,
INITIAL_SETU_PROBABILITY,
ADMIN_DEFAULT_AUTH,
)
from configs.config import plugins2info_dict
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 utils.utils import get_matchers
import random
import asyncio
import nonebot
export = require("nonebot_plugin_manager")
width = 1600
e_height = 0
u_height = 950
o_height = 1500
# f_height =
import os
def create_help_img():
if os.path.exists(IMAGE_PATH + "help.png"):
os.remove(IMAGE_PATH + "help.png")
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),
"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对真寻说 “真寻帮助 指令名” 获取对应详细帮助\n"
"可以通过 “滴滴滴- [消息]” 联系管理员(有趣的想法尽管来吧!<还有Bug和建议>)"
"\n[群管理员请看 管理员帮助(群主与管理员自带 5 级权限)]\n\n"
"\t「如果真寻回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【QAQ】」",
random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help"
background = Path(IMAGE_PATH) / "background" / "0.png"
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)
try:
with open(DATA_PATH + "manager/plugin_list.json", "r", encoding="utf8") as f:
plugin_list = json.load(f)
except (ValueError, FileNotFoundError):
pass
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, plugin_list)
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, plugin_list)
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),
"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对真寻说 “真寻帮助 指令名” 获取对应详细帮助\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「如果真寻回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【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, plugin_list):
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 group_id in plugin_list[cmd]:
if not plugin_list[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
+367 -49
View File
@@ -1,24 +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,
Message,
)
from configs.config import (
BAN_RESULT,
admin_plugins_auth,
MALICIOUS_BAN_TIME,
MALICIOUS_CHECK_TIME,
MALICIOUS_BAN_COUNT,
CHECK_NOTICE_INFO_CD,
)
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.manager import group_manager
import asyncio
try:
import ujson as json
@@ -29,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]:
@@ -42,27 +71,37 @@ 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) + " 分"
if event.message_type == "group":
time = str(time) + " 分钟"
if isinstance(event, GroupMessageEvent):
if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id)
if matcher.priority != 9:
await bot.send_group_msg(
group_id=event.group_id,
message=at(event.user_id) + BAN_RESULT + f" 在..在 {time}后才会理你喔",
)
try:
await bot.send_group_msg(
group_id=event.group_id,
message=at(event.user_id)
+ BAN_RESULT
+ f" 在..在 {time} 后才会理你喔",
)
except ActionFailed:
pass
else:
if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id)
if matcher.priority != 9:
await bot.send_private_msg(
user_id=event.user_id,
message=at(event.user_id) + BAN_RESULT + f" 在..在 {time}后才会理你喔",
)
try:
await bot.send_private_msg(
user_id=event.user_id,
message=at(event.user_id)
+ BAN_RESULT
+ f" 在..在 {time}后才会理你喔",
)
except ActionFailed:
pass
raise IgnoredException("用户处于黑名单中")
@@ -76,56 +115,325 @@ 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)
await bot.send_group_msg(
group_id=event.group_id,
message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
)
if isinstance(event, GroupMessageEvent):
try:
await bot.send_group_msg(
group_id=event.group_id,
message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
)
except ActionFailed:
pass
else:
if not static_flmt.check(event.user_id):
return
static_flmt.start_cd(event.user_id)
await bot.send_private_msg(
user_id=event.user_id,
message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
)
try:
await bot.send_private_msg(
user_id=event.user_id,
message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
)
except ActionFailed:
pass
raise IgnoredException("检测到恶意触发命令")
_blmt.add(f'{event.user_id}{state["_prefix"]["raw_command"]}')
_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):
if not isinstance(event, MessageEvent) or await BanUser.is_ban(event.user_id):
global _exists_msg
module = matcher.module
plugins2info_dict = plugins2settings_manager.get_data()
if (
(not isinstance(event, MessageEvent) and module != "poke")
or await BanUser.is_ban(event.user_id)
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
if matcher.module in admin_plugins_auth.keys() and matcher.priority not in [1, 9]:
if event.message_type == "group":
# 黑名单检测
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[matcher.module]
event.user_id, event.group_id, admin_manager.get_plugin_level(module)
):
await bot.send_group_msg(
group_id=event.group_id,
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
f"{admin_plugins_auth[matcher.module]}",
)
try:
if _flmt.check(event.user_id):
_flmt.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id,
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
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[matcher.module]
event.user_id, 0, admin_manager.get_plugin_level(module)
):
await bot.send_private_msg(
user_id=event.user_id,
message=f"你的权限不足喔,该功能需要的权限等级:{admin_plugins_auth[matcher.module]}",
)
try:
await bot.send_private_msg(
user_id=event.user_id,
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 _exists_msg.get(event.group_id) is None:
_exists_msg[event.group_id] = False
# 群权限
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
event.group_id
):
try:
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, event.group_id):
try:
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", event.group_id):
try:
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)
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:
# 私聊禁用
if not group_manager.get_plugin_status(module, block_type="private"):
try:
if _flmt_c.check(event.user_id):
_flmt_c.start_cd(event.user_id)
await bot.send_private_msg(
user_id=event.user_id, message="该功能在私聊中已被禁用..."
)
except ActionFailed:
pass
raise IgnoredException("该插件在私聊中已被禁用...")
# 维护
if not group_manager.get_plugin_status(module, block_type="all"):
if isinstance(
event, GroupMessageEvent
) and group_manager.check_group_is_white(event.group_id):
return
try:
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="此功能正在维护..."
)
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会自己和自己聊天
@@ -140,10 +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,83 +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
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
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(IMAGE_PATH + TEMP_PATH + "delete.jpg"):
os.remove(IMAGE_PATH + TEMP_PATH + "delete.jpg")
logger.info("删除图片 delete.jpg 成功")
except Exception as e:
logger.warning(f"删除图片 delete.jpg 失败 e{e}")
try:
os.rename(path + img_id + ".jpg", IMAGE_PATH + TEMP_PATH + "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 + img_id + ".jpg"):
try:
if int(img_id) != max_id:
os.rename(path + str(max_id) + ".jpg", path + img_id + ".jpg")
except FileExistsError:
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,93 +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
__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 = IMAGE_PATH + cn2py(state["source_path"])
destination_path = IMAGE_PATH + cn2py(state["destination_path"])
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 + img_id + ".jpg", destination_path + str(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 + str(max_id) + ".jpg", source_path + 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)
@@ -0,0 +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 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)
)
@@ -0,0 +1,51 @@
from configs.config import NICKNAME
from typing import List
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.utils import cn2py
from pathlib import Path
import aiofiles
import aiohttp
import os
async def upload_image_to_local(
img_list: List[str], path: str, user_id: int, group_id: int = 0
) -> str:
_path = path
path = Path(IMAGE_PATH) / cn2py(path)
path.mkdir(parents=True, exist_ok=True)
img_id = len(os.listdir(path))
failed_list = []
success_id = ""
async with aiohttp.ClientSession() as session:
for img_url in img_list:
try:
async with session.get(img_url, timeout=7) as response:
if response.status == 200:
async with aiofiles.open(path / f"{img_id}.jpg", "wb") as f:
await f.write(await response.read())
success_id += str(img_id) + ","
img_id += 1
else:
failed_list.append(img_url)
logger.warning(f"图片:{img_url} 下载失败....")
except TimeoutError as e:
logger.warning(f"图片:{img_url} 下载超时....e:{e}")
if img_url not in failed_list:
failed_list.append(img_url)
failed_result = ""
for img in failed_list:
failed_result += str(img) + "\n"
logger.info(
f"USER {user_id} GROUP {group_id}"
f" 上传图片至 {_path} 共 {len(img_list)} 张,失败 {len(failed_list)} 张,id={success_id[:-1]}"
)
if failed_list:
return (
f"这次一共为 {_path}库 添加了 {len(img_list) - len(failed_list)} 张图片\n"
f"依次的Id为:{success_id[:-1]}\n上传失败:{failed_result[:-1]}\n{NICKNAME}感谢您对图库的扩充!WW"
)
else:
return f"这次一共为 {_path}库 添加了 {len(img_list)} 张图片\n依次的Id为:" \
f"{success_id[:-1]}\n{NICKNAME}感谢您对图库的扩充!WW"
+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()
+290
View File
@@ -0,0 +1,290 @@
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())} 个非限制插件.")
print(admin_manager)
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 -2
View File
@@ -6,9 +6,24 @@ from nonebot.typing import T_State
import aiohttp
from asyncio.exceptions import TimeoutError
__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": ["鸡汤", "毒鸡汤"],
}
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}"
)
+30 -7
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
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 = {}
@@ -105,7 +128,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
user_id=event.user_id,
duration=mute_data[group_id]["duration"],
)
await mute.send("检测到恶意刷屏,真寻要把你关进小黑屋!", at_sender=True)
await mute.send(f"检测到恶意刷屏,{NICKNAME}要把你关进小黑屋!", at_sender=True)
mute_dict[event.user_id]["count"] = 0
logger.info(
f"USER {event.user_id} GROUP {event.group_id} "
+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)
+66
View File
@@ -0,0 +1,66 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from utils.utils import get_message_text
from services.log import logger
import ujson as json
import aiohttp
__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"
nbnhhsh = on_command("nbnhhsh", aliases={"能不能好好说话"}, priority=5, block=True)
@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:
async with session.post(
HHSH_GUESS_URL, data=json.dumps({"text": msg}), timeout=5
) as response:
if response.status == 200:
try:
data = await response.json()
tmp = ""
rst = ""
for x in data:
trans = ""
if x.get("trans"):
trans = x["trans"][0]
elif x.get("inputting"):
trans = ",".join(x["inputting"])
tmp += f'{x["name"]} -> {trans}\n'
rst += trans
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送能不能好好说话: {msg} -> {rst}"
)
await nbnhhsh.send(f"{tmp}={rst}", at_sender=True)
except (IndexError, KeyError):
await nbnhhsh.finish("没有找到对应的翻译....")
else:
await nbnhhsh.finish("网络访问失败了....")
+51 -41
View File
@@ -8,11 +8,21 @@ from models.friend_user import FriendUser
import random
from models.ban_user import BanUser
from services.log import logger
from configs.config import NICKNAME
__plugin_name__ = "昵称系统"
__plugin_usage__ = "用法:\n" "以后叫我 [名称]\n" "真寻我是谁"
__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",
@@ -46,13 +56,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await nickname.send(
random.choice(
[
"好啦好啦,我知道啦,{},以后就这么叫你吧",
"嗯嗯,小真寻记住你的昵称了哦,{}",
"好突然,突然要叫你昵称什么的...{}..",
"小真寻会好好记住的{}的,放心吧",
"好..好.,那窝以后就叫你{}了.",
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住的{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
).format(msg)
)
)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}")
else:
@@ -71,13 +81,13 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
await nickname.send(
random.choice(
[
"好啦好啦,我知道啦,{},以后就这么叫你吧",
"嗯嗯,小真寻记住你的昵称了哦,{}",
"好突然,突然要叫你昵称什么的...{}..",
"小真寻会好好记住的{}的,放心吧",
"好..好.,那窝以后就叫你{}了.",
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住的{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
).format(msg)
)
)
logger.info(f"USER {event.user_id} 设置昵称 {msg}")
else:
@@ -97,14 +107,14 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await my_nickname.send(
random.choice(
[
"我肯定记得你啊,你是{}啊",
"我不会忘记你的,你也不要忘记我!{}",
"哼哼,真寻记忆力可是很好的,{}",
"嗯?你是失忆了嘛...{}..",
"不要小看真寻的记忆力啊!笨蛋{}!QAQ",
"哎?{}..怎么了吗..突然这样问..",
f"我肯定记得你啊,你是{nickname_}啊",
f"我不会忘记你的,你也不要忘记我!{nickname_}",
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
f"嗯?你是失忆了嘛...{nickname_}..",
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
f"哎?{nickname_}..怎么了吗..突然这样问..",
]
).format(nickname_)
)
)
else:
nickname_ = event.sender.card if event.sender.card else event.sender.nickname
@@ -122,14 +132,14 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
await my_nickname.send(
random.choice(
[
"我肯定记得你啊,你是{}啊",
"我不会忘记你的,你也不要忘记我!{}",
"哼哼,真寻记忆力可是很好的,{}",
"嗯?你是失忆了嘛...{}..",
"不要小看真寻的记忆力啊!笨蛋{}!QAQ",
"哎?{}..怎么了吗..突然这样问..",
f"我肯定记得你啊,你是{nickname_}啊",
f"我不会忘记你的,你也不要忘记我!{nickname_}",
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
f"嗯?你是失忆了嘛...{nickname_}..",
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
f"哎?{nickname_}..怎么了吗..突然这样问..",
]
).format(nickname_)
)
)
else:
nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"]
@@ -149,13 +159,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await cancel_nickname.send(
random.choice(
[
"呜..真寻睡一觉就会忘记的..和梦一样..{}",
"窝知道了..{}..",
"是真寻哪里做的不好嘛..好吧..晚安{}",
"呃,{},下次我绝对绝对绝对不会再忘记你!",
"可..可恶!{}!太可恶了!呜",
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
f"窝知道了..{nickname_}..",
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
f"可..可恶!{nickname_}!太可恶了!呜",
]
).format(nickname_)
)
)
await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "")
await BanUser.ban(event.user_id, 9, 60)
@@ -170,13 +180,13 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
await cancel_nickname.send(
random.choice(
[
"呜..真寻睡一觉就会忘记的..和梦一样..{}",
"窝知道了..{}..",
"是真寻哪里做的不好嘛..好吧..晚安 {}",
"呃,{},下次我绝对绝对绝对不会再忘记你!",
"可..可恶!{}!太可恶了!呜",
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
f"窝知道了..{nickname_}..",
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
f"可..可恶!{nickname_}!太可恶了!呜",
]
).format(nickname_)
)
)
await FriendUser.get_user_name(event.user_id)
await BanUser.ban(event.user_id, 9, 60)
-122
View File
@@ -1,122 +0,0 @@
from nonebot.plugin import on_shell_command, get_loaded_plugins, export
from nonebot.matcher import Matcher
from nonebot.typing import T_State
from nonebot.exception import IgnoredException
from nonebot.message import run_preprocessor
from nonebot.adapters.cqhttp import (
Event,
Bot,
GroupMessageEvent,
PrivateMessageEvent,
MessageEvent,
)
from configs.config import plugins2info_dict
from utils.utils import FreqLimiter
from models.ban_user import BanUser
from .data import (
block_plugin,
unblock_plugin,
get_group_plugin_list,
auto_update_plugin_list,
)
from .parser import npm_parser
# 导出给其他插件使用
export = export()
export.block_plugin = block_plugin
export.unblock_plugin = unblock_plugin
export.get_group_plugin_list = get_group_plugin_list
# 注册 shell_like 事件响应器
plugin_manager = on_shell_command("npm", parser=npm_parser, priority=1)
flmt = FreqLimiter(60)
# 在 Matcher 运行前检测其是否启用
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not isinstance(event, MessageEvent) and matcher.module != 'poke':
return
plugin = matcher.module
group_id = _get_group_id(event)
loaded_plugin_list = _get_loaded_plugin_list()
plugin_list = auto_update_plugin_list(loaded_plugin_list)
# 无视本插件的 Matcher
if (
plugin not in plugins2info_dict
or matcher.priority in [1, 9]
or await BanUser.is_ban(event.user_id)
):
return
if isinstance(event, PrivateMessageEvent) and plugin_list[plugin]["default"]:
return
if not plugin_list[plugin]["default"]:
if str(event.user_id) in bot.config.superusers:
return
if isinstance(event, GroupMessageEvent):
if flmt.check(event.group_id):
flmt.start_cd(event.group_id)
await bot.send_group_msg(group_id=event.group_id, message="此功能正在维护...")
else:
if flmt.check(event.user_id):
flmt.start_cd(event.user_id)
await bot.send_private_msg(user_id=event.user_id, message="此功能正在维护...")
raise IgnoredException(f"Nonebot Plugin Manager has blocked {plugin} !")
if group_id in plugin_list[plugin]:
if not plugin_list[plugin][group_id]:
if plugin != "ai" and matcher.type == "message":
if flmt.check(event.group_id):
flmt.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该群未开启此功能.."
)
raise IgnoredException(f"Nonebot Plugin Manager has blocked {plugin} !")
@plugin_manager.handle()
async def _(bot: Bot, event: Event, state: T_State):
args = state["args"]
group_id = _get_group_id(event)
is_admin = _is_admin(event)
is_superuser = _is_superuser(bot, event)
if group_id == 0:
group_id = "default"
if hasattr(args, "handle"):
await plugin_manager.finish(args.handle(args, group_id, is_admin, is_superuser))
# 获取插件列表,并自动排除本插件
def _get_loaded_plugin_list() -> list:
return list(
filter(
lambda plugin: plugin != "nonebot_plugin_manager",
map(lambda plugin: plugin.name, get_loaded_plugins()),
)
)
def _get_group_id(event: Event) -> str:
try:
group_id = event.group_id
except AttributeError:
group_id = "default"
return str(group_id) if group_id else "default"
def _is_admin(event: Event) -> bool:
return (
event.sender.role in ["admin", "owner"]
if isinstance(event, GroupMessageEvent)
else False
)
def _is_superuser(bot: Bot, event: Event) -> bool:
return str(event.user_id) in bot.config.superusers
plugins_dict = {}
-121
View File
@@ -1,121 +0,0 @@
import json
import httpx
from pathlib import Path
from configs.config import plugins2info_dict
_DATA_PATH = Path() / "data" / "manager" / "plugin_list.json"
def get_store_plugin_info(plugin: str) -> str:
store_plugin_list = _get_store_plugin_list()
if plugin in store_plugin_list:
plugin = store_plugin_list[plugin]
return (
f"ID: {plugin['id']}\n"
f"Name: {plugin['name']}\n"
f"Description: {plugin['desc']}\n"
f"Version: {httpx.get('https://pypi.org/pypi/'+plugin['link']+'/json').json()['info']['version']}\n"
f"Author: {plugin['author']}\n"
f"Repo: https://github.com/{plugin['repo']}"
)
else:
return "查无此插件!"
def get_group_plugin_list(group_id: str) -> dict:
plugin_list = _load_plugin_list()
group_plugin_list = {}
for plugin in plugin_list:
if group_id in plugin_list[plugin]:
group_plugin_list[plugin] = plugin_list[plugin][group_id]
else:
group_plugin_list[plugin] = plugin_list[plugin]["default"]
return group_plugin_list
def get_store_pulgin_list() -> str:
message = "商店插件列表如下:"
for plugin in _get_store_plugin_list():
if plugin in _load_plugin_list() or plugin == "nonebot_plugin_manager":
message += f"\n[o] {plugin}"
else:
message += f"\n[x] {plugin}"
return message
def auto_update_plugin_list(loaded_plugin_list: list, keep_history: bool = False):
plugin_list = _load_plugin_list()
for plugin in loaded_plugin_list:
if plugin not in plugin_list:
plugin_list[plugin] = {"default": True}
if not keep_history:
plugin_list = {
key: plugin_list[key] for key in plugin_list if key in loaded_plugin_list
}
_dump_plugin_list(plugin_list)
return plugin_list
def block_plugin(group_id: str, *plugins: str):
return _update_plugin_list(group_id, True, *plugins)
def unblock_plugin(group_id: str, *plugins: str):
return _update_plugin_list(group_id, False, *plugins)
# 获取商店插件列表
def _get_store_plugin_list() -> dict:
store_plugin_list = {}
for plugin in httpx.get(
"https://cdn.jsdelivr.net/gh/nonebot/nonebot2@master/docs/.vuepress/public/plugins.json"
).json():
store_plugin_list.update({plugin["id"]: plugin})
return store_plugin_list
# 更新插件列表
def _update_plugin_list(group_id: str, block: bool, *plugins: str) -> str:
plugin_list = _load_plugin_list()
message = "结果如下:"
operate = "屏蔽" if block else "启用"
for plugin in plugins:
for values in plugins2info_dict.values():
if plugin in values['cmd']:
plugin = list(plugins2info_dict.keys())[list(plugins2info_dict.values()).index(values)]
# print(plugin)
break
message += "\n"
if plugin in plugin_list:
if (
not group_id in plugin_list[plugin]
or plugin_list[plugin][group_id] == block
):
plugin_list[plugin][group_id] = not block
message += f"插件{plugin}{operate}成功!"
print(plugin_list[plugin][group_id])
else:
message += f"插件{plugin}已经{operate}!"
else:
message += f"插件{plugin}不存在!"
_dump_plugin_list(plugin_list)
return message
# 加载插件列表
def _load_plugin_list() -> dict:
try:
return json.load(_DATA_PATH.open("r", encoding="utf-8"))
except FileNotFoundError:
return {}
# 保存插件列表
def _dump_plugin_list(plugin_list: dict):
_DATA_PATH.parent.mkdir(parents=True, exist_ok=True)
json.dump(
plugin_list,
_DATA_PATH.open("w", encoding="utf-8"),
indent=4,
separators=(",", ": "),
)
-138
View File
@@ -1,138 +0,0 @@
from argparse import Namespace
from .data import *
def handle_list(
args: Namespace,
group_id: str,
is_admin: bool,
is_superuser: bool,
) -> str:
message = ""
if args.store:
if is_superuser:
return get_store_pulgin_list()
else:
return "获取商店插件列表需要超级用户权限!"
if args.default:
if is_superuser:
group_id = "default"
message += "默认"
else:
return "获取默认插件列表需要超级用户权限!"
if args.group:
if is_superuser:
group_id = args.group
message += f"群{args.group}"
else:
return "获取指定群插件列表需要超级用户权限!"
message += "插件列表如下:\n"
message += "\n".join(
f"[{'o' if get_group_plugin_list(group_id)[plugin] else 'x'}] {plugin}"
for plugin in get_group_plugin_list(group_id)
)
return message
def handle_block(
args: Namespace,
group_id: str,
is_admin: bool,
is_superuser: bool,
) -> str:
if not is_admin and not is_superuser:
return "管理插件需要群管理员权限!"
message = ""
if args.default:
if is_superuser:
group_id = "default"
message += "默认"
else:
return "管理默认插件需要超级用户权限!"
if args.group:
if is_superuser:
group_id = args.group
message += f"群{args.group}"
else:
return "管理指定群插件需要超级用户权限!"
message += block_plugin(group_id, *args.plugins)
return message
def handle_unblock(
args: Namespace,
group_id: str,
is_admin: bool,
is_superuser: bool,
) -> str:
message = ""
if not is_admin and not is_superuser:
return "管理插件需要群管理员权限!"
if args.default:
if is_superuser:
group_id = "default"
message += "默认"
else:
return "管理默认插件需要超级用户权限!"
if args.group:
if is_superuser:
group_id = args.group
message += f"群{args.group}"
else:
return "管理指定群插件需要超级用户权限!"
message += unblock_plugin(group_id, *args.plugins)
return message
def handle_info(
args: Namespace,
group_id: str,
is_admin: bool,
is_superuser: bool,
) -> str:
if not is_admin and not is_superuser:
return "管理插件需要超级权限!"
return get_store_plugin_info(args.plugin)
def handle_install(
args: Namespace,
group_id: str,
is_admin: bool,
is_superuser: bool,
) -> str:
pass
def handle_update(
args: Namespace,
group_id: str,
is_admin: bool,
is_superuser: bool,
) -> str:
pass
def handle_uninstall(
args: Namespace,
group_id: str,
is_admin: bool,
is_superuser: bool,
) -> str:
pass

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