Compare commits

..
736 Commits
Author SHA1 Message Date
HibiKier 32e420efbb UPDATE README.md 2022-12-27 11:32:40 +08:00
HibiKier 6db9bef115 添加权限检查依赖注入 2022-12-27 11:31:34 +08:00
HibiKier a0b440efcd UPDATE README.md 2022-12-26 22:41:11 +08:00
HibiKier d2bb7ae493 Merge pull request #1221 from newton-miku/main
修复epic获取到的简介不是中文的bug
2022-12-26 22:30:36 +08:00
HibiKier b4e213518b x 2022-12-26 19:11:52 +08:00
HibiKier e3b0da4717 Merge remote-tracking branch 'origin/main' 2022-12-26 19:00:54 +08:00
HibiKier 155de5a032 UPDATE README.md 2022-12-26 19:00:35 +08:00
HibiKier 57e166940d Add files via upload 2022-12-26 18:59:01 +08:00
HibiKier 721efb79fd Delete 3238573864-836268675-E2FFBB2AC143EAF4DDDF150438508721.png 2022-12-26 18:56:48 +08:00
HibiKier 5338342208 Add files via upload 2022-12-26 18:56:30 +08:00
HibiKier c49ef3052f 提供全局被动控制 2022-12-26 18:40:34 +08:00
HibiKier 802f4df2ce 优化gamedraw插件 2022-12-26 01:30:56 +08:00
newton_miku 1edcee9ce3 修复epic获取到的简介不是中文的bug
因为epic的api获取免费游戏时简介始终是英文,故更换为使用游戏销售页面的简介
2022-12-25 14:33:40 +08:00
HibiKier 3acd7d7d41 修复群管理员权限检测会阻挡超级用户权限 2022-12-24 18:57:56 +08:00
HibiKier 83dc29a562 更新依赖 2022-12-24 01:29:21 +08:00
HibiKier b25b9ca928 优化管理员帮助,超级用户帮助图片,重新移植gamedraw,修复pil帮助私聊时无法生成 2022-12-24 00:16:17 +08:00
HibiKier 0dc11b7edb 修复查看插件仓库当已安装插件版本不一致时出错 2022-12-17 13:41:37 +08:00
HibiKier 9b477e2eb8 修复自定义群欢迎消息无法使用 2022-12-15 22:43:58 +08:00
HibiKier 272f6726ea 更新HTML菜单文件 2022-12-15 19:03:17 +08:00
HibiKier 181717001a Merge remote-tracking branch 'origin/main' 2022-12-15 18:14:39 +08:00
HibiKier 43b654285f Merge pull request #1214 from LambdaYH/patch-5
Update zhenxun_menu.html
2022-12-15 18:10:35 +08:00
Cinte 50e7d5036e Update zhenxun_menu.html
https://github.com/HibiKier/zhenxun_bot/issues/1206
2022-12-14 22:51:07 +08:00
HibiKier b6b2f2e2a6 修复.unban 2022-12-13 23:01:12 +08:00
HibiKier b9d08855d0 Add files via upload 2022-12-12 22:55:15 +08:00
HibiKier 93deb2b1be Merge remote-tracking branch 'origin/main' 2022-12-12 22:53:21 +08:00
HibiKier b3871d550c 修复HTML帮助私聊无法生成, 修改HTML帮助禁用提示文本错误 2022-12-12 22:52:56 +08:00
HibiKier ab8e87899c Add files via upload 2022-12-11 23:39:20 +08:00
HibiKier 9d6f44849a UPDATE path_config 2022-12-11 23:34:54 +08:00
HibiKier 380588c11d 帮助新增HTML生成(新布局),添加配置TYPE切换 2022-12-11 23:33:16 +08:00
HibiKier 5810c28294 修复加入新群聊时初始化功能开关错误 2022-12-11 02:49:21 +08:00
HibiKier c039015e8f 添加单例注解 2022-12-11 01:53:59 +08:00
HibiKier 0dda0a228a test 2022-12-11 01:33:31 +08:00
HibiKier 940514b16b 更正私聊时功能管理回复错误 2022-12-11 01:30:23 +08:00
HibiKier 8adff43113 添加统计表 2022-12-11 01:11:09 +08:00
HibiKier b59699dabe 词条问题支持真寻的昵称开头与at真寻开头并优化回复 2022-12-11 00:10:07 +08:00
HibiKier f496ce4861 重写帮助,删除 详细帮助 命令 2022-12-10 19:59:16 +08:00
HibiKier 5fb4eccd0f 优化管理代码 2022-12-04 16:47:14 +08:00
HibiKier 31e4cadecb 优化代码 2022-12-04 16:46:33 +08:00
HibiKier 994484f3b0 修复web_ui群组无法获取,修复web_ui修改插件数据时cmd格式错误 2022-11-30 23:40:55 +08:00
HibiKier 7b3a3451f6 Merge pull request #1188 from Nova-Noir/Hibikier-main
🐛 Fix a bug in open_cases to get vanilla knives' prices
2022-11-28 20:14:57 +08:00
HibiKier 14d075bc17 修复管理员插件加载路径错误 2022-11-24 19:16:31 +08:00
HibiKier 75369411b3 修复管理员插件加载路径错误 2022-11-24 19:16:04 +08:00
HibiKier d97542a3fd 修复webui插件无法获取修改 2022-11-23 23:11:36 +08:00
Nova-Noir 2f70fcd92a 🐛 Fix a bug in open_cases to get vanilla knives' prices 2022-11-23 15:33:49 +08:00
HibiKier 182f93d618 Merge pull request #1185 from LambdaYH/patch-3
fix switch_rule
2022-11-22 20:14:10 +08:00
Cinte 34e28384dd check_plugin_status 中判断是否加载失败的逻辑似乎反了 2022-11-22 11:31:42 +08:00
Cinte f6f095f949 去掉没有用处还会引发异常的一行 2022-11-22 11:23:29 +08:00
Cinte 08609bdf53 fix switch_rule 2022-11-22 11:06:48 +08:00
HibiKier 5de5667f80 更新manage models 2022-11-21 22:20:19 +08:00
HibiKier 69b3ba47b3 update README.md 2022-11-21 20:52:07 +08:00
HibiKier 11c1d0b827 Update __version__ 2022-11-21 20:51:17 +08:00
HibiKier 8f97880754 update README.md 2022-11-21 20:50:21 +08:00
HibiKier ff435bea95 Merge pull request #1180 from PercyDan54/patch-1
修复pid搜图
2022-11-21 20:49:49 +08:00
HibiKier cd66b7f5b8 优化manager代码 2022-11-21 20:43:41 +08:00
PercyDan a60286c328 Fix pid search 2022-11-20 16:52:51 +08:00
HibiKier 49e38862af 修改优化帮助图片生成逻辑 2022-11-19 01:05:08 +08:00
HibiKier 75b8cc0766 Merge pull request #1176 from yajiwa/main
poetry添加适配器依赖,更新支持py3.10
2022-11-17 11:31:51 +08:00
yajiwa a8e2f00e16 poetry flie add adapter 2022-11-15 22:04:13 +08:00
HibiKier d099a85c59 限制帮助图片最小宽度 2022-11-13 04:46:08 +08:00
HibiKier 55b2a86397 使用道具可以附带额外信息供函数使用 2022-11-13 04:12:56 +08:00
HibiKier d39dfbe62f 更新天气api 2022-11-13 02:05:34 +08:00
HibiKier a41e62cefe update README.md 2022-11-13 00:37:22 +08:00
HibiKier c981562f90 Merge pull request #1168 from wse320/main
更新yiqing插件数据显示
2022-11-11 23:11:50 +08:00
HibiKier e6cd57cc26 Merge pull request #1162 from DDS-DS/main
fix: B站直播订阅的相关问题(issues 1158)
2022-11-10 19:52:46 +08:00
wse320 074152ae14 Update data_source.py 2022-11-07 20:24:49 +08:00
DDS-DS 91ca7b40b8 补充代码 2022-11-05 02:17:04 +08:00
dingshan 5321c8d9c0 fix:
1、兼容B站下播的两种状态
2、更改订阅入库逻辑,加入订阅类型
2022-10-31 15:47:40 +08:00
HibiKier b7f753ebb6 商店简介动态行数,根据文字长度自动换行 2022-10-30 18:28:10 +08:00
HibiKier c5e8ba3cdf Merge pull request #1154 from guohu7777/main
把某人漏掉的给复制上去
2022-10-28 18:29:38 +08:00
HibiKier 658ef5309b Merge pull request #1155 from Lycoiref/main
为exec指令进行了SELECT语句适配,添加了查看所有表指令
2022-10-28 18:29:27 +08:00
HDU_Nbsp 823f642225 为exec指令进行了SELECT语句适配,添加了查看所有表指令 2022-10-25 03:27:26 +08:00
guohu7777 57ea6bad07 把某人漏掉的给复制上去
1111
2022-10-24 22:13:25 +08:00
HibiKier 109c645e68 复读修改回图片下载 2022-10-23 11:49:15 +08:00
HibiKier 5ef0ce5aa8 Merge remote-tracking branch 'origin/main' 2022-10-23 00:34:03 +08:00
HibiKier f6d9e083b8 Merge pull request #1151 from DDS-DS/main
update bt url
2022-10-22 18:26:59 +08:00
HibiKier 499517e882 更新依赖注入 2022-10-22 18:12:55 +08:00
dingshan 648db532bb update bt url 2022-10-21 10:07:55 +08:00
HibiKier 1ce4537605 upadte README.md 2022-10-16 22:54:34 +08:00
HibiKier 701812ed9d upadte README.md 2022-10-16 22:39:57 +08:00
HibiKier 8d9e81827b 修改版本 2022-10-16 22:38:12 +08:00
HibiKier f51a2816b4 修改依赖注入方法 2022-10-16 22:37:58 +08:00
HibiKier 3d4a7950c5 修改依赖注入方法 2022-10-16 22:36:13 +08:00
HibiKier ba6668f144 修改商店道具icon可以为空 2022-10-16 11:46:56 +08:00
HibiKier e1f7a77d15 修正 2022-10-16 00:21:42 +08:00
HibiKier 64e2c512d3 Merge remote-tracking branch 'origin/main' 2022-10-16 00:21:30 +08:00
HibiKier 6082e68a1f Delete Generate.yml 2022-10-16 00:21:00 +08:00
HibiKier f135d48e55 Merge remote-tracking branch 'origin/main' 2022-10-16 00:20:24 +08:00
HibiKier 751fc8fdb4 修复我的道具仅有被动或主动道具时图片显示错误 2022-10-16 00:19:55 +08:00
github-actions[bot] df73e79ee4 Auto generate poetry.lock 2022-10-15 15:10:25 +00:00
HibiKier fa6cfdb609 修正 2022-10-15 23:07:26 +08:00
HibiKier b057a05520 更多的依赖注入 2022-10-15 22:13:41 +08:00
HibiKier cb0938721c 新增用户使用道具,花费金币及用途记录表以及更细致的金币使用依赖注入 2022-10-15 21:21:23 +08:00
HibiKier 4f3f8de734 错误捕获 2022-10-15 20:50:02 +08:00
HibiKier 5ba303aada Merge pull request #1139 from yuzb1beiz/main
色图插件p站反向代理失效
2022-10-15 20:42:49 +08:00
yusean bd42fefe4e Merge branch 'HibiKier:main' into main 2022-10-15 20:15:29 +08:00
sean d24c081973 修复色图插件p站反向代理失效问题 2022-10-15 20:00:06 +08:00
HibiKier 1b9eddd905 Add files via upload 2022-10-15 19:53:11 +08:00
HibiKier 0bfe398dc4 更新至nonebot-rc1 2022-10-15 19:49:53 +08:00
HibiKier e9216a472f Add files via upload 2022-10-13 19:36:54 +08:00
HibiKier 8b93ec0df6 Delete poetry.lock 2022-10-13 19:36:40 +08:00
HibiKier 7497706a0d Merge pull request #1124 from DDS-DS/main
修复碧蓝档案角色获取问题,换源
2022-10-09 19:14:35 +08:00
dingshan 6e41cb0630 修复碧蓝档案角色获取问题,换源 2022-10-09 16:08:55 +08:00
HibiKier 62d99e7e90 Merge remote-tracking branch 'origin/main' 2022-10-07 22:07:51 +08:00
HibiKier 43cddb3580 关闭功能与被动时不再区分大小写 2022-10-07 22:07:36 +08:00
github-actions[bot] c9c1beda75 Auto generate poetry.lock 2022-10-07 13:00:26 +00:00
HibiKier 3ee9ae5fb8 Merge pull request #1119 from SK-415/main
修复 B 站请求返回 -401 错误
2022-10-07 20:57:33 +08:00
github-actions[bot] ea6344fae1 Auto generate poetry.lock 2022-10-02 22:53:37 +00:00
SK 6f54e91f5c ⬆️ Bump bilireq to v0.2.3 2022-10-02 22:50:00 +00:00
HibiKier 27fb3aaa19 Merge pull request #1118 from guohu7777/main
修改重置开箱的使用权限
2022-09-29 18:01:39 +08:00
guohu7777 86d736745d 修改重置开箱的使用权限
禁止普通群员使用重置每日开箱次数指令
2022-09-28 01:23:42 +08:00
HibiKier 821fe21c2b Merge pull request #1117 from yajiwa/main
更新b站转发解析
2022-09-27 19:31:11 +08:00
yajiwa 7f4aa518dc update parse_bilibili 2022-09-27 03:11:57 +08:00
HibiKier 8cf589e433 UPDATE README.md 2022-09-25 21:43:23 +08:00
HibiKier 105a29cd70 Merge pull request #1114 from DDS-DS/main
fix: 重载赛马娘卡池失败
2022-09-24 17:50:52 +08:00
HibiKier cb6a5e81e7 Merge pull request #1112 from yajiwa/main
修复b站订阅
2022-09-24 17:49:57 +08:00
dingshan 9c073383ad fix: 重载赛马娘卡池失败 2022-09-23 18:27:04 +08:00
github-actions[bot] 5e0756825d Auto generate poetry.lock 2022-09-21 19:39:34 +00:00
yajiwa 933523ae6d fix bilibili_sub 2022-09-22 03:35:34 +08:00
HibiKier ed6b05605c Update map.py 2022-09-21 21:59:19 +08:00
HibiKier 71a9c34620 Merge pull request #1108 from yajiwa/main
修复原神资源查询没有图片
2022-09-21 21:57:55 +08:00
HibiKier e29f2cb920 Update query_resource.py 2022-09-21 21:57:25 +08:00
yajiwa d47dd88d6c fix genshin path 2022-09-21 01:13:37 +08:00
github-actions[bot] fb34bbce7a Auto generate poetry.lock 2022-09-20 15:36:00 +00:00
HibiKier 100236da83 修复csgo每日开箱可以多开一次 2022-09-19 22:50:56 +08:00
HibiKier a45a3002d5 Merge pull request #1097 from LambdaYH/main
更换bilibili_sub获取用户昵称用的API&尝试修了一下get_video()
2022-09-19 22:34:01 +08:00
HibiKier 9214a4c978 Merge pull request #1098 from yajiwa/main
update check_zhenxun
2022-09-18 15:07:52 +08:00
HibiKier 70761dc222 Merge pull request #1096 from SK-415/main
修复 bilireq 版本过低导致 B 站视频解析错误
2022-09-18 15:05:29 +08:00
Cinte 32e8136f71 fix get_video()
目前测试了下,至少-401的情况少了很多
2022-09-17 18:26:49 +08:00
yajiwa 8b20d99b2c update check_zhenxun 2022-09-17 13:01:50 +08:00
Cinte 1174b5cc7f x 2022-09-17 11:23:55 +08:00
Cinte ec448cfdfb replace get_user_info with get_user_card 2022-09-17 10:58:58 +08:00
SK f3e44b1baf chore(deps): update bilireq 2022-09-16 23:24:40 +00:00
HibiKier 0ea740aa7c Update __version__ 2022-09-16 19:35:33 +08:00
HibiKier 5f118471cb 修复一些问题 2022-09-16 19:29:05 +08:00
HibiKier 504f78dd49 Merge pull request #1090 from NumberSir/main
fix: bilibili_sub, azur_draw_card
2022-09-16 19:14:19 +08:00
Number_Sir 72723c7d1f 修复碧蓝航线抽卡错误 2022-09-16 12:55:22 +08:00
Number_Sir 6a74053853 bilibili_sub更新检查失败时改为logger通知,不在群里发消息 2022-09-16 12:43:22 +08:00
HibiKier af0b4987a4 Merge pull request #1067 from DDS-DS/main
fix:bt url打开失败
2022-09-10 00:20:44 +08:00
HibiKier 775140cf79 自定义群欢迎消息参数不完全时提示报错 2022-09-09 22:41:39 +08:00
HibiKier 6a8a796add 添加插件数据初始化判断 2022-09-08 20:13:26 +08:00
DDS-DS 8e4bda3760 fix bt url打开失败 2022-09-08 01:35:41 +08:00
HibiKier a36e8145a8 旧词条提供图片迁移 2022-09-04 22:05:56 +08:00
HibiKier 3cbd899daa 修复原神资源查询地图api数据变更导致更新的地图不完全 2022-09-03 18:17:42 +08:00
HibiKier 30f356a2c7 Merge remote-tracking branch 'origin/main' 2022-09-03 17:30:21 +08:00
HibiKier 1138a115ce B站订阅在群里中任意群管理员可以统一管理 2022-09-03 17:30:03 +08:00
HibiKier c397da75e7 Merge pull request #1033 from q56535/main
av号覆盖全面,且修复av号链接
2022-09-03 17:14:22 +08:00
HibiKier 1d141c9313 Merge pull request #1059 from unknownsno/main
fix bug
2022-09-03 16:56:49 +08:00
q56535 a4cc365af8 Merge branch 'HibiKier:main' into main 2022-09-03 16:44:57 +08:00
HibiKier 4e551bec0d 修复词条含有CQ回答的模糊匹配无法被解析 2022-09-03 16:16:33 +08:00
unknwonsno e03086062d fix bug 2022-09-03 14:43:13 +08:00
HibiKier 270a5a5e20 Merge pull request #1053 from unknownsno/main
原神玩家查询增加须弥地区
2022-09-03 14:24:18 +08:00
unknwonsno bda9133ed6 原神玩家查询增加须弥地区 2022-08-31 22:22:00 +08:00
HibiKier 749f475f2c UPDATE README.md 2022-08-27 18:25:30 +08:00
HibiKier e38394948c Merge pull request #1044 from zyj3421/main
修复签到积分双倍后,日志记录获得积分变4倍问题
2022-08-27 18:22:35 +08:00
zyj2134 51fc4cbb6a 修复签到积分双倍后,日志记录获得积分变4倍问题 2022-08-26 22:49:51 +08:00
zyj2134 9a976cda37 Merge remote-tracking branch 'origin/main' 2022-08-26 22:39:48 +08:00
HibiKier e42521f0a3 修复词条关键词"问"前空格问题 2022-08-26 19:39:23 +08:00
HibiKier 0756d39ac5 修复群管理员无法添加词条 2022-08-26 19:26:09 +08:00
zyj2134 4595bdcee4 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	README.md
#	plugins/bilibili_sub/__init__.py
2022-08-25 23:00:49 +08:00
HibiKier 38160065cc UPDATE README.md 2022-08-23 23:02:06 +08:00
HibiKier 3d04f013cd Merge pull request #1032 from LambdaYH/p1
修了下模糊匹配 issue#1026
2022-08-23 20:21:25 +08:00
q56535 8e1a416be3 av号覆盖全面 2022-08-23 13:43:43 +08:00
LambdaYH a98bc42f1a fix https://github.com/HibiKier/zhenxun_bot/issues/1026 2022-08-23 13:16:14 +08:00
HibiKier 6c93769838 UPDATE README.md 2022-08-22 22:51:36 +08:00
HibiKier d2dccfebc5 取消配置替换定时任务,统一存储 2022-08-22 22:49:35 +08:00
HibiKier 82fe59e469 修复首次安装时词条旧表出错 2022-08-22 20:59:08 +08:00
HibiKier afc05e1731 Merge remote-tracking branch 'origin/main' 2022-08-22 20:48:57 +08:00
HibiKier 0206b0a522 UPDATE README.md 2022-08-22 20:47:32 +08:00
HibiKier 0e1e5a5ebe Merge pull request #1012 from LambdaYH/patch-4
修复词库问答几个问题
2022-08-22 20:45:31 +08:00
HibiKier 9ad088ed6a Merge pull request #1010 from CRAZYShimakaze/main
修正尘歌壶和质变仪图片获取地址
2022-08-22 20:43:22 +08:00
HibiKier 34da04bba5 Merge pull request #1014 from xiayingLIULI/main
对米游社cookie进行判断,整合米游社签到信息
2022-08-22 20:41:32 +08:00
HibiKier 09ce812faf Update __init__.py 2022-08-22 20:39:03 +08:00
xiayingLIULI 1dc8cb2a98 修复米游社签到在无用户cookie的情况下执行的错误 2022-08-22 13:45:04 +08:00
xiayingLIULI e73c509823 修复米游社签到在无用户cookie的情况下执行的错误 2022-08-22 13:33:49 +08:00
Cinte e70a85400f 查看词条的id范围判断少了个等号 2022-08-22 12:56:35 +08:00
Cinte f7aecf8eed Update word_handle.py 2022-08-22 12:37:06 +08:00
Cinte cc2645aa9d Update word_handle.py 2022-08-22 12:34:21 +08:00
xiayingLIULI 52d23c4a8d 修复能在群聊中查看我的cookie 2022-08-22 11:44:21 +08:00
Cinte 1e57ddb9ee 处理at后自动接空格的情况,problem中允许单空白字符号 & 修复二次元触发 2022-08-22 11:14:04 +08:00
Cinte 7ae883d921 使用check构造的problem而不在message_handle中重新构造 2022-08-22 10:14:59 +08:00
Cinte 27e97214bd 仅仅是检查图片hash就将图片下载到磁盘是否有些浪费io,于是改成了内存中直接计算 2022-08-22 09:49:33 +08:00
LambdaYH 6321a9e7e0 使用gino提供的方法,避免构建sql字符串时出现非法查询语句 2022-08-22 00:49:30 +08:00
xiayingLIULI a9eadca46c 对米游社cookie进行判断,整合米游社签到信息 2022-08-22 00:42:00 +08:00
xiayingLIULI 76bef8a725 对米游社cookie进行判断,整合米游社签到信息 2022-08-22 00:40:51 +08:00
LambdaYH 308b76dc7d _rule中使用messagesegment中未转义的字符串,而添加词条时使用了转义后的字符串,导致二者不一致 2022-08-22 00:38:25 +08:00
LambdaYH 31d4d29f3e 修复匹配时候忽视了word_type的约束 2022-08-21 23:47:21 +08:00
LambdaYH 016a7e87ea Merge branch 'HibiKier-main' into patch-4 2022-08-21 23:46:46 +08:00
LambdaYH 4ce88c7bfc merge 2022-08-21 23:46:38 +08:00
LambdaYH f570bffcf7 修复匹配时候忽视了word_type的约束 2022-08-21 23:42:46 +08:00
LambdaYH 3bb9aaf637 添加正则词条前先检查正则有效性 & 正则词条先进行转义,不然符号都乱了 2022-08-21 23:21:34 +08:00
LambdaYH cf7a64c934 fix: 问答为[at + 文本]的情况时无法正常添加 2022-08-21 22:24:06 +08:00
LambdaYH c466603193 Fix at messages with suffixed text 2022-08-21 21:58:31 +08:00
CRAZY bc53f329a9 修正尘歌壶和质变仪图片获取地址 2022-08-21 20:33:06 +08:00
CRAZY 4a5cc5153f 修正质变仪图片获取地址 2022-08-21 20:11:44 +08:00
HibiKier 8697670fe1 UPDATE README.md 2022-08-21 18:43:58 +08:00
HibiKier 64d8543af9 UPDATE __version__ 2022-08-21 18:42:16 +08:00
HibiKier 482cc242cb UPDATE README.md 2022-08-21 18:41:13 +08:00
HibiKier 2051e8183c 词条模糊匹配使用contains方法 2022-08-21 18:32:24 +08:00
HibiKier d183903917 update README.md 2022-08-21 18:15:18 +08:00
HibiKier 5c695899a1 将配置替换加入单次定时任务,提高启动速度 2022-08-21 18:09:31 +08:00
HibiKier 708e912069 Merge pull request #1008 from LambdaYH/patch-4
fix: WordBank.check()
2022-08-21 16:57:22 +08:00
Cinte db1f4b2b52 fix: WordBank.check() 2022-08-21 16:54:28 +08:00
HibiKier 1508782f49 提供全局字典GDict,适配omega 13w张图的数据结构表 2022-08-21 16:47:50 +08:00
HibiKier 445b830683 开箱提供重置开箱命令 2022-08-21 14:10:49 +08:00
HibiKier 1a17e88142 b站订阅直播订阅支持短号 2022-08-21 13:57:48 +08:00
HibiKier c0ec2e7856 b站订阅直播订阅支持短号 2022-08-21 13:57:17 +08:00
HibiKier 9e962bd0d1 修正词条加载路径 2022-08-21 13:44:06 +08:00
HibiKier 7efcff13bb backup 2022-08-21 13:37:03 +08:00
zyj2134 e70d0df949 Merge remote-tracking branch 'origin/main' 2022-08-19 23:49:16 +08:00
HibiKier fcaa469edd Merge pull request #996 from shinianj/patch-1
Update README.md
2022-08-16 08:46:10 +08:00
shinianj 51508182ef Update README.md 2022-08-16 00:38:14 +08:00
HibiKier 27e78c1626 update README.md 2022-08-14 22:11:36 +08:00
HibiKier 0b4d37a0b6 修复订阅主播时动态获取的id是直播间id 2022-08-14 21:31:57 +08:00
HibiKier ddbebba6f1 修复epic未获取时间时出错 2022-08-14 21:18:29 +08:00
zyj2134 7f296348e4 Merge remote-tracking branch 'origin/main' 2022-08-09 22:20:32 +08:00
HibiKier ca78e32d97 Update README.md 2022-08-08 04:23:05 +08:00
HibiKier 4efc561f4d Merge pull request #969 from DDS-DS/main
修复赛马娘重载卡池失败的问题
2022-08-08 04:22:24 +08:00
HibiKier 40fed798a1 Update data_source.py 2022-08-07 01:10:19 +08:00
HibiKier 0876afc08c Update README.md 2022-08-06 20:40:10 +08:00
HibiKier ba4c4d06ff Merge pull request #971 from HDU-Nbsp/main
修复了原神自动签到返回invalid request的问题,新增查看我的cookie命令
2022-08-06 20:39:30 +08:00
HibiKier f64c30af48 Update __init__.py 2022-08-06 20:39:16 +08:00
HDU_Nbsp bb0cea2dd3 修复了原神自动签到返回invalid request的问题,新增查看我的cookie命令 2022-08-05 22:32:15 +08:00
dingshan 3c120ce602 增加备注说明 2022-08-05 15:49:21 +08:00
dingshan 6151dfb161 修复赛马娘重载卡池失败的问题 2022-08-05 15:42:53 +08:00
dingshan f05d4ec931 修复赛马娘重载卡池失败的问题 2022-08-05 15:35:45 +08:00
HibiKier e16afc3fc2 update README.md 2022-08-03 20:26:41 +08:00
HibiKier 1b8753fead Merge pull request #961 from Gaomengkai/main
修复 bili动态链接在投稿视频时URL和分割线连在一起
2022-08-03 20:20:29 +08:00
HibiKier ba960d1ced Merge pull request #957 from monsterxcn/patch-1
更新 Epic 免费游戏商城链接拼接规则
2022-08-03 20:14:13 +08:00
Merky Gao 41b60b6152 修复 bili动态链接在投稿视频时URL和分割线连在一起
比如up发布一条动态后,qq显示的链接事[https://t.bilibili.com/123456789012345678-------------],会把后面的分隔符算在链接里边,导致直接点开后404(*^_^*). だから……お願い!
2022-08-01 11:11:34 +08:00
github-actions[bot] 70ddce713c Auto generate poetry.lock 2022-08-01 00:23:45 +00:00
HibiKier e15622748b Update pyproject.toml 2022-08-01 08:21:30 +08:00
HibiKier 96687021ff Merge pull request #958 from yajiwa/main
Update poetry.lock
2022-08-01 08:21:12 +08:00
yajiwa 3c0a7ef510 Update poetry.lock 2022-07-31 22:22:54 +08:00
HibiKier 4d84c9fb3f 修复metadata中version判断 2022-07-31 18:00:44 +08:00
HibiKier aa35a16610 修复pix无图时不会提醒而是出错 2022-07-31 17:48:54 +08:00
HibiKier a380fcb680 修复webui元祖类型无法正确转换类型 2022-07-31 17:45:14 +08:00
Monst.x e544afe475 更新 Epic 免费游戏商城链接拼接规则 2022-07-31 17:41:10 +08:00
HibiKier c089388323 适配metadata 2022-07-31 17:30:29 +08:00
HibiKier e97a043031 Merge pull request #953 from tanzhi77/main
发言记录统计添加日消息统计
2022-07-30 10:55:50 +08:00
HibiKier d1b6dfe577 Merge pull request #951 from yajiwa/main
替换了cos和bt的url
2022-07-30 10:53:49 +08:00
HibiKier 9189fd411e Update __init__.py 2022-07-29 19:50:21 +08:00
弹指 432eba80a9 发言记录统计添加日消息统计 2022-07-29 19:08:16 +08:00
yajiwa db39612c54 update bt 2022-07-28 16:49:28 +08:00
yajiwa 5794c82a2d update coser 2022-07-28 16:48:45 +08:00
yajiwa acf875a886 Merge branch 'HibiKier:main' into main 2022-07-28 14:42:47 +08:00
HibiKier 79185bd90f Update README.md 2022-07-26 18:31:30 +08:00
HibiKier d695c30988 Update __version__ 2022-07-26 18:30:09 +08:00
zyj2134 a1308fbdc9 Merge remote-tracking branch 'origin/main' 2022-07-24 22:16:51 +08:00
yajiwa e4f2b761d6 Merge branch 'HibiKier:main' into main 2022-07-24 18:51:09 +08:00
HibiKier 6ff6009a70 b站订阅up动态提供直链 2022-07-24 02:54:51 +08:00
HibiKier dadeb4006e Update __init__.py 2022-07-24 01:19:47 +08:00
yajiwa ee0ff762e5 Merge branch 'HibiKier:main' into main 2022-07-23 18:02:24 +08:00
HibiKier 1f01ba1d10 优化开箱次数判断 2022-07-23 14:09:17 +08:00
HibiKier 62965fe1df Merge pull request #928 from Sakuracio/main
update: README.md
2022-07-19 08:36:37 +08:00
MangataAkihi e29eb4cce5 Update README.md 2022-07-18 19:05:44 +08:00
MangataAkihi 699791e318 Update README.md 2022-07-18 19:03:32 +08:00
zyj2134 946fbbec3c Merge remote-tracking branch 'origin/main' 2022-07-17 15:34:18 +08:00
HibiKier d2aae0103d fix b23.tv bug 2022-07-16 05:48:00 +08:00
HibiKier ab06e38b7c update coser 2022-07-16 05:31:56 +08:00
zyj2134 bd531c85b1 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	README.md
2022-07-14 20:44:12 +08:00
HibiKier 8a0ca3c2e5 update README.md 2022-07-13 22:55:54 +08:00
HibiKier 97317ed2c6 update bilibili_sub 2022-07-13 22:54:13 +08:00
HibiKier cda9aae8a3 Update README.md 2022-07-07 22:02:33 +08:00
HibiKier a33e785043 Merge pull request #891 from yajiwa/main
更新微博热搜
2022-07-07 22:01:53 +08:00
yajiwa 833e266a1f update wbtop 2022-07-06 04:59:54 +08:00
HibiKier 1bb9b2cb3f fix setu 2022-07-04 20:21:35 +08:00
HibiKier 7ba129b3bf update README.md 2022-07-04 20:03:38 +08:00
HibiKier 1e2c9ca28a Merge pull request #886 from yajiwa/main
修复B站订阅UP动态
2022-07-04 19:34:33 +08:00
yajiwa c6f37fd05f update bilibili_sub 2022-07-04 15:45:15 +08:00
HibiKier b6b569fff9 Update goods_info.py 2022-07-04 13:13:06 +08:00
HibiKier ac57c016a6 Update goods_info.py 2022-07-04 13:09:16 +08:00
HibiKier 28fdd9de95 Update __version__ 2022-07-04 12:29:33 +08:00
HibiKier 1ec946aaa9 Update README.md 2022-07-04 08:40:44 +08:00
HibiKier d6110e3c6f update bilibili_sub 2022-07-03 22:00:49 +08:00
HibiKier 4c5302bd4c fix shop update goods 2022-07-03 16:47:19 +08:00
HibiKier 21ee3d5c3e update send_setu 2022-07-03 16:33:14 +08:00
HibiKier e5c036cee8 update shop image 2022-07-03 13:55:26 +08:00
HibiKier 6f82488af7 Merge pull request #879 from VirtualTowel/main
修复图库内图片无法被连续删除的问题
2022-07-03 13:53:49 +08:00
VirtualTowel 57a7903c63 修复图库内图片无法被连续删除的问题 2022-07-01 20:12:39 +08:00
HibiKier 27b89b333a Merge pull request #866 from Excalibur5100/main
修复色图插件api修改无法搜索图片
2022-06-28 20:48:33 +08:00
Excalibur5100 ce2c4e7492 修复色图插件最近加tag参数后搜不到图的问题
插件所用API更新,最大数量num改为20
https://api.lolicon.app/#/setu
2022-06-28 19:48:59 +08:00
HibiKier cad98a2a33 Update goods_info.py 2022-06-26 22:23:19 +08:00
HibiKier 40da48e685 update models 2022-06-26 19:29:51 +08:00
HibiKier 1c393e5c3e update shop daily_limit 2022-06-26 03:08:23 +08:00
HibiKier 667c143c74 update pix 2022-06-26 01:37:47 +08:00
HibiKier bc089c18ce update bt 2022-06-26 01:26:14 +08:00
HibiKier 24b730c0e2 Merge pull request #847 from po-lan/main
对WSL虚拟机 代理 添加写法
2022-06-24 20:59:28 +08:00
po-lan 9ed9e9b973 对WSL虚拟机 代理 添加写法 2022-06-23 17:57:47 +08:00
HibiKier 5b0027aa3d Update README.md 2022-06-22 22:49:26 +08:00
HibiKier 810c5e4e8b Update README.md 2022-06-21 21:59:41 +08:00
HibiKier 907534958f Merge pull request #840 from yajiwa/main
update parse_bilibili
2022-06-21 21:59:23 +08:00
HibiKier f08a18ab07 Update data_class.py 2022-06-21 21:01:14 +08:00
github-actions[bot] 40549d5ca7 Auto generate poetry.lock 2022-06-21 00:56:57 +00:00
yajiwa 3e67edc506 update pyproject.toml 2022-06-21 08:53:49 +08:00
yajiwa 9c56a81f65 update parse_bilibili 2022-06-21 08:50:05 +08:00
HibiKier a9a636c9ae Update plugins2settings_manager.py 2022-06-20 22:31:57 +08:00
HibiKier 98374dcd74 Update README.md 2022-06-20 22:07:48 +08:00
HibiKier 10ca6eec91 update webui 2022-06-20 21:54:10 +08:00
HibiKier 216d32cf21 Update README.md 2022-06-19 23:16:11 +08:00
HibiKier 248fae4fe6 Update __version__ 2022-06-19 23:15:40 +08:00
HibiKier b479b6839d Update README.md 2022-06-19 22:29:44 +08:00
HibiKier 1a4e1e9515 Merge pull request #835 from yajiwa/main
词条优化问题展示,修改含机器人昵称和@逻辑
2022-06-19 22:29:20 +08:00
yajiwa e5160a4ee8 Merge branch 'HibiKier:main' into main 2022-06-19 17:26:13 +08:00
yajiwa 56ea3964a7 update word_bank 2022-06-19 17:24:50 +08:00
HibiKier ad73778286 update README.md 2022-06-19 16:55:02 +08:00
HibiKier 3e548f48c8 Merge pull request #828 from McElaga/main
修复原神树脂重复提醒的bug
2022-06-19 16:54:25 +08:00
HibiKier ae466931fa fix webui 2022-06-19 16:44:37 +08:00
HibiKier 68052b526f update image_utils 2022-06-18 15:23:36 +08:00
HibiKier 903b5b88a7 update image_utils 2022-06-18 15:09:55 +08:00
HibiKier 007823d6b2 update README.md 2022-06-18 15:03:05 +08:00
HibiKier db5c4fb349 Merge pull request #830 from po-lan/main
我不太会提交单个文件,我就把俄罗斯轮盘的文件 改回去了,再提交的
2022-06-18 15:00:46 +08:00
HibiKier c37901290a fix nickname 2022-06-18 14:57:54 +08:00
HibiKier da67f1f6f8 update webui 2022-06-18 14:48:46 +08:00
HibiKier 5172fa69e5 fix web ui 2022-06-18 14:31:44 +08:00
po-lan dd7280cd0d 恢复 原先的文件 2022-06-18 14:08:59 +08:00
McElaga 0d0f522c88 Merge branch 'HibiKier:main' into main 2022-06-18 09:27:12 +08:00
McElaga 5429e6ed5c Merge branch 'main' of https://github.com/McElaga/zhenxun_bot 2022-06-18 09:15:24 +08:00
McElaga 9db69fa05b 修复一点逻辑小问题 2022-06-18 09:15:19 +08:00
HibiKier 3b8d52bcb5 Update README.md 2022-06-17 18:50:37 +08:00
HibiKier 807f39a336 Update README.md 2022-06-17 18:50:15 +08:00
HibiKier fea2f30461 Merge pull request #820 from LambdaYH/patch-2
修复wordbank的一些小问题
2022-06-17 18:49:42 +08:00
po-lan 5d97e3f95f Update __init__.py 2022-06-16 16:15:39 +08:00
po-lan 63e6ca3e99 Update __init__.py 2022-06-16 15:40:46 +08:00
po-lan b11590ec3c ban掉被击毙的人一段时间 2022-06-16 15:38:20 +08:00
po-lan 3a43ed6919 如果需要 保存到 config 可以少调用一次 2022-06-16 14:38:41 +08:00
po-lan 15ce9c91fb Update __init__.py 2022-06-16 14:25:22 +08:00
LambdaYH 0e8d7537d4 fix wordbank 2022-06-16 00:43:32 +08:00
Cinte 1fca0787be fix: 修复之前更改正则引入的问题 2022-06-15 23:16:39 +08:00
HibiKier af30285c00 Update browser.py 2022-06-15 10:08:43 +08:00
HibiKier a84cab7afd replace bt url 2022-06-14 20:40:11 +08:00
HibiKier 593573ddfb fix pix 2022-06-14 19:48:32 +08:00
HibiKier e9e9f81bdb Merge pull request #806 from LambdaYH/patch-2
fix: 修复添加词条时对answer中图片的处理
2022-06-14 19:31:53 +08:00
HibiKier 61f624841b Merge pull request #810 from LambdaYH/patch-3
fix: 自动更新群组
2022-06-14 19:31:18 +08:00
HibiKier 4bb38a2730 Merge pull request #812 from po-lan/main
可关闭 ssl 验证
2022-06-14 19:22:25 +08:00
HibiKier d4ec0df00c Update http_utils.py 2022-06-14 19:22:12 +08:00
po-lan c8a7d855f8 Update http_utils.py 2022-06-14 18:47:43 +08:00
Cinte 73a126dcd5 fix: 自动更新群组 2022-06-14 09:18:03 +08:00
HibiKier 0736533389 fix search_image 2022-06-13 22:16:45 +08:00
Cinte 2695d658ab fix: 修复添加词条时对answer中图片的处理 2022-06-13 22:11:18 +08:00
HibiKier 947166e793 Merge pull request #804 from po-lan/main
Windows 重启适配
2022-06-13 20:20:30 +08:00
po-lan 80c49a7cf5 Update __init__.py 2022-06-13 15:34:28 +08:00
po-lan 55bfa8f669 Update __init__.py
Windows 重启适配
2022-06-13 15:24:28 +08:00
HibiKier 74ade14f5e Update README.md 2022-06-13 11:07:34 +08:00
HibiKier c9b5218ebc Merge pull request #798 from CopilotLaLaLa/main
webui中token.json文件写入补充
2022-06-13 11:07:11 +08:00
HibiKier b324b2bd65 Merge pull request #800 from yajiwa/main
update setu_img
2022-06-13 11:06:20 +08:00
HibiKier 35c038efa2 Update utils.py 2022-06-13 11:05:16 +08:00
HibiKier caa404d58d Update utils.py 2022-06-13 11:03:21 +08:00
yajiwa 830103b9d5 update change_img_md5 2022-06-13 10:59:29 +08:00
yajiwa 6e18379597 update setu_img 2022-06-13 10:08:51 +08:00
yajiwa 6effbacb28 add change_img_md5 2022-06-13 10:08:09 +08:00
CopilotLaLaLa a20a1a0234 同步原仓库 2022-06-12 15:23:10 +00:00
CopilotLaLaLa 3667724061 token_json文件写入 2022-06-12 15:16:07 +00:00
HibiKier 785179e4a7 update pix 2022-06-11 17:57:19 +08:00
HibiKier 715338f821 Merge pull request #791 from mmmjie/main
两处BUG的修复
2022-06-10 21:31:51 +08:00
mmmjie 7d5a82ab6d Update update_picture.py
对于temp/temp的错误路径,减少了一个temp
TEMP_PATH 已经指向了一个temp了
2022-06-10 00:37:18 +08:00
mmmjie e764cfcc1c Update white2black_image.py
随着7b836ac 对utils/image_utils.py 的改动
调整此插件对于 utils/image_utils.py改动的引用部分
2022-06-10 00:35:57 +08:00
HibiKier 363acf37bc fix bug and update 2022-06-09 20:39:48 +08:00
HibiKier 5fd687c1e4 Merge pull request #778 from SinKy-Yan/main
fix auto update bug
2022-06-09 19:37:26 +08:00
HibiKier dbedcbb93d Update pyproject.toml 2022-06-08 11:51:32 +08:00
HibiKier 9e9611f11f Update README.md 2022-06-08 11:43:10 +08:00
HibiKier 44002838da Merge pull request #779 from MingxuanGame/main
chore(deps): update `nonebot-adapter-onebot`
2022-06-08 11:42:43 +08:00
MingxuanGame 4daab8459f chore(deps): update nonebot-adapter-onebot 2022-06-07 11:57:34 +00:00
HibiKier 5a002f75cc Merge pull request #777 from LambdaYH/patch-1
fix image_utils.py
2022-06-07 19:27:31 +08:00
源源球球✨ a2180a1365 fix auto update bug 2022-06-07 10:19:23 +00:00
Cinte 7b836acf36 fix image_utils.py
https://github.com/HibiKier/zhenxun_bot/commit/ae8a214a3a5c08a51cacd1dc37583c0b32e6332f
之前这个commit里面看到函数参数有写着int类型就把`font_size`类型转换给去了,结果导致了部分地方输入float类型后报错。现在改回来
2022-06-07 17:06:16 +08:00
HibiKier a112a561cc Update README.md 2022-06-05 20:30:49 +08:00
HibiKier 6dcc2a69f4 Update README.md 2022-06-05 19:56:42 +08:00
HibiKier 74e9c55a09 update v0.1.5.8 2022-06-05 19:51:23 +08:00
HibiKier d4d6e736a4 Merge pull request #764 from McElaga/main
金币红包功能增加更多封面
2022-06-05 19:08:51 +08:00
HibiKier 5cf9938fa2 Merge pull request #763 from RShock/main
fix gold_redbag
2022-06-05 19:04:40 +08:00
McElaga 72ad0ad983 commit on main 2022-06-04 12:34:18 +08:00
咕咕型小r 690750d91e fix gold_redbag 2022-06-04 12:09:05 +08:00
HibiKier 9f1dfc4b9c Merge pull request #756 from McElaga/main
修复原神树脂提醒bug(已实测)
2022-06-03 16:15:50 +08:00
HibiKier 05eab5307f Update README.md 2022-06-03 16:13:29 +08:00
HibiKier b0fe70c960 Merge pull request #745 from LambdaYH/main
稍微调整了一下查看所有请求中的年龄绘制
2022-06-03 16:07:01 +08:00
McElaga 09d7992bc4 comit on main 2022-06-03 12:09:15 +08:00
McElaga c832a432c1 commit on main 2022-06-03 11:52:40 +08:00
HibiKier 41c22f4314 fix ShopRegister 2022-06-03 01:14:34 +08:00
HibiKier 252d45c79b fix webui update plugin_shop 2022-06-03 00:59:00 +08:00
Cinte ae8a214a3a Update image_utils.py 2022-06-02 10:06:55 +08:00
LambdaYH 86ce6d7664 fix: 稍微调整了一下查看所有请求中的年龄绘制 2022-06-02 10:02:03 +08:00
McElaga 67e96d6106 commit on main 2022-06-02 08:55:24 +08:00
HibiKier 24d9ec2b75 Update __init__.py 2022-06-01 11:05:12 +08:00
HibiKier 501e47c6ec fix image2text 2022-05-31 20:45:28 +08:00
HibiKier 5534a5a5c2 Merge pull request #707 from HiDolen/main
修复抽卡插件:方舟更新UP池信息时,若公告的第一个池子过期会导致无法更新UP池信息
2022-05-31 20:14:48 +08:00
HibiKier 7246aabf40 Merge pull request #712 from McElaga/main
修复发红包图片背景未透明化;修复原神树脂提醒参数错误
2022-05-31 20:07:35 +08:00
HibiKier 604ffae87e Merge pull request #711 from LambdaYH/patch-1
bot_friend_group将group_handle.修改为friend_handle.
2022-05-31 20:06:12 +08:00
HibiKier 2d5c16456b Merge pull request #721 from LambdaYH/patch-2
修复开启/关闭全部功能时帮助图片未重绘
2022-05-31 20:01:39 +08:00
Cinte d44f7633dc 修复开启/关闭全部功能时帮助图片未重绘 2022-05-30 20:43:48 +08:00
Cinte 469ac4035c 大概是把group_handle写成了friend_handle 2022-05-30 11:27:14 +08:00
McElaga dab218a6d7 commit on main 2022-05-30 11:14:47 +08:00
Dolen d6fc675d57 修复抽卡插件:避免被跳过的卡池信息污染后面的卡池信息 2022-05-30 11:11:49 +08:00
McElaga 04148f7365 commit on main 2022-05-30 11:00:19 +08:00
Dolen 4c34ac570f 修复抽卡插件:方舟更新UP池信息时,若公告的第一个池子过期会导致无法更新UP池信息 2022-05-29 23:13:36 +08:00
HibiKier fbdb8758a3 Update README.md 2022-05-29 22:21:26 +08:00
HibiKier 2d08747d70 Merge pull request #705 from yajiwa/main
商店插件判断是否有requirements.txt文件
2022-05-29 22:21:03 +08:00
yajiwa 0b4bacbbd1 update plugin_shop 2022-05-29 21:57:01 +08:00
yajiwa e0412c7edb Merge branch 'HibiKier:main' into main 2022-05-29 21:03:12 +08:00
HibiKier 38501cebf1 Update data_source.py 2022-05-29 20:56:03 +08:00
HibiKier ee45d0217e Update __init__.py 2022-05-29 20:55:32 +08:00
HibiKier 558f362919 update v0.1.5.8 2022-05-29 20:47:18 +08:00
HibiKier fb9db2f50c fix 2022-05-29 19:57:57 +08:00
HibiKier c1862e9c68 fix bt 2022-05-29 19:15:29 +08:00
HibiKier 731bde8e28 update v0.1.5.7 2022-05-29 19:14:36 +08:00
HibiKier 47c87f8694 update db_context 2022-05-28 22:50:23 +08:00
HibiKier 5558cdacc3 Update README.md 2022-05-28 21:09:58 +08:00
HibiKier 4650d244a5 Merge pull request #688 from McElaga/main
修复微博热搜报错,发红包小bug
2022-05-28 21:08:17 +08:00
HibiKier c65b8aae07 update webui 2022-05-28 20:57:08 +08:00
HibiKier 7ba2fb9584 update black_word 2022-05-28 20:55:14 +08:00
HibiKier 9a2cfd0c9b zhenxun_update add config 2022-05-28 18:28:38 +08:00
HibiKier a7d61b1f2b add config 2022-05-28 18:12:08 +08:00
HibiKier 7ab185f7d7 fix poke 2022-05-28 17:48:28 +08:00
HibiKier 724541d691 fix bug 2022-05-28 17:22:51 +08:00
McElaga baa6cda9c2 commit on main 2022-05-28 10:31:27 +08:00
HibiKier 9c987e9aad log2cn 2022-05-26 22:49:48 +08:00
HibiKier 134974ea9c Merge pull request #667 from NumberSir/main
更新抽卡插件
2022-05-26 22:43:11 +08:00
HibiKier 2d946958e3 Merge pull request #668 from HanakoLuna/patch-1
更新BT搜索源地址
2022-05-26 22:42:37 +08:00
Lya_Yami ffe010e9ce 更新BT搜索源地址 2022-05-26 20:47:12 +08:00
HibiKier 1c67252b0c Update README.md 2022-05-26 20:26:14 +08:00
HibiKier 60c1be25d4 Merge pull request #643 from LambdaYH/patch-1
修复[滴滴滴]会被转义成[滴滴滴]导致无法触发的问题
2022-05-26 20:25:45 +08:00
Number_Sir 18323a0916 更新抽卡插件
修复了方舟抽卡图文不符的问题
修复了方舟许多三星抽不出来的问题
修复了方舟重载卡池失败的问题
2022-05-26 20:07:09 +08:00
HibiKier 9d98abded9 Merge pull request #660 from Sakuracio/main
Replace URL
2022-05-26 19:49:23 +08:00
MangataAkihi b06a742b8c Update README.md 2022-05-26 17:20:37 +08:00
github-actions[bot] 87fe44f188 Auto generate poetry.lock 2022-05-26 09:18:16 +00:00
Cinte 96f6ef1693 修复[滴滴滴]会被转义成[滴滴滴]导致无法触发的问题 2022-05-26 09:59:45 +08:00
github-actions[bot] 374b7b7261 Auto generate poetry.lock 2022-05-25 23:42:48 +00:00
HibiKier 23c4141e55 Update README.md 2022-05-25 20:53:09 +08:00
HibiKier c21200c2a9 Merge pull request #610 from yajiwa/main
修复碧蓝航线/明日方舟up池解析出错的问题
2022-05-25 20:52:58 +08:00
HibiKier 4a8b94259d Merge pull request #602 from HiDolen/main-patch
修改翻译插件,添加缺失的冒号
2022-05-25 20:49:51 +08:00
HibiKier 28a58df27b Merge pull request #607 from MingxuanGame/main
feat: stream downloading and progress
2022-05-25 20:49:20 +08:00
HibiKier caaf486bbe Merge branch 'main' into main 2022-05-25 20:49:07 +08:00
HibiKier 0a972a399e Merge pull request #617 from mouhensama/main
把gamedraw的ba卡池搬运了过来并且进行了真寻的适配。
2022-05-25 20:44:07 +08:00
HibiKier 245dad1239 Merge pull request #624 from HiDolen/main-patch2
修改nickname插件:一处文案错误,添加敏感词
2022-05-25 20:42:51 +08:00
Dolen a6b6a2fbff 修改nickname插件:一处文案错误 2022-05-25 17:21:00 +08:00
Dolen 53000a949b 修改nickname插件:添加一个敏感词 2022-05-25 17:03:44 +08:00
Dolen eae1dd59a7 修改nickname插件:一处文案错误 2022-05-25 17:02:09 +08:00
HibiKier e6347a76a8 Update issue-template.md 2022-05-25 14:44:28 +08:00
HibiKier 13e0fb3df7 Delete bug-issue-template.md 2022-05-25 13:42:22 +08:00
HibiKier 3f1b23ef8a Update issue templates 2022-05-25 13:41:35 +08:00
HibiKier acae7f0658 Create ISSUE_TEMPLATE.md 2022-05-25 13:37:29 +08:00
HibiKier a9456b1bd6 Merge pull request #608 from AkashiCoin/main
Use Action to automatically generate poetry.lock
2022-05-25 13:35:39 +08:00
mouhensama e4d5a230d2 把nonebot_plugin_gamedraw的ba卡池搬运了过来并且进行了真寻的适配。 2022-05-25 11:47:08 +08:00
HibiKier fedf44b9fa Update README.md 2022-05-25 10:54:52 +08:00
HibiKier 451db104e8 Update config.py 2022-05-25 08:52:22 +08:00
HibiKier 9ac4c7f4e3 Update README.md 2022-05-25 08:52:15 +08:00
HibiKier 7cf1c6f016 Update README.md 2022-05-25 08:41:59 +08:00
yajiwa 6dd87ee301 fix draw_card 2022-05-25 07:02:42 +08:00
MingxuanGame 96837fa8db fix: rich from dev dependent to main dependent 2022-05-25 01:19:12 +08:00
MingxuanGame d816e76962 fix: rich from dev dependent to main dependent 2022-05-25 01:13:27 +08:00
AkashiCoin 310945d9cd Merge branch 'HibiKier:main' into main 2022-05-25 01:01:11 +08:00
MingxuanGame 1aba480495 feat: stream downloading and progress 2022-05-25 00:56:41 +08:00
HibiKier 07407749fe Update README.md 2022-05-24 22:05:38 +08:00
HibiKier dfab70dd90 Merge pull request #581 from HiDolen/main
修复抽卡插件:方舟抽卡的抽取和显示问题
2022-05-24 22:05:13 +08:00
Dolen 3b15469c98 修改翻译插件,发送消息添加冒号 2022-05-24 08:59:14 -05:00
HibiKier e4590800c2 Update README.md 2022-05-24 21:20:59 +08:00
HibiKier c63d4b8ad0 Merge pull request #573 from jk6589jk/patch-2
修复复读不能复读图片的问题
2022-05-24 21:19:41 +08:00
HibiKier 1fb913e2ed Merge pull request #576 from MingxuanGame/main
refactor&fix(manager): modify argument
2022-05-24 21:18:22 +08:00
HibiKier 72ace2dab7 Merge pull request #579 from yajiwa/main
更新"微博热搜"接口
2022-05-24 21:14:51 +08:00
HibiKier 3bcef18629 Merge pull request #600 from sdy623/main
bugfix: 修正了签到时日期时间的显示不补齐零的bug (符合日期时间表示法 ISO 8601)
2022-05-24 21:13:33 +08:00
sdy623 c91758519c bugfix: 修正了签到时日期时间的显示不补齐零的bug (符合日期时间表示法 ISO 8601) 2022-05-24 20:19:32 +08:00
jk6589jk 9c8f2e7aa0 Update fudu.py 2022-05-24 14:01:08 +08:00
Dolen 5f377af6d5 修复抽卡插件:方舟抽卡的抽取和显示问题 2022-05-24 09:13:10 +08:00
yajiwa 570b5b1766 update wbtop 2022-05-24 06:01:23 +08:00
MingxuanGame c4d53d58eb refactor&fix(manager): modify argument 2022-05-24 01:27:55 +08:00
jk6589jk ed65033cf1 修复复读不能复读图片的问题
IMAGE_PATH = Path() / "resources" / "image"
TEMP_PATH = Path() / "resources" / "temp"
image()默认读取在 resource/img 目录下,读写路径不同,导致找不到图片

打断打断施法!,rst.endswith("打断施法!")在复读内容含有图片时会报错
2022-05-23 22:06:53 +08:00
HibiKier 41836bde26 Update README.md 2022-05-23 22:05:19 +08:00
HibiKier 8381858742 Update README.md 2022-05-23 22:02:49 +08:00
HibiKier 1040bd0d58 update v0.1.5.6 2022-05-23 22:01:56 +08:00
HibiKier 404e47332e Merge pull request #441 from with9/main
添加pixiv搜图多关键词支持;修复p站搜图数量参数问题
2022-05-23 21:52:33 +08:00
HibiKier 3db128785e Update __init__.py 2022-05-23 21:52:08 +08:00
HibiKier 2189ea11df Update README.md 2022-05-23 19:46:30 +08:00
HibiKier 49b9bd65b0 Merge pull request #552 from jk6589jk/patch-1
修复有置顶的up主B站动态获取失败
2022-05-23 19:45:59 +08:00
jk6589jk b3fdb1ff58 修复B站动态获取失败
bili-dyn-item__tag的父项的父项才是完整的一条置顶动态
2022-05-23 12:59:53 +08:00
HibiKier c79e3fdcf0 Update README.md 2022-05-23 07:52:27 +08:00
HibiKier d7509f7030 Merge pull request #545 from yajiwa/main
修复"清除已删除插件数据"
2022-05-23 07:51:54 +08:00
yajiwa 5c99b55502 fix none_plugin_count 2022-05-23 02:35:57 +08:00
yajiwa fd255f022b Merge branch 'HibiKier:main' into main 2022-05-23 02:27:00 +08:00
HibiKier 41642589ae Update __version__ 2022-05-22 20:56:03 +08:00
HibiKier 619fef3bff update README.md 2022-05-22 20:52:59 +08:00
HibiKier 38c0da0cf8 update v0.1.5.4 2022-05-22 20:51:35 +08:00
HibiKier b241a58e84 update check_update 2022-05-22 19:04:58 +08:00
HibiKier 35c9585b22 delete WindowsSelectorEventLoopPolicy 2022-05-22 19:03:22 +08:00
HibiKier d2fe95cc05 fix query_resource_points and sign_in 2022-05-22 18:08:06 +08:00
HibiKier 92e60ba141 fix epic 2022-05-22 15:22:57 +08:00
HibiKier 2356527791 update word_clouds 2022-05-22 12:51:53 +08:00
HibiKier cab0f7b522 update change_pixiv_image_links 2022-05-22 12:49:32 +08:00
github-actions[bot] 8d3f101a68 Auto generate poetry.lock 2022-05-21 18:38:05 +00:00
AkashiCoin c8ac2b6281 Update Generate.yml 2022-05-22 02:35:20 +08:00
AkashiCoin d7d8efd305 Merge branch 'HibiKier:main' into main 2022-05-22 02:04:34 +08:00
HibiKier a4bc04c958 Update pid_search.py 2022-05-22 01:46:52 +08:00
AkashiCoin 5fc208c95a Create Generate.yml 2022-05-22 00:29:54 +08:00
HibiKier 02743d5955 Merge pull request #384 from AkashiCoin/main
Update anime.json of Kyomotoi/AnimeThesaurus
2022-05-21 23:40:13 +08:00
HibiKier a7ffebea35 Merge pull request #503 from yajiwa/main
修复命令不唯一的问题
2022-05-21 23:39:39 +08:00
HibiKier c511ef50a2 update wbtop 2022-05-21 23:34:48 +08:00
HibiKier 82902e0cde update invite_manager 2022-05-21 22:40:05 +08:00
AkashiCoin 1de5ae09bc Merge branch 'HibiKier:main' into main 2022-05-21 20:46:04 +08:00
yajiwa 8b735f1cb5 fix word_clouds 2022-05-21 20:08:53 +08:00
HibiKier 33d1334174 fix what_anime 2022-05-21 19:33:39 +08:00
HibiKier 324b58c21b update README.md 2022-05-21 16:42:19 +08:00
HibiKier b7b1651709 fix what_anime 2022-05-21 16:39:06 +08:00
HibiKier b5a4a6a9ff fix mute and open_case 2022-05-21 15:58:58 +08:00
HibiKier fe2c82b03c fix mute and open_case 2022-05-21 15:58:29 +08:00
HibiKier 81e4bca9ef fix mute 2022-05-21 13:46:29 +08:00
HibiKier c0d055b825 add get_message_img_file 2022-05-21 13:20:58 +08:00
HibiKier 188ae38525 fix bug 2022-05-21 13:15:53 +08:00
HibiKier 86a8fe7096 Merge pull request #462 from yajiwa/main
Update poetry file
2022-05-21 11:47:50 +08:00
yajiwa 0bb2b45f5c Update poetry.lock 2022-05-21 00:23:41 +08:00
yajiwa a17d8731c8 Update pyproject.toml 2022-05-21 00:22:44 +08:00
with9 9cdd2326c8 添加pixiv搜图多关键词支持;修复p站搜图数量参数问题 2022-05-20 19:35:18 +08:00
AkashiCoin d75653631d Merge branch 'HibiKier:main' into main 2022-05-19 23:21:02 +08:00
AkashiCoin e234c8906e Update anime.json 2022-05-19 23:20:00 +08:00
HibiKier 57baea18b5 Merge pull request #348 from sihuan/fix-bilibili_sub
Fix wrong live streamer name, fixes #284
2022-05-19 22:11:59 +08:00
HibiKier 0f3efe29c4 Merge pull request #357 from MingxuanGame/main
fix: mihoyo bbs api changed
2022-05-19 22:04:36 +08:00
HibiKier 89b87a38b3 Merge pull request #342 from yajiwa/main
fix bug
2022-05-19 21:03:23 +08:00
MingxuanGame c52b7ca2e9 fix: mihoyo bbs api changed 2022-05-19 17:47:20 +08:00
SiHuan 371b55dc9e Fix wrong live streamer name, fixes #284 2022-05-19 16:03:33 +08:00
yajiwa 53e572353c fix bug 2022-05-19 15:14:20 +08:00
yajiwa 3ae71c74e9 x 2022-05-19 15:10:42 +08:00
HibiKier cb643c04f7 Merge pull request #265 from yajiwa/main
Add word_clouds
2022-05-19 09:27:54 +08:00
yajiwa faf9ee159b update wordclouds url 2022-05-18 23:10:12 +08:00
yajiwa ffb3b2d73e Add word_clouds 2022-05-18 20:31:14 +08:00
HibiKier ffcc327089 Merge pull request #252 from yajiwa/main
Add wordclouds file
2022-05-18 20:04:13 +08:00
yajiwa dfd5a6a86a Add wordclouds file 2022-05-18 18:45:48 +08:00
HibiKier d43f89b067 Update README.md 2022-05-17 19:52:33 +08:00
HibiKier f15c3ab6a2 Update README.md 2022-05-16 19:20:01 +08:00
HibiKier e27809298e Merge pull request #160 from yajiwa/yajiwa
update word_bank
2022-05-16 19:19:20 +08:00
HibiKier 4b3e28e14b fix shop setu 2022-05-15 21:10:35 +08:00
yajiwa 71ce9153ed no message 2022-05-14 15:54:10 +08:00
yajiwa 25d63966de update word_bank 2022-05-14 15:47:33 +08:00
yajiwa 98afbb54b6 add get imgfile 2022-05-14 15:41:44 +08:00
HibiKier 03a51ca5dd Update README.md 2022-05-14 14:48:11 +08:00
HibiKier 428481b2d5 Merge pull request #159 from noahzark/patch-2
修复B站动态生成失败的问题
2022-05-14 14:47:30 +08:00
Feliciano Long f87c60e6db 修复B站动态生成失败的问题
B站动态样式更改
1. card已变更为bili-dyn-list__item
2. 置顶消息变成了一个tag(此处存疑,暂未发现其他tag
2022-05-13 19:38:24 +08:00
HibiKier 6d824e38bc Update README.md 2022-05-11 22:45:20 +08:00
HibiKier f0fd5bfb9e Merge pull request #155 from AkashiCoin/main
fix: 更改p搜api,解决p搜无法使用的问题
2022-05-11 22:44:32 +08:00
HibiKier 33374df671 Update pyproject.toml 2022-05-10 22:25:43 +08:00
AkashiCoin c035b1b19c Update pid_search.py 2022-05-10 18:47:39 +08:00
HibiKier b3b09ed666 update v0.1.5.3 2022-05-09 21:42:24 +08:00
HibiKier 8029c00a02 Update README.md 2022-05-05 20:32:22 +08:00
HibiKier a2c0921013 Merge pull request #153 from NumberSir/main
修改bilibili_sub插件在windows平台下报错
2022-05-05 20:32:17 +08:00
Number_Sir 31cdabc229 修改bilibili_sub插件在windows平台下报错
改用bilireq库,同时补充部分bilireq暂无的方法如获取番剧、获取用户投稿视频
2022-05-04 17:02:56 +08:00
HibiKier 1059a0aae0 Update README.md 2022-05-03 15:40:19 +08:00
HibiKier e6576e7f40 Update README.md 2022-05-03 15:34:47 +08:00
HibiKier 5837144095 Update data_source.py 2022-05-03 15:31:34 +08:00
HibiKier d30a5c4207 Update data_source.py 2022-05-03 10:03:27 +08:00
HibiKier 7d169b0e5e Update README.md 2022-05-03 09:46:06 +08:00
HibiKier 1f54226673 update ShopRegister 2022-05-03 09:43:38 +08:00
HibiKier 901a90ff13 update v0.1.5.1 2022-05-03 02:03:06 +08:00
HibiKier 56573d1d34 update black_word 2022-05-01 15:53:52 +08:00
HibiKier b0ab78340a Update chat_message_handle.py 2022-04-26 15:16:26 +08:00
HibiKier 93539be492 update v0.1.5.0 2022-04-26 14:45:04 +08:00
HibiKier c551e21766 Update __version__ 2022-04-12 00:51:37 +08:00
HibiKier ed342af97d Update README.md 2022-04-12 00:51:25 +08:00
HibiKier 17b87a2cb1 Update README.md 2022-04-12 00:50:55 +08:00
HibiKier 69ca02834d Update __init__.py 2022-04-12 00:50:19 +08:00
HibiKier 6cb4099a2e Update README.md 2022-04-10 22:57:36 +08:00
HibiKier e75a4966b2 Update __init__.py 2022-04-10 22:57:05 +08:00
HibiKier d55cba49bd Update data_source.py 2022-04-10 22:31:07 +08:00
HibiKier 0215abac30 update v0.1.4.7 2022-04-10 22:19:50 +08:00
HibiKier 2dcac5f009 Update README.md 2022-04-09 18:09:22 +08:00
HibiKier 0d8c64f7d1 Merge pull request #144 from AkashiCoin/main
fix: 更新问题,戳一戳图片路径问题
2022-04-09 18:08:49 +08:00
AkashiCoin 55626645fb fix: 更新问题,戳一戳图片路径问题 2022-04-09 14:56:30 +08:00
HibiKier f7925fa259 update genshin.query_role 2022-04-08 01:09:29 +08:00
HibiKier c814ae08b1 Update README.md 2022-04-06 18:52:01 +08:00
HibiKier 24666368f7 Merge pull request #143 from yajiwa/main
update search_type
2022-04-06 18:50:59 +08:00
yajiwa a77e85b62d fix bug 2022-04-06 13:17:08 +08:00
yajiwa 6319c7fce1 fix 2022-04-05 22:38:43 +08:00
yajiwa a45b95d5d4 update search_type 2022-04-05 22:15:47 +08:00
HibiKier 188f6f0f99 Update README.md 2022-04-05 19:42:20 +08:00
HibiKier a72f126d8f fix web_ui api 2022-04-05 13:14:29 +08:00
HibiKier 33eb1b83a8 Update README.md 2022-04-04 23:52:24 +08:00
HibiKier 2d9ebe2e6d Merge pull request #141 from yajiwa/main
Update word_bank plus
2022-04-04 23:50:34 +08:00
yajiwa 262b098dec Merge branch 'HibiKier:main' into main 2022-04-04 22:04:27 +08:00
HibiKier 79d88065aa Update README.md 2022-04-04 20:56:02 +08:00
HibiKier 0f59895c3b update v0.1.4.5 2022-04-04 20:33:37 +08:00
yajiwa 610d588e34 Merge branch 'zhenxun_yajiwa' 2022-04-03 20:17:08 +08:00
yajiwa f99abb2f98 fix config 2022-04-03 20:11:00 +08:00
yajiwa b2b7560d05 Update word_bank_plus 2022-04-03 20:05:18 +08:00
yajiwa 07c16e5238 Merge pull request #1 from yajiwa/zhenxun_yajiwa
Update Modify the entry
2022-04-01 23:56:57 +08:00
yajiwa 1741ea7d26 Update Modify the entry 2022-04-01 23:54:40 +08:00
HibiKier b5ce4fab31 Merge pull request #135 from Sakuracio/main
fix GB18030 to UTF-8.
2022-03-28 00:04:32 +08:00
MangataAkihi 062e4c2062 fix GB18030 to UTF-8. 2022-03-26 23:43:21 +08:00
MangataAkihi 0adb66a8bf fix GB18030 to UTF-8. 2022-03-26 23:43:06 +08:00
HibiKier 2aad517112 fix statistics_handle 2022-03-21 18:43:06 +08:00
HibiKier 14d1512b1e update v0.1.4.4 2022-03-18 20:55:05 +08:00
HibiKier 3f533516af Update README.md 2022-03-07 20:46:48 +08:00
HibiKier f1354308fd Update set_admin_permissions.py 2022-03-07 20:46:13 +08:00
HibiKier c06248e46b Update README.md 2022-03-06 18:00:58 +08:00
HibiKier 9c8eaed938 Update pid_search.py 2022-03-06 18:00:35 +08:00
HibiKier 2081302e32 Update README.md 2022-03-06 17:04:34 +08:00
HibiKier 678fc19f2d Update __init__.py 2022-03-06 17:02:59 +08:00
HibiKier adc2757e8e Merge pull request #128 from Sakuracio/main
去除背景图上的(白点?
2022-03-03 21:18:43 +08:00
Sakuracio 82a1261371 去除背景图上的(白点? 2022-03-03 00:38:54 +08:00
HibiKier 067da9dc57 update 0.1.4.3 2022-03-03 00:18:59 +08:00
HibiKier 0eb9f9fc6f Update README.md 2022-03-01 21:02:36 +08:00
HibiKier aee1340714 Update README.md 2022-03-01 21:02:18 +08:00
HibiKier a72a9bd8cb Update __version__ 2022-03-01 21:01:52 +08:00
HibiKier 7250410653 Update __version__ 2022-03-01 20:59:52 +08:00
HibiKier 12f55800b0 x 2022-03-01 20:26:11 +08:00
HibiKier 53b375b4b2 Add files via upload 2022-02-27 18:26:39 +08:00
HibiKier fba27abe29 Update pyproject.toml 2022-02-27 17:56:56 +08:00
HibiKier 4caa3dec04 Update poetry.lock 2022-02-27 17:56:26 +08:00
HibiKier 516b0f5ccb Add files via upload 2022-02-27 17:34:19 +08:00
HibiKier b5098be08e Update __version__ 2022-02-27 17:32:40 +08:00
HibiKier 5b08a4650c Update README.md 2022-02-27 17:31:51 +08:00
HibiKier eb02157b94 Add files via upload 2022-02-27 17:30:26 +08:00
HibiKier 222e1719a4 Delete plugins/draw_card directory 2022-02-27 17:29:57 +08:00
HibiKier 3c8983e753 Update task_hook.py 2022-02-26 00:11:26 +08:00
HibiKier 1fe41dd823 Update __version__ 2022-02-25 23:21:03 +08:00
HibiKier e8df59203c Update README.md 2022-02-25 23:17:42 +08:00
HibiKier 0f6690606b Update README.md 2022-02-25 22:50:24 +08:00
HibiKier a0115309dd Merge pull request #124 from Nova-Noir/main
Fixed error in custom_welcome_msg and message_builder
2022-02-24 16:12:39 +08:00
HibiKier ca18d45786 Update message_builder.py 2022-02-24 16:12:25 +08:00
NovaNo1r 76df21036a Fixed error in custom_welcome_msg and message_builder 2022-02-23 21:45:53 -08:00
HibiKier c674d581b7 Update README.md 2022-02-23 13:52:10 +08:00
HibiKier fc53c3c487 Update _data_source.py 2022-02-23 13:51:19 +08:00
HibiKier 7a4e31df80 Update __init__.py 2022-02-23 13:49:57 +08:00
HibiKier f1d308d559 Update __init__.py 2022-02-23 13:49:21 +08:00
HibiKier b7914bac05 Update README.md 2022-02-21 19:05:42 +08:00
HibiKier 8c40d88cc4 Update .gitignore 2022-02-21 18:20:43 +08:00
HibiKier b4ed6dcb5d Delete server_ip.py 2022-02-21 18:18:30 +08:00
HibiKier 0d3bd8a89c fix bug 2022-02-21 15:59:17 +08:00
HibiKier 87f0189abd Update README.md 2022-02-20 11:39:00 +08:00
HibiKier 1c17ac1f9d Update __init__.py 2022-02-20 11:06:32 +08:00
HibiKier f038763041 fix bug 2022-02-20 11:06:04 +08:00
HibiKier eaf6d54757 Update README.md 2022-02-19 23:24:21 +08:00
HibiKier d7368c83bc Update query_resource.py 2022-02-19 20:12:51 +08:00
HibiKier 4011620da1 Update README.md 2022-02-19 20:06:53 +08:00
HibiKier 6e0b91531e Update __version__ 2022-02-19 20:05:36 +08:00
HibiKier b8ca1d68aa Update update_info.json 2022-02-19 20:04:19 +08:00
HibiKier 2b9cda40a0 Update query_resource.py 2022-02-19 20:03:40 +08:00
HibiKier d8983bdcbf Update README.md 2022-02-19 18:32:09 +08:00
HibiKier 14bce52f2f Update README.md 2022-02-19 18:31:41 +08:00
HibiKier a7b0f7da68 Update README.md 2022-02-19 18:29:40 +08:00
HibiKier 7dd68cf1ef fit nonebot.beta2 2022-02-19 18:20:19 +08:00
HibiKier ab443a21ec Merge pull request #122 from AkashiCoin/main
fix: 修复远古时期残留的epic推送问题
2022-02-19 15:54:59 +08:00
HibiKier ed7e8a8a4c Merge pull request #109 from SAGIRI-kawaii/main
优化BuildImage.circle()锯齿问题
2022-02-19 15:54:14 +08:00
HibiKier a1435e2fc4 Merge branch 'main' into main 2022-02-19 15:53:47 +08:00
AkashiCoin 44a80f89da fix: 修复远古时期残留的epic推送问题 2022-02-19 14:57:23 +08:00
HibiKier 164f6af30c Merge pull request #119 from evlic/fixEPIC
epic restful 替换
2022-02-18 16:22:16 +08:00
evlic 9093a79101 epic restful 替换 2022-02-16 13:31:24 +08:00
HibiKier 14cce89a18 Update README.md 2022-02-11 13:16:48 +08:00
HibiKier 4bce20a0a9 Update data_source.py 2022-02-11 13:16:10 +08:00
HibiKier f32d8b4eff Update __version__ 2022-02-10 11:58:22 +08:00
HibiKier 685f2b8c53 Update README.md 2022-02-10 11:57:41 +08:00
HibiKier 1e63ca2549 Update buy.py 2022-02-10 11:55:36 +08:00
HibiKier c1bc4eff2b Update README.md 2022-02-09 23:02:14 +08:00
HibiKier bc903d3813 Update __init__.py 2022-02-09 22:28:49 +08:00
HibiKier 80fc17b610 Update __version__ 2022-02-09 21:44:09 +08:00
HibiKier 0efb2bbc60 update v0.1 2022-02-09 20:05:49 +08:00
SAGIRI-kawaii 95ad533b87 优化BuildImage.circle()锯齿问题 2022-01-24 23:52:57 +08:00
HibiKier b6e3240df9 Update README.md 2022-01-16 19:22:03 +08:00
HibiKier 5ae41e1d38 Update __init__.py 2022-01-16 18:37:14 +08:00
HibiKier 8022ae1fb1 Update README.md 2022-01-16 15:20:48 +08:00
HibiKier 0163fc1d88 Update draw_image.py 2022-01-16 15:16:19 +08:00
HibiKier 5d9ab40e35 Update __version__ 2022-01-16 15:00:16 +08:00
HibiKier b1ca7930bb Update README.md 2022-01-16 14:54:31 +08:00
HibiKier 40111261ed Update README.md 2022-01-16 14:54:16 +08:00
HibiKier 4cb91b47e6 update v0.0.9.0 2022-01-16 14:52:50 +08:00
HibiKier 30b56583bd update v0.0.8.0 2022-01-05 22:32:59 +08:00
HibiKier 5e5168f804 fix genshin 2021-12-26 22:14:01 +08:00
HibiKier 4a8122829e Update README.md 2021-12-24 10:23:35 +08:00
HibiKier 52ba2cf89a Merge pull request #99 from yzyyz1387/fix_zx
支持国际疫情数据查询
2021-12-24 10:22:45 +08:00
HibiKier 58957cdf44 Update other_than.py 2021-12-24 10:20:57 +08:00
HibiKier 71f860a500 Update other_than.py 2021-12-24 10:10:48 +08:00
HibiKier 9b4cde819e Update __init__.py 2021-12-24 10:09:53 +08:00
yzyyz1387 99637de1de International information inquiry is supported 2021-12-24 04:08:07 +08:00
yzyyz1387 19dbd3f2b0 International information inquiry is supported 2021-12-24 04:06:56 +08:00
yzyyz1387 7567794f74 International information inquiry is supported 2021-12-24 04:05:44 +08:00
yzyyz1387 df0d15c1b3 International information inquiry is supported 2021-12-24 04:03:26 +08:00
HibiKier 9a84c02bb5 Merge pull request #97 from BalconyJH/patch-1
Update __version__
2021-12-22 12:07:53 +08:00
BalconyJH e623c4f30f Update __version__ 2021-12-21 22:52:45 +08:00
HibiKier 3fd7acffb2 Update README.md 2021-12-20 20:41:54 +08:00
HibiKier 71f8c16c26 Merge pull request #96 from noahzark/patch-1
只有当真的发布新动态/视频的时候才获取并推送
2021-12-20 20:40:42 +08:00
Feliciano Long b64699c4ab 只有当真的发布新动态/视频的时候才获取并推送
1. 当up删除动态的时候,老动态会变成新的,此时不应该重复推送老动态
2. 2021-12-20 b站服务器不稳定,动态列表刷新混乱,造成重复推送
2021-12-20 17:48:05 +08:00
HibiKier 786d62bb2f Update README.md 2021-12-16 20:52:55 +08:00
HibiKier ac48d3d542 Update README.md 2021-12-16 19:23:30 +08:00
HibiKier c4d9523ec2 Update set_admin_permissions.py 2021-12-16 19:22:46 +08:00
HibiKier cb6549c297 Update prts_handle.py 2021-12-16 11:31:15 +08:00
HibiKier 29816ada2a Update README.md 2021-12-16 11:29:12 +08:00
HibiKier dd12bdc028 Update README.md 2021-12-16 11:17:27 +08:00
HibiKier 2a52c0711b Update README.md 2021-12-16 11:17:04 +08:00
HibiKier 2653f67193 update 0.0.7.0 2021-12-16 11:16:28 +08:00
HibiKier b892617824 Update group_user_checkin.py 2021-12-07 12:20:14 +08:00
HibiKier a6fb05c91d Update README.md 2021-12-01 16:25:44 +08:00
HibiKier ccfb9403c8 Update update_info.json 2021-12-01 16:21:58 +08:00
HibiKier 66fa194c7f Update data_source.py 2021-12-01 16:21:29 +08:00
HibiKier 65d8fae9ca Update http_utils.py 2021-12-01 15:20:32 +08:00
HibiKier 58acb14859 Update requirements.txt 2021-12-01 14:53:45 +08:00
HibiKier b63c05a509 Update requirements.txt 2021-12-01 14:17:11 +08:00
HibiKi 2a1a2ee8c5 update 0.0.6.5 2021-12-01 14:03:34 +08:00
HibiKier 8c4b515093 Update update_info.json 2021-12-01 10:53:15 +08:00
HibiKier 6d43989a4d Update update_info.json 2021-12-01 10:52:28 +08:00
HibiKier fb1f15bcb4 Update update_game_simple_info.py 2021-11-29 21:30:06 +08:00
HibiKier 81ad585a18 Update update_game_requests_info.py 2021-11-29 21:29:48 +08:00
HibiKier eb3bd2b4a6 Update update_game_info.py 2021-11-29 21:29:29 +08:00
HibiKier e401914790 Update README.md 2021-11-29 13:11:34 +08:00
HibiKier fef5dadaba Update __version__ 2021-11-29 13:10:43 +08:00
HibiKi c1348d08ed update 0.0.6.4 2021-11-29 13:09:47 +08:00
HibiKier fbd7c568d9 Update pix_update.py 2021-11-24 18:26:52 +08:00
HibiKier 2941774913 Update __init__.py 2021-11-24 18:26:38 +08:00
HibiKier b96d910401 Update __version__ 2021-11-24 14:40:53 +08:00
HibiKier 9275d0782b Update README.md 2021-11-24 14:40:39 +08:00
HibiKier 7acc6cf6af Update data_source.py 2021-11-24 14:33:10 +08:00
HibiKier d380a9aacc Update data_source.py 2021-11-24 14:32:46 +08:00
HibiKier 495377da13 Update README.md 2021-11-24 10:25:00 +08:00
HibiKier 218eed4068 Add files via upload 2021-11-24 10:24:40 +08:00
HibiKier 1e9c99dec1 Delete plugins/search_image directory 2021-11-24 10:07:47 +08:00
HibiKier 0326bc2831 Update __init__.py 2021-11-24 09:56:50 +08:00
HibiKier aed770a761 Update README.md 2021-11-23 21:48:11 +08:00
HibiKi 3de487fb24 update 0.0.6.2 2021-11-23 21:44:59 +08:00
HibiKier c802dfda22 Update README.md 2021-11-19 15:47:10 +08:00
HibiKier 3a4378e4c6 Update __init__.py 2021-11-18 14:41:54 +08:00
HibiKier 955a1f8a7f Update __init__.py 2021-11-18 14:41:13 +08:00
HibiKier ab69e5c477 Create README.md 2021-11-17 11:34:40 +08:00
HibiKier 55e42e8334 Update README.md 2021-11-17 11:33:26 +08:00
HibiKier a0f59bc2c2 Update README.md 2021-11-14 17:27:26 +08:00
HibiKier 66dabd0c8a Update plugins_manager.py 2021-11-14 17:25:45 +08:00
HibiKier 915d585e3a Merge pull request #77 from AkashiCoin/main
修复有免费游戏时不能获取免费游戏的问题
2021-11-13 16:12:49 +08:00
HibiKier 979080d281 Merge branch 'main' into main 2021-11-13 16:12:41 +08:00
HibiKier 335f76c532 Update data_source.py 2021-11-12 16:13:16 +08:00
AkashiCoin b50b934a12 Update data_source.py 2021-11-10 22:26:57 +08:00
AkashiCoin 6a1684d277 Update __init__.py 2021-11-10 22:26:29 +08:00
HibiKier 4926e4d69c Update pix_update.py 2021-11-10 21:33:10 +08:00
HibiKier b29a26551a Update README.md 2021-11-10 21:32:54 +08:00
HibiKier d1c1d93ab7 fix 2021-11-10 21:27:49 +08:00
HibiKier 907df4253c Update __version__ 2021-11-10 20:06:44 +08:00
HibiKier 658152fdc9 Update jitang.py 2021-11-10 16:45:19 +08:00
HibiKier 1a68ede632 Update README.md 2021-11-09 18:05:36 +08:00
HibiKier b70851b810 Update __init__.py 2021-11-09 18:04:33 +08:00
HibiKier 17506691a8 Update __init__.py 2021-11-07 20:45:34 +08:00
HibiKier 37a651da4e Update README.md 2021-11-05 16:52:33 +08:00
HibiKier c535a32230 Update update_info.json 2021-11-05 16:51:28 +08:00
HibiKier bb54781209 Add files via upload 2021-11-05 16:50:40 +08:00
HibiKier dcb538a3a9 Update data_source.py 2021-11-05 16:48:28 +08:00
HibiKier 185f7d9c31 Update README.md 2021-11-04 16:52:44 +08:00
986 changed files with 40931 additions and 19831 deletions
+23
View File
@@ -0,0 +1,23 @@
---
name: Issue template
about: " issue template's purpose here."
title: ''
labels: ''
assignees: ''
---
### 系统版本:Ubuntu 20.04
### 真寻版本:0.1.5.3
### 错误截图
[img]
### 日志截图
[img]
### 错误说明
发生了xx错误...
+9
View File
@@ -0,0 +1,9 @@
### 系统版本:Ubuntu 20.04
### 真寻版本:0.1.5.3
### 错误截图
[img]
### 错误说明
发生了xx错误...
+165
View File
@@ -0,0 +1,165 @@
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
demo.py
test.py
server_ip.py
member_activity_handle.py
Yu-Gi-Oh/
csgo/
fantasy_card/
data/
log/
backup/
extensive_plugin/
test/
bot.py
data/
.env
.env.dev
/resources/text/
/resources/image/
!/resources/template/
configs/config.py
configs/config.yaml
./.env
./.env.dev
plugins/csgo_server/
plugins/activity/
+332 -363
View File
@@ -1,4 +1,4 @@
<div align=center><img width="320" height="320" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/zhenxun.jpg"/></div>
<div align=center><img width="320" height="320" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/logo.png"/></div>
![maven](https://img.shields.io/badge/python-3.8%2B-blue)
![maven](https://img.shields.io/badge/nonebot-2.0.0-yellow)
@@ -13,18 +13,49 @@
如果该项目的图片等等侵犯猫豆腐老师权益请联系我删除!
如果希望有个地方讨论绪山真寻Bot,或者有问题或建议,可以发送issues或加入[ <strong>[是真寻酱哒](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>]
是新手!希望有个地方讨论绪山真寻Bot,或者有问题或建议,可以发送issues或加入[ <strong>[是真寻酱哒(萌新版)](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>]
[//]: # (是老手!讨论插件开发,nonebot2开发,可以加入[ <strong>[真寻酱的技术群]&#40;https://jq.qq.com/?_wv=1027&k=u8PgBkMZ&#41; </strong>])
## 声明
此项目仅用于学习交流,请勿用于非法用途
# Nonebot2
<img style="height: 200px;width: 200px;" src="https://camo.githubusercontent.com/0ef71e86056da694c540790aa4a4e314396884d6c4fdb95362a7538b27a1b034/68747470733a2f2f76322e6e6f6e65626f742e6465762f6c6f676f2e706e67">
非常 [ **[NICE](https://github.com/nonebot/nonebot2)** ] 的OneBot框架
## 未完成的文档
[传送门](https://hibikier.github.io/zhenxun_bot/)
# [传送门](https://hibikier.github.io/zhenxun_bot/)
## 真寻的帮助
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
## 普通帮助图片
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/help.png)
## HTML版帮助图片
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/html_help.png)
## Web UI
[zhenxun_bot_webui](https://github.com/HibiKier/zhenxun_bot_webui)
## 一键安装脚本
[zhenxun_bot-deploy](https://github.com/AkashiCoin/zhenxun_bot-deploy)
## 提供符合真寻标准的插件仓库
[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
## 来点优点?
* 实现了许多功能,且提供了大量功能管理命令
* 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改
* 方便增删插件,原生nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
* 提供了cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`__plugin_cd_limit__`
* __..... 更多详细请通过`传送门`查看文档!__
## 功能列表
<details>
@@ -47,9 +78,13 @@
- [x] 商店/我的金币/购买道具/使用道具
- [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
- [x] 我有一个朋友想问问..(借鉴pcrbot插件)
- [x] 原神黄历 (使用[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 原神黄历
- [x] 原神今日素材
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 原神便笺查询
- [x] 原神玩家查询
- [x] 原神树脂提醒
- [x] 原神签到/自动签到
- [x] 金币红包
- [x] 微博热搜
- [x] B站主播/UP/番剧订阅
@@ -84,6 +119,8 @@
- [x] 获取b站视频封面
- [x] 通过PID获取图片
- [x] 功能统计可视化
- [x] 词云
- [x] 关于
### 已实现的管理员功能
- [x] 更新群组成员信息
@@ -96,6 +133,8 @@
- [x] 移动图片 (同上)
- [x] 删除图片 (同上)
- [x] 群内B站订阅
- [x] 词条设置
- [x] 休息吧/醒来
### 已实现的超级用户功能
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
@@ -121,6 +160,12 @@
- [x] 功能开关(更多设置)
- [x] 功能状态
- [x] b了
- [x] 执行sql
- [x] 重载配置
- [x] 清理临时数据
- [x] 增删群认证
- [x] 同意/拒绝好友/群聊请求
- [x] 配置重载
#### 超级用户的被动技能
- [x] 邀请入群提醒(别人邀请真寻入群)
@@ -145,138 +190,20 @@
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
- [x] 群权限系统
- [x] 定时更新权限
- [x] 自动配置重载
</details>
## 功能具体指令
<details>
<summary>功能具体指令说明</summary>
### 常用功能
** [*]:表示该参数可有多个 [?]:表示参数可选 **
| 功能 | 指令 | 说明
| ----------------------| :--------------------------------------:| :------------------------:
| 签到 | 签到/我的签到/好感度排行/好感度总榜/好感度总榜\[显示我/屏蔽我] | 普通的签到插件,可以获得好感度和金币<br>好感度影响开箱次数和涩图触发概率,金币用于购买道具,俄罗斯轮盘赌注以及金币红包<br>好感度总榜,显示所有群的群员好感度排行,可通过命令好感度总榜\[显示我/屏蔽我] 来设置是否隐藏
| 发送图片 | 美图/壁纸/萝莉 \[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图片,说实话挺失望的,太色了
| 骂我 | 骂我 | 就是发送钉宫的语音罢了
| 戳一戳 | 戳一戳 | 随机发送钉宫语音 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>示例:我有一个朋友想问问他喜不喜欢真寻
| 昵称系统 | 以后叫我\[昵称]/以后请叫我\[昵称]/我是谁/我叫什么 | 此昵称会替换与真寻聊天中 '你' 的名称(群名片),群与群与私聊的昵称相互独立
| 原神黄历 | 原神黄历 | 查看今日原神黄历,含有每日10:25的定时任务
| 原神材料 | 今日素材 | 发送可莉特调的截图
| 丘丘语翻译 | 丘丘翻译/丘丘一下/丘丘语翻译 | 示例:丘丘一下 mimi
| 原神资源查询 | 原神资源查询 \[资源名称] \[路线]?/\[资源名称]在哪/哪里有\[资源名称]/原神资源列表 | 如果资源名称末尾添加‘路线’的话将生成残缺缺缺版的优先路径<br>示例:嘟嘟莲在哪<br>原神资源查询嘟嘟莲路线
| 俄罗斯轮盘 | 装弹\[子弹数] \[金额](默认200)/开枪/结算/我的战绩/胜场排行/败场排行/欧洲人排行/慈善家排行 | 紧张刺激的群内小游戏,使用每日签到的金币作为赌注,具体玩法请发送 真寻帮助 俄罗斯轮盘
| 红包系统 | 塞红包\[金额] \[数量](默认5)/抢/开/戳一戳/退回 | 仿微信明日方舟红包的样式(pil拼图大师!),每个红包金额随机生成,最多会是红包总金额的1/3,退回用于退回一分钟后还未开完的红包
| 金币排行 | 金币排行 | 字面意思
|网易云热评 | 到点了/12点了/网易云热评/网易云评论 | 防下塔
| 古诗 | 念诗/念首诗/来首诗 | 突然文艺起来了
|微博热搜 | 微博热搜/微博热搜[序号]? | 快捷热搜查询方式
| pil对图片的操作 | 修改尺寸/等比压缩/旋转图片/水平翻转/铅笔滤镜/模糊效果/锐化效果/高斯模糊/边缘检测/底色替换 | 选项较多,请直接发送 真寻图片帮助
| BUFF皮肤底价查询 | 查询皮肤 \[武器名称] \[皮肤名称] | 网络不友好的话会经常超时<br>示例:查询皮肤 沙漠之鹰 印花集
| 天气查询 | \[城市]天气 | 非常常见的插件,第一个入门插件
| 疫情查询 | 疫情/查询疫情 \[城市名或省份名] | 示例:疫情杭州
| 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仅可私聊,查看真寻帮助搜图
| 通过PID搜索图片 | p搜 [pid] | 在群内使用此功能会在30秒内撤回
| 翻译 | 英翻/日翻/韩翻/翻韩/翻日/翻英 \[文本] | 三种语言互相翻译
| 获取b站视频封面 | b封面 [链接/av/bv/cv/直播id] | 快捷的封面获取方式
| 群欢迎消息 | 群欢迎消息/查看群欢迎消息/查看当前群欢迎消息 | 查看给真寻设置的群欢迎消息
| 自我介绍 | 自我介绍 | 没错,一份正经的真寻自我介绍
| 我的权限 | 我的权限 | 真寻内部定义的一套权限系统
| 我的信息 | 我的信息 | 唯一的作用就是看看什么时候加入群
| 撤回 | 撤回 \[消息位置]?(默认为最新一条消息) | 按顺序撤回发送的消息,示例:撤回 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动态和投稿
### 管理员功能
**群主与群管理员默认5级权限**
| 功能 | 权限等级 | 指令 | 说明
| -------------| --------------| :--------------------------------------:| :------------------------:
| 更新群组成员信息 | 1 | 更新群组成员信息/更新群组成员列表 | 存储群员的基本信息,虽然有自动更新,但备个命令以防万一
| 群功能开关 | 2 | 开启/关闭\[指令名]功能 | 群帮助中左边带有√的功能都可以通过此命令开启或关闭,示例:开启色图
| 查看群被动技能 | 2 | 群通知状态 | 详细请查看被动技能列表
| 被动技能开关 | 2 | 开启/关闭被动技能 | 有时候花里胡哨通知也会很烦人
| 自定义群欢迎消息 | 2 | 自定义群欢迎消息 \[文本] \[图片] | 文本和图片至少需要一个,在文本内添加"\[at]"字符串可以用来设置艾特进群的新群员
| 黑名单 | 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帮助,省略群号则私聊用户(必须要有用户的好友)
| 更新cookie | 更新cookie \[cookie] | 用于更新开箱数据和查询buff皮肤
| 开启广播通知 | 开启/关闭广播通知 \[群号] | 用于开启/关闭是否对某些群进行广播(上边的广播方法)
| 退群 | 退群 \[群号] | 用于退出某一些群
| 检查系统状态 | 自检 | 略
| 更新好友/群组信息| 更新好友/群组信息 | 包含自动更新,被t出群等等有更好的可视信息
| 重载卡池 | 略 | 重载抽卡的游戏卡池,请查看 \[nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw)
| 添加商品 | 添加商品 \[名称]-\[价格]-\[描述]-\[折扣](小数)?-\[限时时间](分钟)? | 为真寻的商店添加一点点道具<br>示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60
| 删除商品 | 删除商品 \[名称或序号] | 在真寻的商店中删除一点东西
| 修改商品 | 修改商品 -name \[名称或序号] -price \[价格] -des \[描述] -discount \[折扣] -time \[限时]| 注意空格,不需要的参数可以不加<br>示例:修改商品 -name 1 -price 900 【修改序号为1的商品的价格为900】
| 节日红包 | 节日红包 \[金额] \[数量] \[祝福语]? \[群号]?... | 群号支持批量,使用空格隔开,不使用群号则对所有群发送节日红包,节日红包有效时间为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<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>
## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
## 部署
## 简单部署
```
# 配置gocq
在 https://github.com/Mrs4s/go-cqhttp 下载Releases最新版本,运行后选择反向代理,
后将gocq的配置文件config.yml中的universal改为universal: ws://127.0.0.1:8080/cqhttp/ws
后将gocq的配置文件config.yml中的universal改为universal: ws://127.0.0.1:8080/onebot/v11/ws
# 获取代码
git clone https://github.com/HibiKier/zhenxun_bot.git
@@ -285,17 +212,18 @@ git clone https://github.com/HibiKier/zhenxun_bot.git
cd zhenxun_bot
# 安装依赖
pip install -r requirements.txt
pip install poetry # 安装 poetry
poetry install # 安装依赖
# 进行基础配置
####请查看 配置 部分####
# 开始运行
poetry shell # 进入虚拟环境
python bot.py
```
## 配置
在 configs/config.py 中的 USE_CONFIG_FILE,默认为False
## 简单配置
```
1.在.env.dev文件中
@@ -303,299 +231,340 @@ python bot.py
SUPERUSERS = [""] # 填写你的QQ
2.在configs/config.py文件中
必填:
1. API KEY
2.数据库配置
* 数据库配置
在./configs/config.py中配置基本配置(除API KEY ,数据库和代理外都含有默认值)
在./configs/path_config.py配置路径(含有默认配置)
3.在configs/config.yaml文件中 # 该文件需要启动一次后生成
* 修改插件配置项
```
## 使用Docker
__Docker 单机版(仅真寻Bot)__
**点击下方的 GitHub 徽标查看教程**
[![Github](https://shields.io/badge/GITHUB-Sakuracio-4476AF?logo=github&style=for-the-badge)](https://github.com/Sakuracio/zhenxun_bot_docker)
[![DOCKER](https://shields.io/badge/docker-hibikier/zhenxun_bot-4476AF?logo=docker&style=for-the-badge)](https://hub.docker.com/r/hibikier/zhenxun_bot)
__Docker 全量版(包含 真寻Bot PostgreSQL数据库 go-cqhttp webui等)__
[![Github](https://shields.io/badge/GITHUB-SinKy--Yan-4476AF?logo=github&style=for-the-badge)](https://github.com/SinKy-Yan/zhenxunbot-docker)
[![DOCKER](https://shields.io/badge/docker-jyishit/zhenxun_bot-4476AF?logo=docker&style=for-the-badge)](https://hub.docker.com/r/jyishit/zhenxun_bot)
**点击上方的 GitHub 徽标查看教程**
PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能无法正常启动全量版容器**
## [爱发电](https://afdian.net/@HibiKier)
<details>
<summary>爱发电 以及 感谢投喂 </summary>
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
### 感谢名单
(可以告诉我你的 __github__ 地址,我偷偷换掉0v|)
[阿奎](https://afdian.net/u/da41f72845d511ed930d52540025c377)
[醉梦尘逸](https://afdian.net/u/bc11d2683cd011ed99b552540025c377)
[Abc](https://afdian.net/u/870dc10a3cd311ed828852540025c377)
[本喵无敌哒](https://afdian.net/u/dffaa9005bc911ebb69b52540025c377)
[椎名冬羽](https://afdian.net/u/ca1ebd64395e11ed81b452540025c377)
[kaito](https://afdian.net/u/a055e20a498811eab1f052540025c377)
[笑柒XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377)
[请问一份爱多少钱](https://afdian.net/u/f57ef6602dbd11ed977f52540025c377)
[咸鱼鱼鱼鱼](https://afdian.net/u/8e39b9a400e011ed9f4a52540025c377)
[Kafka](https://afdian.net/u/41d66798ef6911ecbc5952540025c377)
[墨然](https://afdian.net/u/8aa5874a644d11eb8a6752540025c377)
[爱发电用户_T9e4](https://afdian.net/u/2ad1bb82f3a711eca22852540025c377)
[笑柒XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377)
[noahzark](https://afdian.net/a/noahzark)
[腊条](https://afdian.net/u/f739c4d69eca11eba94b52540025c377)
[ze roller](https://afdian.net/u/0e599e96257211ed805152540025c377)
[爱发电用户_4jrf](https://afdian.net/u/6b2cdcc817c611ed949152540025c377)
[爱发电用户_TBsd](https://afdian.net/u/db638b60217911ed9efd52540025c377)
[烟寒若雨](https://afdian.net/u/067bd2161eec11eda62b52540025c377)
[ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377)
[爱发电用户_b9S4](https://afdian.net/u/3d8f30581a2911edba6d52540025c377)
[爱发电用户_c58s](https://afdian.net/u/a6ad8dda195e11ed9a4152540025c377)
[爱发电用户_eNr9](https://afdian.net/u/05fdb41c0c9a11ed814952540025c377)
[MangataAkihi](https://github.com/Sakuracio)
[炀](https://afdian.net/u/69b76e9ec77b11ec874f52540025c377)
[爱发电用户_Bc6j](https://afdian.net/u/8546be24f44111eca64052540025c377)
[大魔王](https://github.com/xipesoy)
[CopilotLaLaLa](https://github.com/CopilotLaLaLa)
[嘿小欧](https://afdian.net/u/daa4bec4f24911ec82e552540025c377)
[回忆的秋千](https://afdian.net/u/e315d9c6f14f11ecbeef52540025c377)
[十年くん](https://github.com/shinianj)
[哇](https://afdian.net/u/9b266244f23911eca19052540025c377)
[yajiwa](https://github.com/yajiwa)
[爆金币](https://afdian.net/u/0d78879ef23711ecb22452540025c377)
</details>
## 更新
### 2021/10/15
### 2022/12/27 \[v0.1.6.6]
* 适配了原神资源查询米游社地图返回的新格式
* 添加权限检查依赖注入
### 2021/10/8
### 2022/12/26
* 修复疫情省份查询失效
* 修复功能调用统计全局下统计可能发生错误
* 优化`gamedraw`插件
* 提供全局被动控制
* 群被动状态改为图片
* 修复epic获取到的简介不是中文的bug [@pull/1221](https://github.com/HibiKier/zhenxun_bot/pull/1221)
### 2021/10/4
## 2022/12/24
* 修复了功能调用统计失效问题
* 当色图库中没有色图时,会在线搜索色图而不是‘没找到符合条件的色图...’
* 快速更新权限再给超级用户发送错误日志
* 修复疫情未加载省份城市无法正常使用
* 修复群管理员权限检测会阻挡超级用户权限
### 2021/10/3
### 2022/12/23
* 对插件进行分离
* 重写了插件与限制管理器以及帮助获取
* 修改一些插件目录和数据存储目录
* 插件通用配置与限制数据将以ymal文件存储 \[路径:data/configs]
* 所有商店相关操作调用统计合并为商店(包括之前已经保存的数据,会先进行备份)
* 简化了点歌的代码相关
* 修复了碧蓝航线抽卡新框导致报错无法正常初始化
* 修复了P站排行/搜图在PC端无法正常显示
* 添加了插件对超级用户是否限制的配置 ‘limit_superuser’
* 添加命令 ‘重载插件配置’,用于生效手动修改配文件
* 超级用户帮助可以添加 -super 来显示该插件的超级用户帮助,示例:帮助.ban -super
* 原神黄历改为网页截图
* 修改了鲁迅说逻辑结构
* 修改了统计图表样式,改为自定义CreateMat
* 节日红包不再被24小时限制,群内多个节日红包将会覆盖
* 当群权限为-1时,不会对群发送修改权限通知,并屏蔽此群一切命令(包括提醒)
* 修复了红包数量可以过大或为负数,红包数量大于群员数量时会修改为群员数量
* 修复了负数开箱
* 签到最低好感度设置为0.01 [@pull/53](https://github.com/HibiKier/zhenxun_bot/pull/53)
* pip安装新依赖 ruamel.yaml
* 修复功能 EPIC [@pull/58](https://github.com/HibiKier/zhenxun_bot/pull/58)
* 优化`管理员帮助`,`超级用户帮助`图片
* 重新移植`gamedraw`
* 修复pil帮助私聊时无法生成
### 2021/9/10
### 2022/12/17
* 修复撤回消息有时无法正确获取消息id
* 修复查看插件仓库当已安装插件版本不一致时出错
### 2021/9/9
### 2022/12/15
* 替换coser API
* 修复签到uid可能不默认为0
* 修复签到可能重复的问题
* 修复无订阅时递归出错
* 启用了plugins2info_dict, plugins2cd_dict, plugins2exists_dict配置文件,通过USE_CONFIG_FILE=True开启
* 修复涩图local_id会被固定为50
* 优化图库数量查询
* 修复原神大地图过大无法打开报错
* 修复无法显示正确的涩图上限
* 修复自定义群欢迎消息无法使用
### 2021/9/7
### 2022/12/13
* 修改 update_info.json
* 修改 更新信息 图片大小
* 修复 查看订阅 命令 UP和番剧无法正常显示
* 修复订阅推送无法正确推送
* 修复搜图返回列表为空时无法正确回复 [@pull/40](https://github.com/HibiKier/zhenxun_bot/pull/40)
* 修复.unban
### 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权限用户可以修改禁言检测相关设置
### 2022/12/12
### 2021/8/17
* 修改HTML帮助禁用提示文本错误
* 修复HTML帮助私聊无法生成
* 新增配置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不生效
### 2022/12/11
### 2021/8/10
* 词条问题支持真寻的昵称开头与at真寻开头并优化回复
* 帮助新增HTML生成(新布局),添加配置`TYPE`切换
* 更正私聊时功能管理回复错误
* 修复加入新群聊时初始化功能开关错误
* 添加单例注解
* 添加统计表
* 重复的好友请求和邀群提示在5分钟内不会重复提示
* 疫情会优先检查城市,城市省份市区重名时请添加‘市’
* 添加命令‘原神资源查找’,‘设置cookie’
* 添加配置AUTO_UPDATE_ZHENXUN,是否自动更新真寻,默认True
* 添加配置MAX_RUSSIAN_BET_GOLD,俄罗斯轮盘赌注最大金额,默认1000
* 检查更新真寻定时任务时间改为12 : 00
* 添加功能能不能好好说话(nbnhhsh)
* 添加功能随机roll,无参为数字,有参为随机参数
* 添加linux重启脚本以及重启命令‘重启’(建议首次生成restart.sh先查看命令是否正确)
* 修复管理员功能的权限检测
* 修复丢人爬开关
### 2022/12/10
### 2021/8/6
* 重写帮助,删除 `详细帮助` 命令
* 天气查询会优先遍历城市
* 添加自动更新真寻命令
### 2022/12/4
##### 如果你的版本为 2021/8/4,可以直接复制plugins/check_zhenxun_update后,通过指令来更新真寻
* 优化管理代码
### 2021/8/4
### 2022/11/28
* 修改天气与疫情城市数据,改为api获取,丰富疫情的回复消息
* 原神资源查询,大地图将被压缩至9M,且启动时当大地图存在时不再自动更新地图
* 下载数据库内色图时将直接存储至_setu,不再存储至临时文件
* 重复的好友请求或邀请请求在一定时间不会重复发送提醒
* 添加每日自动清理临时图片定时任务
* 修复金币排行显示
* 修复无法正常关闭戳一戳功能
* 修复web_ui群组无法获取
* 修复web_ui修改插件数据时cmd格式错误
### 2021/7/30
### 2022/11/28
* 重构代码,进行优化,添加注释,删除冗余代码,降低代码耦合
* 添加功能:PIX(一套快捷的pixiv存图命令,自建图库存储url等信息?意在获取自己或群友xp的图)
* 添加功能:清理临时图片文件(temp/rar/r18_rar文件夹)
* 添加额外定时任务(5分钟检测一次),解决加入新群时无法及时为管理员提供权限
* 添加配置ALAPI_AI_CHECK,开关AI回复文本检测
* 添加配置IMPORT_DEFAULT_SHOP_GOODS,控制是否导入内置的三个商品(好感度加持卡ⅠⅡⅢ)
* 添加配置ONLY_USE_LOCAL_SETU,仅仅使用本地色图(有的话),提升速度,但无法在线搜索色图和保存链接
* 添加配置WITHDRAW_SETU_TIME,是否需要延迟撤回色图,可配置仅群里,私聊或全部
* 好友请求,入群请求,滴滴滴-,/t,被踢出群提醒,的提示消息更加丰富
* 彻底重写原神资源查找,添加规划路线(路线残缺缺缺缺版,有空补)添加命令‘更新原神资源信息’,强制更新地图等资源
* 优化色图和P站排行/搜图检测用户是否正在触发命令代码
* 当群最后发言大于36小时,也会关闭广播通知
* 功能维护时超级用户依然可以调用(苦了谁都不能苦了自己)
* 修复获取赛马娘UP公告
* 重写 色图/更新色图
* 色图数据存储改为数据库,启动时会更新之前的色图数据(有的话),更新完毕后会删除原数据文件,如果需要保留请提前备份,
* lolicon api改为v2
* 取消r18次数限制
* 单次搜索至多保存100条链接
* 添加定时撤回
* 暂时取消上传/删除色图
*
* 更新建议(不要替换你的data和resources文件夹!)
* 删除configs,plugins,services,utils,models文件夹重新clone
* 删除多余文件夹,resources/img/genshin/seek_god_eye
* 清空resources/img/genshin/genshin_icon文件夹,仅保留box.png和box_alpha.png
* 替换bot.py
* :bug: Fix a bug in open_cases to get vanilla knives' prices [@pull/1188](https://github.com/HibiKier/zhenxun_bot/pull/1188)
### 2021/7/27
### 2022/11/24
* 原神今日素材改为单张截图+拼图,更新文件utils/img_utils.py及plugins/genshin/material_remind/__init__.py
* 修复管理员插件加载路径错误
### 2021/7/26
### 2022/11/23
* 修复原神今日素材稻妻城开放后截图不完整的问题
* 修复webui插件无法获取修改
### 2021/7/14
### 2022/11/22
* 原神今日素材自动更新时间由 00:01 -> 04:01 [#issues7](https://github.com/HibiKier/zhenxun_bot/issues/7)
* 小问题的修复和优化
* fix switch_rule [@pull/1185](https://github.com/HibiKier/zhenxun_bot/pull/1185)
### 2021/7/12
### 2022/11/21 \[v0.1.6.5]
* 修复开箱功能单抽出金时存储格式错误导致 ‘我的金色’ 无法正常发送图片
* 小问题的修复和优化
* 优化manager, hook代码
* 修复pid搜图 [@pull/1180](https://github.com/HibiKier/zhenxun_bot/pull/1180)
### 2021/7/6
### 2022/11/19
* 识番功能 trace.moe 替换为新API(旧API已失效)
* 小问题的修复和优化
* 修改优化帮助图片生成逻辑
### 2021/6/30
### 2022/11/18
* 将plugin2name和plugin2level合并为plugin2info
* util改为utils(。。!)
* 修复当用户发送速度极快时开箱会突破每日限制
* 新增功能:通过PID获取图片
* 发送图片新增功能:搜索图片
* 功能统计可视化
* 新增命令:好感度总排行
* 原神每日素材改为从"可莉特调"截图,提供命令‘更新原神每日素材’和定时任务
* 修复月功能统计错误的问题
* poetry添加适配器依赖,更新支持py3.10 [@pull/1176](https://github.com/HibiKier/zhenxun_bot/pull/1176)
### 2021/6/24
### 2022/11/13
* 添加了一些ALAPI:网易云热评,获取b站视频封面,古诗(需要填写ALAPI_TOKEN)
* 如果填写了ALAPI_TOKEN,将会检测备用接口回复的文本是否合规
* 优化了色图,当搜索色图下载失败时,会从本地色图库中发送相关tag色图
* 当网易云点歌繁忙时会尝试多次点歌
* 更新天气api
* 使用道具可以附带额外信息供函数使用
* 限制帮助图片最小宽度
### 2021/6/23
### 2022/11/12
* 添加功能:群权限(所以说内鬼都快爬,可以在configs/config.py中修改各个功能的权限等级)
* 优化了数据统计,将以7天,30天为周期,为将来更方便实现数据可视化
* 更新坎公骑冠剑UP卡池
* 修复赛马娘UP卡池
* 修复一些小问题
* 更新yiqing插件数据显示 [@pull/1168](https://github.com/HibiKier/zhenxun_bot/pull/1168)
### 2021/6/18
### 2022/11/11
* 修复p站排行,搜图因网络问题爆炸时没有具体回复
* 更换色图显示方式为 id,title,author,pid
* 修复修改商品后商品顺序改变
* 滴滴滴- 和 /t支持图片回复
* 将/t回复更加简单(可以通过序号),且可以直接发送群
* 修复bt功能无法交互
* fix: B站直播订阅的相关问题 [@pull/1158](https://github.com/HibiKier/zhenxun_bot/pull/1158)
### 2021/6/17
### 2022/10/30
* 修复p站排行,搜图因网络问题爆炸时没有具体回复
* 更换色图显示方式为 id,title,author,pid
* 商店简介动态行数,根据文字长度自动换行
### 2021/6/15
* 修改了‘帮助’功能,具体为‘帮助 指令名’,未指定指令名时则为查看全部功能列表
* 修改了色图的存储数据格式
* 色图功能搜索的色图改为随机从urls中随机抽取
* 将商品数据存储入数据库,提供 '增加/删除/修改商品' 指令
* 商店列表图片不再使用固定背景图,改为直接拼图
* 增加功能:俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
* 增加功能:金币红包(节日红包与群红包相互独立)
* 金币排行
* 重写一个朋友插件
* 其他微小调整
### 2022/10/28
### 2021/6/4
* 重写BT功能
* 进行一些BUG修复和微小调整
* 添加撤回功能[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
* 为色图功能添加额外的 上传色图 和 删除色图方法(影响hash)
* 为exec指令进行了SELECT语句适配,添加了查看所有表指令 [@pull/1155](https://github.com/HibiKier/zhenxun_bot/pull/1155)
* 修复复读 [@pull/1154](https://github.com/HibiKier/zhenxun_bot/pull/1154)
### 2021/5/26
* 将语录源更换为一言api
### 2022/10/23
* 复读修改回图片下载
### 2022/10/22
* 更新依赖注入
### 2022/10/16 \[v0.1.6.4]
* 修改商店道具icon可以为空
### 2022/10/15
* nonebot2版本更新为rc1
* 我的道具改为图片形式
* 商品添加图标与是否为被动道具(被动道具无法被主动使用)
* 商品添加使用前方法和使用后方法(类似hook),使用方法具体查看文档或签到商品文件中注册的例子
* 新增用户使用道具,花费金币(包括插件)及用途记录
* 更细致的金币使用依赖注入
* 更多的依赖注入(包含图片获取等等..
* 修复我的道具仅有被动或主动道具时图片显示错误
* 色图插件p站反向代理失效 [@pull/1139](https://github.com/HibiKier/zhenxun_bot/pull/1139)
### 2022/10/9
* 修复碧蓝档案角色获取问题,换源 [@pull/1124](https://github.com/HibiKier/zhenxun_bot/pull/1124)
### 2022/10/7
* 修复 B 站请求返回 -401 错误 [@pull/1119](https://github.com/HibiKier/zhenxun_bot/pull/1119)
* 关闭功能与被动时不再区分大小写,同名时仅被动关闭操作生效
### 2022/9/30
* 修改重置开箱的使用权限 [@pull/1118](https://github.com/HibiKier/zhenxun_bot/pull/1118)
### 2022/9/27
* 更新b站转发解析 [@pull/1117](https://github.com/HibiKier/zhenxun_bot/pull/1117)
### 2022/9/24
* 修复b站订阅 [@pull/1112](https://github.com/HibiKier/zhenxun_bot/pull/1112)
* fix: 重载赛马娘卡池失败 [@pull/1114](https://github.com/HibiKier/zhenxun_bot/pull/1114)
### 2022/9/19
* 更换bilibili_sub获取用户昵称用的API&尝试修了一下get_video() [@pull/1097](https://github.com/HibiKier/zhenxun_bot/pull/1097)
* 修复csgo每日开箱可以多开一次
### 2022/9/18
* 修复 bilireq 版本过低导致 B 站视频解析错误 [@pull/1090](https://github.com/HibiKier/zhenxun_bot/pull/1096)
### 2022/9/16
* fix: bilibili_sub, azur_draw_card [@pull/1090](https://github.com/HibiKier/zhenxun_bot/pull/1090)
* 修复原神资源查询查询完毕后图片存储错误
* b站订阅发送 与 b站订阅 使用相同开关,即:关闭b站订阅
### 2022/9/10
* 自定义群欢迎消息参数不完全时提示报错
* 修改bt插件的url地址 [@pull/1067](https://github.com/HibiKier/zhenxun_bot/pull/1067)
### 2022/9/8
* 添加插件数据初始化判断
### 2022/9/4
* 旧词条提供图片迁移(需要重新获取old_model文件,并将数据库中user_qq为0的数据删除)
### 2022/9/3
* 原神玩家查询增加须弥地区 [@pull/1053](https://github.com/HibiKier/zhenxun_bot/pull/1053)
* av号覆盖全面,且修复av号链接 [@pull/1033](https://github.com/HibiKier/zhenxun_bot/pull/1033)
* 修复词条含有CQ回答的模糊匹配无法被解析
* 禁言检测图片在内存中获取图片hash
* B站订阅在群里中任意群管理员可以统一管理(原来为管理员1无法删除管理员2的订阅)
* 修复原神资源查询地图api数据变更导致更新的地图不完全
### 2022/8/27
* 修复签到积分双倍后,日志记录获得积分变4倍问题 [@pull/1044](https://github.com/HibiKier/zhenxun_bot/pull/1044)
### 2022/8/26
* 修复群管理员无法添加词条
* 修复词条关键词"问"前空格问题
### 2022/8/23
* 修了下模糊匹配 issue#1026 [@pull/1026](https://github.com/HibiKier/zhenxun_bot/pull/1026)
### 2022/8/22
* 修复首次安装时词条旧表出错(因为根本就没有这张表!)
* 取消配置替换定时任务,统一存储
* 对米游社cookie进行判断,整合米游社签到信息 [@pull/1014](https://github.com/HibiKier/zhenxun_bot/pull/1014)
* 修正尘歌壶和质变仪图片获取地址 [@pull/1010](https://github.com/HibiKier/zhenxun_bot/pull/1010)
* 修复词库问答 **很多** 问题[@pull/1012](https://github.com/HibiKier/zhenxun_bot/pull/1012)
### 2022/8/21 \[v0.1.6.3]
* 重构群词条,改为词库Plus,增加 精准|模糊|正则 问题匹配,问题与回答均支持at,image,face,超级用户额外提供 全局|私聊 词库设置,数据迁移目前只提供了问题和回答都是纯文本的词条
* 修复b站转发解析av号无法解析
* B站订阅直播订阅支持短号
* 开箱提供重置开箱命令,重置今日所有开箱数据(重置次数,并不会删除今日已开箱记录)
* 提供全局字典GDict,通过from utils.utils import GDict导入
* 适配omega 13w张图的数据结构表(建议删表重导)
* 除首次启动外将配置替换加入单次定时任务,加快启动速度
* fix: WordBank.check() [@pull/1008](https://github.com/HibiKier/zhenxun_bot/pull/1008)
* 改进插件 `我有一个朋友`,避免触发过于频繁 [@pull/1001](https://github.com/HibiKier/zhenxun_bot/pull/1001)
* 原神便笺新增洞天宝钱和参量质变仪提示 [@pull/1005](https://github.com/HibiKier/zhenxun_bot/pull/1005)
* 新增米游社签到功能,自动领取(白嫖)米游币 [@pull/991](https://github.com/HibiKier/zhenxun_bot/pull/991)
### 2022/8/14
* 修复epic未获取到时间时出错
* 修复订阅主播时动态获取的id是直播间id
### 2022/8/8
* 修复赛马娘重载卡池失败的问题 [@pull/969](https://github.com/HibiKier/zhenxun_bot/pull/969)
### 2022/8/3
* 修复 bili动态链接在投稿视频时URL和分割线连在一起 [@pull/951](https://github.com/HibiKier/zhenxun_bot/pull/961)
* 更新 Epic 免费游戏商城链接拼接规则 [@pull/957](https://github.com/HibiKier/zhenxun_bot/pull/957)
### 2022/8/6
* 修复了原神自动签到返回invalid request的问题,新增查看我的cookie命令 [@pull/971](https://github.com/HibiKier/zhenxun_bot/pull/971)
<br>
__..... 更多更新信息请查看文档__
## Todo
- [ ] 提供更多对插件的控制
- [ ] 明日方舟卡片式的签到..(大概)
- [ ] 更多的群管理功能
- [ ] 数据清理控制
- [ ] docker容器
- [x] web管理
## 感谢
[Onebot](https://github.com/howmanybots/onebot)
[go-cqhttp](https://github.com/Mrs4s/go-cqhttp)
[nonebot2](https://github.com/nonebot/nonebot2)
[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)
[cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins#%E7%94%9F%E6%88%90%E5%99%A8%E6%8F%92%E4%BB%B6)
[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
[nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)
[nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager)
[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)
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
[Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台.
[nonebot / nonebot2](https://github.com/nonebot/nonebot2) :跨平台Python异步机器人框架
[Angel-Hair / XUN_Bot](https://github.com/Angel-Hair/XUN_Bot) :一个基于NoneBot和酷Q的功能性QQ机器人
[pcrbot / cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins) :hoshino插件合集
[MeetWq /nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw) :A simple withdraw plugin for Nonebot2
[maxesisn / nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) :适用于nonebot2的点歌插件
[nonepkg / nonebot-plugin-manager](https://github.com/nonepkg/nonebot-plugin-manager) :Nonebot Plugin Manager base on import hook
[H-K-Y / Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot) :原神bot,这是一个基于nonebot和HoshinoBot的原神娱乐及信息查询插件
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
[KimigaiiWuyi / GenshinUID](https://github.com/KimigaiiWuyi/GenshinUID) :一个基于HoshinoBot/NoneBot2的原神UID查询插件
+1 -1
View File
@@ -1 +1 @@
__version__: v0.0.5.1
__version__: v0.1.6.6
Regular → Executable
View File
+4 -2
View File
@@ -1,10 +1,12 @@
from pathlib import Path
from configs.config import Config
import nonebot
Config.add_plugin_config(
"admin_bot_manage:custom_welcome_message",
"SET_GROUP_WELCOME_MESSAGE_LEVEL",
"SET_GROUP_WELCOME_MESSAGE_LEVEL [LEVEL]",
2,
name="群管理员操作",
help_="设置群欢迎消息权限",
@@ -27,4 +29,4 @@ Config.add_plugin_config(
default_value=5
)
nonebot.load_plugins("basic_plugins/admin_bot_manage")
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
@@ -0,0 +1,384 @@
from typing import List
from nonebot.adapters.onebot.v11.message import MessageSegment
from services.log import logger
from configs.path_config import DATA_PATH, IMAGE_PATH
from utils.message_builder import image
from utils.utils import get_bot, get_matchers
from pathlib import Path
from models.group_member_info import GroupInfoUser
from datetime import datetime
from services.db_context import db
from models.level_user import LevelUser
from configs.config import Config
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
import asyncio
import time
import os
import ujson as json
custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
)
ICON_PATH = IMAGE_PATH / 'other'
async def group_current_status(group_id: int) -> str:
"""
说明:
获取当前群聊所有通知的开关
参数:
:param group_id: 群号
"""
_data = group_manager.get_task_data()
image_list = []
for i, task in enumerate(_data):
name = _data[task]
name_image = BuildImage(0, 0, plain_text=f"{i+1}.{name}", font_size=20)
bk = BuildImage(name_image.w + 200, name_image.h + 20, color=(103, 177, 109), font_size=15)
await bk.apaste(name_image, (10, 0), True, "by_height")
a_icon = BuildImage(40, 40, background=ICON_PATH / "btn_false.png")
if group_manager.check_group_task_status(group_id, task):
a_icon = BuildImage(40, 40, background=ICON_PATH / "btn_true.png")
b_icon = BuildImage(40, 40, background=ICON_PATH / "btn_false.png")
if group_manager.check_task_super_status(task):
b_icon = BuildImage(40, 40, background=ICON_PATH / "btn_true.png")
await bk.atext((name_image.w + 20, 10), "状态")
await bk.apaste(a_icon, (name_image.w + 50, 0), True)
await bk.atext((name_image.w + 100, 10), "全局")
await bk.apaste(b_icon, (name_image.w + 130, 0), True)
image_list.append(bk)
w = max([x.w for x in image_list])
h = sum([x.h + 10 for x in image_list])
A = BuildImage(w + 20, h + 70, font_size=30, color=(119, 97, 177))
await A.atext((15, 20), "群被动状态")
curr_h = 75
for img in image_list:
# await img.acircle_corner()
await A.apaste(img, (0, curr_h), True)
curr_h += img.h + 10
return A.pic2bs4()
async def custom_group_welcome(
msg: str, img_list: List[str], user_id: int, group_id: int
) -> str:
"""
说明:
替换群欢迎消息
参数:
:param msg: 欢迎消息文本
:param img_list: 欢迎消息图片,只取第一张
:param user_id: 用户id,用于log记录
:param group_id: 群号
"""
img_result = ""
result = ""
img = img_list[0] if img_list else ""
if (DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").exists():
(DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").unlink()
data = {}
if not custom_welcome_msg_json.exists():
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
else:
try:
data = json.load(open(custom_welcome_msg_json, "r"))
except FileNotFoundError:
pass
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}")
result += msg
if img:
await AsyncHttpx.download_file(
img, DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg"
)
img_result = image(DATA_PATH / "custom_welcome_msg" / f"{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
task_data = None
def change_global_task_status(cmd: str) -> str:
"""
说明:
修改全局被动任务状态
参数:
:param cmd: 功能名称
"""
global task_data
if not task_data:
task_data = group_manager.get_task_data()
status = cmd[:2]
_cmd = cmd[4:]
if '全部被动' in cmd:
for task in task_data:
if status == "开启":
group_manager.open_global_task(task)
else:
group_manager.close_global_task(task)
group_manager.save()
return f"已 {status} 全局全部被动技能!"
else:
modules = [x for x in task_data if task_data[x].lower() == _cmd.lower()]
if not modules:
return '未查询到该被动任务'
if status == "开启":
group_manager.open_global_task(modules[0])
else:
group_manager.close_global_task(modules[0])
group_manager.save()
return f"已 {status} 全局{_cmd}"
async def change_group_switch(cmd: str, group_id: int, is_super: bool = False) -> str:
"""
说明:
修改群功能状态
参数:
:param cmd: 功能名称
:param group_id: 群号
:param is_super: 是否位超级用户,超级用户用于私聊开关功能状态
"""
global task_data
if not task_data:
task_data = group_manager.get_task_data()
group_help_file = DATA_PATH / "group_help" / f"{group_id}.png"
status = cmd[:2]
cmd = cmd[2:]
type_ = "plugin"
modules = plugins2settings_manager.get_plugin_module(cmd, True)
if cmd == "全部被动":
for task in task_data:
if status == "开启":
if not group_manager.check_group_task_status(group_id, task):
group_manager.open_group_task(group_id, task)
else:
if group_manager.check_group_task_status(group_id, task):
group_manager.close_group_task(group_id, task)
if group_help_file.exists():
group_help_file.unlink()
return f"已 {status} 全部被动技能!"
if cmd == "全部功能":
for f in plugins2settings_manager.get_data():
if status == "开启":
group_manager.unblock_plugin(f, group_id, False)
else:
group_manager.block_plugin(f, group_id, False)
group_manager.save()
if group_help_file.exists():
group_help_file.unlink()
return f"已 {status} 全部功能!"
if cmd.lower() in [task_data[x].lower() for x in task_data.keys()]:
type_ = "task"
modules = [x for x in task_data.keys() if task_data[x].lower() == cmd.lower()]
for module in modules:
if is_super:
module = f"{module}:super"
if status == "开启":
if type_ == "task":
if group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
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 group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
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()
if is_super:
for file in os.listdir(DATA_PATH / "group_help"):
file = DATA_PATH / "group_help" / file
file.unlink()
else:
_help_image = DATA_PATH / "group_help" / f"{group_id}.png"
if _help_image.exists():
_help_image.unlink()
return f"{status} {cmd} 功能!"
def set_plugin_status(cmd: str, block_type: str = "all"):
"""
说明:
设置插件功能状态(超级用户使用)
参数:
:param cmd: 功能名称
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
"""
status = cmd[:2]
cmd = cmd[2:]
module = plugins2settings_manager.get_plugin_module(cmd)
if status == "开启":
plugins_manager.unblock_plugin(module)
else:
plugins_manager.block_plugin(module, block_type=block_type)
for file in os.listdir(DATA_PATH / "group_help"):
file = DATA_PATH / "group_help" / file
file.unlink()
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"
tmp_name = []
for matcher in get_matchers():
if matcher.plugin_name not in tmp_name:
tmp_name.append(matcher.plugin_name)
module = matcher.plugin_name
flag = plugins_manager.get_plugin_block_type(module)
flag = flag.upper() + " CLOSE" if flag else "OPEN"
try:
plugin_name = plugins_manager.get(module).plugin_name
if (
"[Hidden]" in plugin_name
or "[Admin]" in plugin_name
or "[Superuser]" in plugin_name
):
continue
rst += f"{plugin_name}"
except KeyError:
rst += f"{module}"
if plugins_manager.get(module).error:
rst += "[ERROR]"
rst += "\n"
flag_str += f"{flag}\n"
height = len(rst.split("\n")) * 24
a = BuildImage(250, height, font_size=20)
a.text((10, 10), rst)
b = BuildImage(200, height, font_size=20)
b.text((10, 10), flag_str)
A = BuildImage(500, height)
A.paste(a)
A.paste(b, (270, 0))
return image(b64=A.pic2bs4())
async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool:
"""
说明:
更新群成员信息
参数:
:param group_id: 群号
:param remind_superuser: 失败信息提醒超级用户
"""
bot = get_bot()
_group_user_list = await bot.get_group_member_list(group_id=group_id)
_error_member_list = []
_exist_member_list = []
# try:
for user_info in _group_user_list:
nickname = user_info["card"] or user_info["nickname"]
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"],
Config.get_config("admin_bot_manage", "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"]))
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",
)
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"]))
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))
)
)
if _del_member_list:
for del_user in _del_member_list:
if await GroupInfoUser.delete_member_info(del_user, group_id):
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
else:
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
if _error_member_list and remind_superuser:
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]
)
return True
def set_group_bot_status(group_id: int, status: bool) -> str:
"""
说明:
设置群聊bot开关状态
参数:
:param group_id: 群号
:param status: 状态
"""
if status:
if group_manager.check_group_bot_status(group_id):
return "我还醒着呢!"
group_manager.turn_on_group_bot_status(group_id)
return "呜..醒来了..."
else:
group_manager.shutdown_group_bot_status(group_id)
return "那我先睡觉了..."
+37 -38
View File
@@ -1,38 +1,37 @@
from nonebot import on_notice
from services.log import logger
from nonebot.adapters.cqhttp import Bot, GroupAdminNoticeEvent
from nonebot.typing import T_State
from models.level_user import LevelUser
from models.group_member_info import GroupInfoUser
from configs.config import Config
__zx_plugin_name__ = "群管理员变动监测 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
admin_notice = on_notice(priority=5)
@admin_notice.handle()
async def _(bot: Bot, event: GroupAdminNoticeEvent, state: T_State):
try:
nickname = (
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
).user_name
except AttributeError:
nickname = event.user_id
if event.sub_type == "set":
await LevelUser.set_level(
event.user_id,
event.group_id,
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
)
logger.info(
f"为新晋管理员 {nickname}({event.user_id}) "
f"添加权限等级:{Config.get_config('admin_bot_manage', 'ADMIN_DEFAULT_AUTH')}"
)
elif event.sub_type == "unset":
await LevelUser.delete_level(event.user_id, event.group_id)
logger.info(f"将非管理员 {nickname}({event.user_id}) 取消权限等级")
from nonebot import on_notice
from services.log import logger
from nonebot.adapters.onebot.v11 import GroupAdminNoticeEvent
from models.level_user import LevelUser
from models.group_member_info import GroupInfoUser
from configs.config import Config
__zx_plugin_name__ = "群管理员变动监测 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
admin_notice = on_notice(priority=5)
@admin_notice.handle()
async def _(event: GroupAdminNoticeEvent):
try:
nickname = (
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
).user_name
except AttributeError:
nickname = event.user_id
if event.sub_type == "set":
await LevelUser.set_level(
event.user_id,
event.group_id,
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
)
logger.info(
f"为新晋管理员 {nickname}({event.user_id}) "
f"添加权限等级:{Config.get_config('admin_bot_manage', 'ADMIN_DEFAULT_AUTH')}"
)
elif event.sub_type == "unset":
await LevelUser.delete_level(event.user_id, event.group_id)
logger.info(f"将非管理员 {nickname}({event.user_id}) 取消权限等级")
+52 -51
View File
@@ -1,51 +1,52 @@
from nonebot import on_command
from utils.utils import get_message_text, get_message_imgs
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 Config
from services.log import logger
__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": Config.get_config("admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"),
}
custom_welcome = on_command(
"自定义进群欢迎消息",
aliases={"自定义欢迎消息", "自定义群欢迎消息", "设置群欢迎消息"},
permission=GROUP,
priority=5,
block=True,
)
@custom_welcome.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
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("发生了一些未知错误...")
from typing import List
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.params import CommandArg
from ._data_source import custom_group_welcome
from nonebot.adapters.onebot.v11.permission import GROUP
from configs.config import Config
from services.log import logger
from utils.depends import ImageList
__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": Config.get_config("admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"),
}
custom_welcome = on_command(
"自定义进群欢迎消息",
aliases={"自定义欢迎消息", "自定义群欢迎消息", "设置群欢迎消息"},
permission=GROUP,
priority=5,
block=True,
)
@custom_welcome.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg(), img: List[str] = ImageList()):
msg = arg.extract_plain_text().strip()
if not msg and not img:
await custom_welcome.finish(__plugin_usage__)
try:
await custom_welcome.send(
await custom_group_welcome(msg, img, 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("发生了一些未知错误...")
@@ -1,296 +0,0 @@
from typing import List
from nonebot.adapters.cqhttp.message import MessageSegment
from services.log import logger
from configs.path_config import DATA_PATH
from utils.message_builder import image
from utils.utils import get_local_proxy, get_bot
from pathlib import Path
from models.group_member_info import GroupInfoUser
from datetime import datetime
from services.db_context import db
from models.level_user import LevelUser
from configs.config import Config
from utils.manager import group_manager, plugins2settings_manager, plugins_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
async def group_current_status(group_id: int) -> str:
"""
获取当前所有通知的开关
:param group_id: 群号
"""
rst = "[被动技能 状态]\n"
_data = group_manager.get_task_data()
for task in _data.keys():
rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n'
return rst.strip()
custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "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"))
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}")
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:
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} 更换群欢迎消息图片")
except Exception as e:
logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}")
return "替换群消息失败.."
return f"替换群欢迎消息成功:\n{result}" + img_result
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:]
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 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()
if is_super:
for file in os.listdir(Path(DATA_PATH) / 'group_help'):
file = Path(DATA_PATH) / 'group_help' / file
file.unlink()
else:
_help_image = Path(DATA_PATH) / 'group_help' / f"{group_id}.png"
if _help_image.exists():
_help_image.unlink()
return f"{status} {cmd} 功能!"
def set_plugin_status(cmd: str, block_type: str = "all"):
"""
设置插件功能状态(超级用户使用)
:param cmd: 功能名称
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
"""
status = cmd[:2]
cmd = cmd[2:]
module = plugins2settings_manager.get_plugin_module(cmd)
if status == "开启":
plugins_manager.unblock_plugin(module)
else:
plugins_manager.block_plugin(module, block_type=block_type)
for file in os.listdir(Path(DATA_PATH) / 'group_help'):
file = Path(DATA_PATH) / 'group_help' / file
file.unlink()
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 plugins_manager.get_data():
flag = plugins_manager.get_plugin_block_type(module)
flag = flag.upper() + " CLOSE" if flag else "OPEN"
try:
plugin_name = plugins_manager.get(module)["plugin_name"]
if (
"[Hidden]" in plugin_name
or "[Admin]" in plugin_name
or "[Superuser]" in plugin_name
):
continue
rst += f"{plugin_name}"
except KeyError:
rst += f"{module}"
if plugins_manager.get(module)["error"]:
rst += "[ERROR]"
rst += "\n"
flag_str += f"{flag}\n"
height = len(rst.split("\n")) * 24
a = CreateImg(250, height, font_size=20)
a.text((10, 10), rst)
b = CreateImg(200, height, font_size=20)
b.text((10, 10), flag_str)
A = CreateImg(500, height)
A.paste(a)
A.paste(b, (270, 0))
return image(b64=A.pic2bs4())
async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool:
"""
更新群成员信息
:param group_id: 群号
:param remind_superuser: 失败信息提醒超级用户
"""
bot = get_bot()
_group_user_list = await bot.get_group_member_list(group_id=group_id)
_error_member_list = []
_exist_member_list = []
# try:
for user_info in _group_user_list:
if user_info["card"] == "":
nickname = user_info["nickname"]
else:
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"],
Config.get_config("admin_bot_manage", "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"]))
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",
)
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"]))
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))
)
)
if _del_member_list:
for del_user in _del_member_list:
if await GroupInfoUser.delete_member_info(del_user, group_id):
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
else:
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
if _error_member_list and remind_superuser:
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]
)
return True
+27 -16
View File
@@ -1,39 +1,50 @@
from nonebot.adapters.cqhttp import Bot, Event
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Event
from utils.manager import group_manager, plugins2settings_manager
from utils.utils import get_message_text
from services.log import logger
import time
cmd = []
v = time.time()
def switch_rule(bot: Bot, event: Event, state: T_State) -> bool:
def switch_rule(event: Event) -> bool:
"""
检测文本是否是关闭功能命令
:param bot: pass
:param event: pass
:param state: pass
说明:
检测文本是否是关闭功能命令
参数:
:param event: pass
"""
global cmd, v
try:
if not cmd:
cmd.append('关闭全部被动')
cmd.append('开启全部被动')
if not cmd or time.time() - v > 60 * 60:
cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"]
_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]}")
cmd.append(f"开启 {_data[key]}")
cmd.append(f"关闭 {_data[key]}")
_data = plugins2settings_manager.get_data()
for key in _data:
for key in _data.keys():
try:
for x in _data[key]["cmd"]:
cmd.append(f"开启{x}")
cmd.append(f"关闭{x}")
cmd.append(f"开启 {x}")
cmd.append(f"关闭 {x}")
if isinstance(_data[key].cmd, list):
for x in _data[key].cmd:
cmd.append(f"开启{x}")
cmd.append(f"关闭{x}")
cmd.append(f"开启 {x}")
cmd.append(f"关闭 {x}")
else:
cmd.append(f"开启{key}")
cmd.append(f"关闭{key}")
cmd.append(f"开启 {key}")
cmd.append(f"关闭 {key}")
except KeyError:
pass
v = time.time()
msg = get_message_text(event.json()).split()
msg = msg[0] if msg else ""
return msg in cmd
+129 -107
View File
@@ -1,107 +1,129 @@
from nonebot import on_command, on_message
from nonebot.typing import T_State
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 NICKNAME, Config
from utils.utils import get_message_text, is_number
from nonebot.permission import SUPERUSER
from .rule import switch_rule
__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": Config.get_config("admin_bot_manage", "CHANGE_GROUP_SWITCH_LEVEL"),
"cmd": ["开启功能", "关闭功能", "开关"]
}
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)
@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}")
@plugins_status.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await plugins_status.send(await get_plugin_status())
@group_task_status.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await group_task_status.send(await group_current_status(event.group_id))
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent, GROUP, PrivateMessageEvent
from nonebot import on_command, on_message, on_regex
from nonebot.params import RegexGroup
from utils.message_builder import image
from ._data_source import (
change_group_switch,
set_plugin_status,
get_plugin_status,
group_current_status,
set_group_bot_status, change_global_task_status
)
from services.log import logger
from configs.config import NICKNAME, Config
from utils.utils import get_message_text, is_number
from nonebot.permission import SUPERUSER
from typing import Tuple, Any
from .rule import switch_rule
__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": Config.get_config("admin_bot_manage", "CHANGE_GROUP_SWITCH_LEVEL"),
"cmd": ["开启功能", "关闭功能", "开关"]
}
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)
group_status = on_regex("^(休息吧|醒来)$", permission=GROUP, priority=5, block=True)
@switch_rule_matcher.handle()
async def _(bot: Bot, event: MessageEvent):
_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 ("关闭被动" in _cmd or "开启被动" in _cmd) and isinstance(event, PrivateMessageEvent):
await switch_rule_matcher.send(change_global_task_status(_cmd))
elif is_number(block_type):
if not int(block_type) in [
g["group_id"]
for g in await bot.get_group_list()
]:
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"已{_cmd[:2]}群聊 {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}")
@plugins_status.handle()
async def _():
await plugins_status.send(await get_plugin_status())
@group_task_status.handle()
async def _(event: GroupMessageEvent):
await group_task_status.send(image(b64=await group_current_status(event.group_id)))
@group_status.handle()
async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
cmd = reg_group[0]
if cmd == "休息吧":
msg = set_group_bot_status(event.group_id, False)
else:
msg = set_group_bot_status(event.group_id, True)
await group_status.send(msg)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用总开关命令:{cmd}")
+51 -51
View File
@@ -1,51 +1,51 @@
from utils.utils import scheduler, get_bot
from .data_source import update_member_info
from services.log import logger
from models.group_info import GroupInfo
from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError
__zx_plugin_name__ = '管理方面定时任务 [Hidden]'
__plugin_usage__ = '无'
__plugin_des__ = '成员信息和管理权限的定时更新'
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
# 自动更新群员信息
@scheduler.scheduled_job(
"cron",
hour=2,
minute=1,
)
async def _():
bot = get_bot()
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}")
# 快速更新群员信息以及管理员权限
@scheduler.scheduled_job(
"interval",
minutes=5,
)
async def _():
try:
bot = get_bot()
if bot:
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
all_group = [x.group_id for x in await GroupInfo.get_all_group()]
for g in gl:
if g not in all_group:
await update_member_info(g, False)
logger.info(f"快速更新群信息以及权限:{g}")
except (IndexError, ConnectionDoesNotExistError, UndefinedColumnError):
pass
from utils.utils import scheduler, get_bot
from ._data_source import update_member_info
from services.log import logger
from models.group_info import GroupInfo
from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError
__zx_plugin_name__ = '管理方面定时任务 [Hidden]'
__plugin_usage__ = '无'
__plugin_des__ = '成员信息和管理权限的定时更新'
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
# 自动更新群员信息
@scheduler.scheduled_job(
"cron",
hour=2,
minute=1,
)
async def _():
bot = get_bot()
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}")
# 快速更新群员信息以及管理员权限
@scheduler.scheduled_job(
"interval",
minutes=5,
)
async def _():
try:
bot = get_bot()
if bot:
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
all_group = [x.group_id for x in await GroupInfo.get_all_group()]
for g in gl:
if g not in all_group:
await update_member_info(g, False)
logger.info(f"快速更新群信息以及权限:{g}")
except (IndexError, ConnectionDoesNotExistError, UndefinedColumnError):
pass
+41 -41
View File
@@ -1,41 +1,41 @@
from nonebot import on_command, on_notice
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
from .data_source import update_member_info
__zx_plugin_name__ = "更新群组成员列表 [Admin]"
__plugin_usage__ = """
usage:
更新群组成员的基本信息
指令:
更新群组成员列表/更新群组成员信息
""".strip()
__plugin_des__ = '更新群组成员列表'
__plugin_cmd__ = ['更新群组成员列表']
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"admin_level": 1,
}
refresh_member_group = on_command(
"更新群组成员列表", aliases={"更新群组成员信息"}, permission=GROUP, priority=5, block=True
)
@refresh_member_group.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if await update_member_info(event.group_id):
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)
from nonebot import on_command, on_notice
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
from ._data_source import update_member_info
__zx_plugin_name__ = "更新群组成员列表 [Admin]"
__plugin_usage__ = """
usage:
更新群组成员的基本信息
指令:
更新群组成员列表/更新群组成员信息
""".strip()
__plugin_des__ = '更新群组成员列表'
__plugin_cmd__ = ['更新群组成员列表']
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"admin_level": 1,
}
refresh_member_group = on_command(
"更新群组成员列表", aliases={"更新群组成员信息"}, permission=GROUP, priority=5, block=True
)
@refresh_member_group.handle()
async def _(event: GroupMessageEvent):
if await update_member_info(event.group_id):
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):
if event.user_id == int(bot.self_id):
await update_member_info(event.group_id)
+27 -27
View File
@@ -1,27 +1,27 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters import Bot
from nonebot.adapters.cqhttp import GroupMessageEvent
from utils.message_builder import image
from .data_source import create_help_image, admin_help_image
__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)
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'))
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters import Bot
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from utils.message_builder import image
from .data_source import create_help_image, ADMIN_HELP_IMAGE
__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)
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_IMAGE))
+87 -94
View File
@@ -1,94 +1,87 @@
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 init_task(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())} 个被动技能.')
async def create_help_image():
"""
创建管理员帮助图片
"""
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)} 条管理员命令')
import nonebot
from configs.path_config import IMAGE_PATH
from nonebot import Driver
from services.log import logger
from utils.image_template import help_template
from utils.image_utils import (BuildImage, build_sort_image, group_image,
text2image)
from utils.manager import group_manager, plugin_data_manager
from utils.manager.models import PluginType
driver: Driver = nonebot.get_driver()
background = IMAGE_PATH / "background" / "0.png"
ADMIN_HELP_IMAGE = IMAGE_PATH / "admin_help_img.png"
@driver.on_bot_connect
async def init_task():
if not group_manager.get_task_data():
group_manager.load_task()
logger.info(f"已成功加载 {len(group_manager.get_task_data())} 个被动技能.")
async def create_help_image():
"""
创建管理员帮助图片
"""
await _create_help_image()
async def _create_help_image():
"""
创建管理员帮助图片
"""
if ADMIN_HELP_IMAGE.exists():
return
plugin_data_ = plugin_data_manager.get_data()
image_list = []
task_list = []
for plugin_data in [plugin_data_[x] for x in plugin_data_]:
try:
usage = None
if plugin_data.plugin_type == PluginType.ADMIN and plugin_data.usage:
usage = await text2image(
plugin_data.usage, padding=5, color=(204, 196, 151)
)
if usage:
await usage.acircle_corner()
level = 5
if plugin_data.plugin_setting:
level = plugin_data.plugin_setting.level or level
image = await help_template(plugin_data.name + f"[{level}]", usage)
image_list.append(image)
if plugin_data.task:
for x in plugin_data.task.keys():
task_list.append(plugin_data.task[x])
except Exception as e:
logger.warning(
f"获取群管理员插件 {plugin_data.model}: {plugin_data.name} 设置失败... {type(e)}:{e}"
)
task_str = "\n".join(task_list)
task_str = "通过 开启/关闭 来控制群被动\n----------\n" + task_str
task_image = await text2image(task_str, padding=5, color=(204, 196, 151))
task_image = await help_template("被动任务", task_image)
image_list.append(task_image)
image_group, _ = group_image(image_list)
A = await build_sort_image(image_group, color="#f9f6f2", padding_top=180)
await A.apaste(
BuildImage(0, 0, font="CJGaoDeGuo.otf", plain_text="群管理员帮助", font_size=50),
(50, 30),
True,
)
await A.apaste(
BuildImage(
0,
0,
font="CJGaoDeGuo.otf",
plain_text="注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数",
font_size=30,
font_color="red",
),
(50, 90),
True,
)
await A.asave(ADMIN_HELP_IMAGE)
logger.info(f"已成功加载 {len(image_list)} 条管理员命令")
+249 -195
View File
@@ -1,195 +1,249 @@
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', # 任务储存库,在下一小节中说明
# )
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.onebot.v11 import ActionFailed
from configs.config import NICKNAME, Config
from pathlib import Path
import shutil
__zx_plugin_name__ = "定时任务相关 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {'zwa': '早晚安'}
Config.add_plugin_config(
"_task",
"DEFAULT_ZWA",
True,
help_="被动 早晚安 进群默认开关状态",
default_value=True,
)
Config.add_plugin_config(
"_backup",
"BACKUP_FLAG",
True,
help_="是否开启文件备份",
default_value=True
)
Config.add_plugin_config(
"_backup",
"BACKUP_DIR_OR_FILE",
['data/black_word', 'data/configs', 'data/statistics', 'data/word_bank', 'data/manager', 'configs'],
name="文件备份",
help_="备份的文件夹或文件",
default_value=[]
)
cx = on_message(priority=9999, block=False, rule=lambda: 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:
result = image("zao.jpg", "zhenxun")
try:
await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + 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:
result = image("sleep.jpg", "zhenxun")
try:
await bot.send_group_msg(
group_id=g, message=f"[[_task|zwa]]{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"],
1
)
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}")
# 自动备份
@scheduler.scheduled_job(
"cron",
hour=3,
minute=25,
)
async def _():
if Config.get_config("_backup", "BACKUP_FLAG"):
_backup_path = Path() / 'backup'
_backup_path.mkdir(exist_ok=True, parents=True)
for x in Config.get_config("_backup", "BACKUP_DIR_OR_FILE"):
try:
path = Path(x)
_p = _backup_path / x
if path.exists():
if path.is_dir():
if _p.exists():
shutil.rmtree(_p, ignore_errors=True)
shutil.copytree(x, _p)
else:
if _p.exists():
_p.unlink()
shutil.copy(x, _p)
logger.info(f'已完成自动备份:{x}')
except Exception as e:
logger.error(f"自动备份文件 {x} 发生错误 {type(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', # 任务储存库,在下一小节中说明
# )
Regular → Executable
+172 -197
View File
@@ -1,197 +1,172 @@
from nonebot import on_command
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, PrivateMessageEvent
from utils.utils import get_message_at, get_message_text, is_number
from configs.config import NICKNAME, Config
from nonebot.permission import SUPERUSER
from services.log import logger
__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": Config.get_config("ban", "BAN_LEVEL"),
"cmd": ['.ban', '.unban', 'ban', 'unban']
}
__plugin_configs__ = {
"BAN_LEVEL [LEVEL]": {
"value": 5,
"help": "ban/unban所需要的管理员权限等级",
"default_value": 5
}
}
ban = on_command(
".ban",
aliases={".unban", "/ban", "/unban"},
priority=5,
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())
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())
if msg:
msg = msg.split()
if len(msg) == 2:
if not is_number(msg[0].strip()) or not is_number(msg[1].strip()):
await ban.finish("参数必须是数字!", at_sender=True)
time = int(msg[0]) * 60 * 60 + int(msg[1]) * 60
else:
if not is_number(msg[0].strip()):
await ban.finish("参数必须是数字!", at_sender=True)
time = int(msg[0]) * 60 * 60
else:
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 ban.finish(
f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!",
at_sender=True,
)
if await BanUser.ban(
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} 加入{NICKNAME}的黑名单了!"
if time != -1:
result += f"将在 {time/60} 分钟后解封"
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 += " 分钟"
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 ban.finish(
f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True
)
if await BanUser.unban(qq):
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 解禁"
)
result = f"已经把 {user_name} 从黑名单中删除了!"
else:
result = f"{user_name} 不在黑名单!"
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的对象..')
from typing import Tuple, List
from configs.config import NICKNAME, Config
from models.ban_user import BanUser
from models.level_user import LevelUser
from nonebot import on_command
from nonebot.adapters.onebot.v11 import (Bot, GroupMessageEvent, Message,
MessageEvent, PrivateMessageEvent)
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from services.log import logger
from utils.depends import AtList
from utils.utils import get_message_at, is_number
from .data_source import a_ban, parse_ban_time
__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:
b了=屏蔽用户消息,相当于最上级.ban
跨群ban以及跨群b了
指令:
b了 [at/qq]
.ban [user_id] ?[小时] ?[分钟]
示例:b了 @user
示例:b了 1234567
示例:.ban 12345567
""".strip()
__plugin_des__ = "你被逮捕了!丢进小黑屋!"
__plugin_cmd__ = [".ban [at] ?[小时] ?[分钟]", ".unban [at]", "b了 [at] [_superuser]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"admin_level": Config.get_config("ban", "BAN_LEVEL"),
"cmd": [".ban", ".unban", "ban", "unban"],
}
__plugin_configs__ = {
"BAN_LEVEL [LEVEL]": {
"value": 5,
"help": "ban/unban所需要的管理员权限等级",
"default_value": 5,
}
}
ban = on_command(
".ban",
aliases={".unban", "/ban", "/unban"},
priority=5,
block=True,
)
super_ban = on_command("b了", permission=SUPERUSER, priority=5, block=True)
@ban.handle()
async def _(
bot: Bot,
event: GroupMessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
qq: List[int] = AtList()
):
cmd = cmd[0]
result = ""
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"] or user_name["nickname"]
msg = arg.extract_plain_text().strip()
time = parse_ban_time(msg)
if isinstance(time, str):
await ban.finish(time, at_sender=True)
if cmd 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 ban.finish(
f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!",
at_sender=True,
)
result = await a_ban(qq, time, user_name, event)
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 ban.finish(
f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True
)
if await BanUser.unban(qq):
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 解禁"
)
result = f"已经把 {user_name} 从黑名单中删除了!"
else:
result = f"{user_name} 不在黑名单!"
else:
await ban.finish("艾特人了吗??", at_sender=True)
await ban.send(result, at_sender=True)
@ban.handle()
async def _(
bot: Bot,
event: PrivateMessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
):
cmd = cmd[0]
msg = arg.extract_plain_text().strip()
if msg:
if str(event.user_id) in bot.config.superusers:
msg_splt = msg.split()
if is_number(msg_splt[0]):
qq = int(msg_splt[0])
msg = msg_splt[1:]
if cmd in [".ban", "/ban"]:
time = parse_ban_time(" ".join(msg))
if isinstance(time, str):
await ban.finish(time)
result = await a_ban(qq, time, str(qq), event, 9)
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: MessageEvent, arg: Message = CommandArg()):
user_name = ""
if isinstance(event, GroupMessageEvent):
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"] or user["nickname"]
else:
qq = arg.extract_plain_text().strip()
if not is_number(qq):
await super_ban.finish("对象qq必须为纯数字...")
qq = int(qq)
user_name = qq
if qq:
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的对象,可以使用at或者指定qq..")
+62
View File
@@ -0,0 +1,62 @@
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from configs.config import NICKNAME
from models.level_user import LevelUser
from utils.utils import is_number
from models.ban_user import BanUser
from services.log import logger
from typing import Union
def parse_ban_time(msg: str) -> Union[int, str]:
"""
解析ban时长
:param msg: 文本消息
"""
if not msg:
return -1
msg = msg.split()
if len(msg) == 1:
if not is_number(msg[0].strip()):
return "参数必须是数字!"
return int(msg[0]) * 60 * 60
else:
if not is_number(msg[0].strip()) or not is_number(msg[1].strip()):
return "参数必须是数字!"
return int(msg[0]) * 60 * 60 + int(msg[1]) * 60
async def a_ban(
qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None
) -> str:
"""
ban
:param qq: qq
:param time: ban时长
:param user_name: ban用户昵称
:param event: event
:param ban_level: ban级别
"""
if isinstance(event, GroupMessageEvent):
ban_level = await LevelUser.get_user_level(event.user_id, event.group_id)
if await BanUser.ban(qq, ban_level, time):
logger.info(
f"USER {event.user_id} GROUP"
f" {event.group_id if isinstance(event, GroupMessageEvent) else ''} 将 USER {qq} 封禁 时长 {time / 60} 分钟"
)
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
if time != -1:
result += f"将在 {time / 60} 分钟后解封"
else:
result += f"将在 ∞ 分钟后解封"
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 += " 分钟"
result = f"{user_name} 已在黑名单!预计 {time}后解封"
return result
+66 -59
View File
@@ -1,59 +1,66 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters import Bot, Event
from nonebot.permission import SUPERUSER
import asyncio
from utils.utils import get_message_text, get_message_imgs
from services.log import logger
from utils.message_builder import image
from utils.manager import group_manager
__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)
@broadcast.handle()
async def _(bot: Bot, event: Event, state: T_State):
msg = get_message_text(event.json())
imgs = get_message_imgs(event.json())
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
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:
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}")
from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.params import CommandArg
from utils.utils import get_message_img
from services.log import logger
from utils.message_builder import image
from utils.manager import group_manager
from configs.config import Config
import asyncio
__zx_plugin_name__ = "广播 [Superuser]"
__plugin_usage__ = """
usage:
指令:
广播- ?[消息] ?[图片]
示例:广播- 你们好!
""".strip()
__plugin_des__ = "昭告天下!"
__plugin_cmd__ = ["广播-"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"broadcast": "广播"}
Config.add_plugin_config(
"_task",
"DEFAULT_BROADCAST",
True,
help_="被动 广播 进群默认开关状态",
default_value=True,
)
broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
@broadcast.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
img_list = get_message_img(event.json())
rst = ""
for img in img_list:
rst += image(img)
gl = [
g["group_id"]
for g in await bot.get_group_list()
if group_manager.check_group_task_status(g["group_id"], "broadcast")
]
g_cnt = len(gl)
cnt = 0
error = ""
x = 0.25
for g in gl:
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(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}")
+4
View File
@@ -0,0 +1,4 @@
import nonebot
from pathlib import Path
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
+6
View File
@@ -0,0 +1,6 @@
from nonebot.adapters.onebot.v11 import Event, MessageEvent
from configs.config import Config
def rule(event: Event) -> bool:
return Config.get_config("chat_history", "FLAG") and isinstance(event, MessageEvent)
@@ -0,0 +1,39 @@
from configs.config import Config
from models.chat_history import ChatHistory
from nonebot import on_message
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from utils.depends import PlaintText
from ._rule import rule
__zx_plugin_name__ = "消息存储 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
Config.add_plugin_config(
"chat_history", "FLAG", True, help_="是否开启消息自从存储", name="消息存储", default_value=True
)
chat_history = on_message(rule=rule, priority=1, block=False)
@chat_history.handle()
async def _(event: MessageEvent, msg: str = PlaintText()):
if isinstance(event, GroupMessageEvent):
await ChatHistory.add_chat_msg(
event.user_id, event.group_id, str(event.get_message()), msg
)
else:
await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message()), msg)
# @test.handle()
# async def _(event: MessageEvent):
# print(await ChatHistory.get_user_msg(event.user_id, "private"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "private"))
# print(await ChatHistory.get_user_msg(event.user_id, "group"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "group"))
# print(await ChatHistory.get_group_msg(event.group_id))
# print(await ChatHistory.get_group_msg_count(event.group_id))
@@ -0,0 +1,114 @@
from datetime import datetime, timedelta
import pytz
from models.chat_history import ChatHistory
from models.group_member_info import GroupInfoUser
from nonebot import on_regex
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from nonebot.params import RegexGroup
from utils.image_utils import BuildImage, text2image
from utils.utils import is_number
from utils.message_builder import image
from typing import Tuple, Any
__zx_plugin_name__ = "消息统计"
__plugin_usage__ = """
usage:
发言记录统计
regex:(周|月|日)?消息排行(des|DES)?(n=[0-9]{1,2})?
指令:
消息统计?(des)?(n=?)
周消息统计?(des)?(n=?)
月消息统计?(des)?(n=?)
日消息统计?(des)?(n=?)
示例:
消息统计
消息统计des
消息统计DESn=15
消息统计n=15
""".strip()
__plugin_des__ = "发言消息排行"
__plugin_cmd__ = [
"消息统计",
"周消息统计",
"月消息统计",
"日消息统计"
]
__plugin_type__ = ("数据统计", 1)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"cmd": ["消息统计"],
}
msg_handler = on_regex(r"^(周|月|日)?消息统计(des|DES)?(n=[0-9]{1,2})?$", priority=5, block=True)
@msg_handler.handle()
async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
gid = event.group_id
date_scope = None
date, order, num = reg_group
num = num.split("=")[-1] if num else 10
if num and is_number(num) and 10 < int(num) < 50:
num = int(num)
time_now = datetime.now()
zero_today = time_now - timedelta(hours=time_now.hour, minutes=time_now.minute, seconds=time_now.second)
if date in ["日"]:
date_scope = (zero_today, time_now)
elif date in ["周"]:
date_scope = (time_now - timedelta(days=7), time_now)
elif date in ["月"]:
date_scope = (time_now - timedelta(days=30), time_now)
if rank_data := await ChatHistory.get_group_msg_rank(
gid, num, order or "DESC", date_scope
):
name = "昵称:\n\n"
num_str = "发言次数:\n\n"
idx = 1
for uid, num in rank_data:
try:
user_name = (await GroupInfoUser.get_member_info(uid, gid)).user_name
except AttributeError:
user_name = uid
name += f"\t{idx}.{user_name} \n\n"
num_str += f"\t{num}\n\n"
idx += 1
name_img = await text2image(name.strip(), padding=10, color="#f9f6f2")
num_img = await text2image(num_str.strip(), padding=10, color="#f9f6f2")
if not date_scope:
if date_scope := await ChatHistory.get_group_first_msg_datetime(gid):
date_scope = date_scope.astimezone(
pytz.timezone("Asia/Shanghai")
).replace(microsecond=0)
else:
date_scope = time_now.replace(microsecond=0)
date_str = f"日期:{date_scope} - 至今"
else:
date_str = f"日期:{date_scope[0].replace(microsecond=0)} - {date_scope[1].replace(microsecond=0)}"
date_w = BuildImage(0, 0, font_size=15).getsize(date_str)[0]
img_w = date_w if date_w > name_img.w + num_img.w else name_img.w + num_img.w
A = BuildImage(
img_w + 15,
num_img.h + 30,
color="#f9f6f2",
font="CJGaoDeGuo.otf",
font_size=15,
)
await A.atext((10, 10), date_str)
await A.apaste(name_img, (0, 30))
await A.apaste(num_img, (name_img.w, 30))
await msg_handler.send(image(b64=A.pic2bs4()))
# @test.handle()
# async def _(event: MessageEvent):
# print(await ChatHistory.get_user_msg(event.user_id, "private"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "private"))
# print(await ChatHistory.get_user_msg(event.user_id, "group"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "group"))
# print(await ChatHistory.get_group_msg(event.group_id))
# print(await ChatHistory.get_group_msg_count(event.group_id))
+207 -184
View File
@@ -1,184 +1,207 @@
from nonebot import on_notice, on_request
from configs.path_config import IMAGE_PATH, DATA_PATH
from utils.message_builder import image
from models.group_member_info import GroupInfoUser
from datetime import datetime
from services.log import logger
from nonebot.adapters.cqhttp import (
Bot,
GroupIncreaseNoticeEvent,
GroupDecreaseNoticeEvent,
)
from nonebot.adapters.cqhttp.exception import ActionFailed
from utils.manager import group_manager, plugins2settings_manager, requests_manager
from configs.config import NICKNAME
from models.group_info import GroupInfo
from utils.utils import FreqLimiter
from configs.config import Config
from pathlib import Path
import random
import os
try:
import ujson as json
except ModuleNotFoundError:
import json
__zx_plugin_name__ = "群事件处理 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"group_welcome": "进群欢迎", "refund_group_remind": "退群提醒"}
Config.add_plugin_config(
"auto_invite", "message", f"请不要未经同意就拉{NICKNAME}入群!告辞!", help_="强制拉群后进群回复的内容.."
)
Config.add_plugin_config(
"auto_invite", "flag", True, help_="被强制拉群后是否直接退出", default_value=True
)
Config.add_plugin_config(
"auto_invite", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
)
_flmt = FreqLimiter(Config.get_config("auto_invite", "welcome_msg_cd"))
# 群员增加处理
group_increase_handle = on_notice(priority=1, block=False)
# 群员减少处理
group_decrease_handle = on_notice(priority=1, block=False)
# (群管理)加群同意请求
add_group = on_request(priority=1, block=False)
@group_increase_handle.handle()
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
if event.user_id == int(bot.self_id):
group = await GroupInfo.get_group_info(event.group_id)
# 群聊不存在或被强制拉群,退出该群
if (not group or group.group_flag == 0) and Config.get_config(
"auto_invite", "flag"
):
try:
msg = Config.get_config("auto_invite", "message")
if msg:
await bot.send_group_msg(group_id=event.group_id, message=msg)
await bot.set_group_leave(group_id=event.group_id)
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"触发强制入群保护,已成功退出群聊 {event.group_id}..",
)
logger.info(f"强制拉群或未有群信息,退出群聊 {group} 成功")
requests_manager.remove_request("group", event.group_id)
except Exception as e:
logger.info(f"强制拉群或未有群信息,退出群聊 {group} 失败 e:{e}")
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"触发强制入群保护,退出群聊 {event.group_id} 失败..",
)
# 默认群功能开关
elif 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:
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']} 更新成功")
else:
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
# 群欢迎消息
if await group_manager.check_group_task_status(
event.group_id, "group_welcome"
) and _flmt.check(event.group_id):
_flmt.start_cd(event.group_id)
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
try:
operator_name = (
await GroupInfoUser.get_member_info(event.operator_id, event.group_id)
).user_name
except AttributeError:
operator_name = "None"
group = await GroupInfo.get_group_info(group_id)
group_name = group.group_name if group else ""
coffee = int(list(bot.config.superusers)[0])
await bot.send_private_msg(
user_id=coffee,
message=f"****呜..一份踢出报告****\n"
f"我被 {operator_name}({operator_id})\n"
f"踢出了 {group_name}({group_id})\n"
f"日期:{str(datetime.now()).split('.')[0]}",
)
return
if event.user_id == int(bot.self_id):
group_manager.delete_group(event.group_id)
return
try:
user_name = (
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
).user_name
except AttributeError:
user_name = str(event.user_id)
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} 删除失败")
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
from nonebot import on_notice, on_request
from configs.path_config import IMAGE_PATH, DATA_PATH
from models.level_user import LevelUser
from utils.message_builder import image
from models.group_member_info import GroupInfoUser
from datetime import datetime
from services.log import logger
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
GroupIncreaseNoticeEvent,
GroupDecreaseNoticeEvent,
)
from utils.manager import group_manager, plugins2settings_manager, requests_manager
from configs.config import NICKNAME
from models.group_info import GroupInfo
from utils.utils import FreqLimiter
from configs.config import Config
from pathlib import Path
import random
import os
import ujson as json
__zx_plugin_name__ = "群事件处理 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"group_welcome": "进群欢迎", "refund_group_remind": "退群提醒"}
Config.add_plugin_config(
"invite_manager", "message", f"请不要未经同意就拉{NICKNAME}入群!告辞!", help_="强制拉群后进群回复的内容.."
)
Config.add_plugin_config(
"invite_manager", "flag", True, help_="被强制拉群后是否直接退出", default_value=True
)
Config.add_plugin_config(
"invite_manager", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
)
Config.add_plugin_config(
"_task",
"DEFAULT_GROUP_WELCOME",
True,
help_="被动 进群欢迎 进群默认开关状态",
default_value=True,
)
Config.add_plugin_config(
"_task",
"DEFAULT_REFUND_GROUP_REMIND",
True,
help_="被动 退群提醒 进群默认开关状态",
default_value=True,
)
_flmt = FreqLimiter(Config.get_config("invite_manager", "welcome_msg_cd"))
# 群员增加处理
group_increase_handle = on_notice(priority=1, block=False)
# 群员减少处理
group_decrease_handle = on_notice(priority=1, block=False)
# (群管理)加群同意请求
add_group = on_request(priority=1, block=False)
@group_increase_handle.handle()
async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
if event.user_id == int(bot.self_id):
group = await GroupInfo.get_group_info(event.group_id)
# 群聊不存在或被强制拉群,退出该群
if (not group or group.group_flag == 0) and Config.get_config(
"invite_manager", "flag"
):
try:
msg = Config.get_config("invite_manager", "message")
if msg:
await bot.send_group_msg(group_id=event.group_id, message=msg)
await bot.set_group_leave(group_id=event.group_id)
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"触发强制入群保护,已成功退出群聊 {event.group_id}..",
)
logger.info(f"强制拉群或未有群信息,退出群聊 {group} 成功")
requests_manager.remove_request("group", event.group_id)
except Exception as e:
logger.info(f"强制拉群或未有群信息,退出群聊 {group} 失败 e:{e}")
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"触发强制入群保护,退出群聊 {event.group_id} 失败..",
)
# 默认群功能开关
elif event.group_id not in group_manager.get_data().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)
# 即刻刷新权限
for user_info in await bot.get_group_member_list(group_id=event.group_id):
if user_info["role"] in [
"owner",
"admin",
] and not await LevelUser.is_group_flag(
user_info["user_id"], event.group_id
):
await LevelUser.set_level(
user_info["user_id"],
user_info["group_id"],
Config.get_config("admin_bot_manage", "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
)
else:
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']} 更新成功")
else:
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
# 群欢迎消息
if _flmt.check(event.group_id):
_flmt.start_cd(event.group_id)
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 (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists():
img = image(DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg")
if msg or img:
msg = msg.strip() + img
msg = "\n" + msg if at_flag else msg
await group_increase_handle.send(
"[[_task|group_welcome]]" + msg, at_sender=at_flag
)
else:
await group_increase_handle.send(
"[[_task|group_welcome]]新人快跑啊!!本群现状↓(快使用自定义!)"
+ image(random.choice(os.listdir(IMAGE_PATH / "qxz")), "qxz")
)
@group_decrease_handle.handle()
async def _(bot: Bot, event: GroupDecreaseNoticeEvent):
# 被踢出群
if event.sub_type == "kick_me":
group_id = event.group_id
operator_id = event.operator_id
try:
operator_name = (
await GroupInfoUser.get_member_info(event.operator_id, event.group_id)
).user_name
except AttributeError:
operator_name = "None"
group = await GroupInfo.get_group_info(group_id)
group_name = group.group_name if group else ""
coffee = int(list(bot.config.superusers)[0])
await bot.send_private_msg(
user_id=coffee,
message=f"****呜..一份踢出报告****\n"
f"我被 {operator_name}({operator_id})\n"
f"踢出了 {group_name}({group_id})\n"
f"日期:{str(datetime.now()).split('.')[0]}",
)
return
if event.user_id == int(bot.self_id):
group_manager.delete_group(event.group_id)
return
try:
user_name = (
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
).user_name
except AttributeError:
user_name = str(event.user_id)
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} 删除失败")
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"[[_task|refund_group_remind]]{rst}")
except ActionFailed:
return
Regular → Executable
+56 -73
View File
@@ -1,73 +1,56 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import (
Bot,
MessageEvent,
GroupMessageEvent
)
from nonebot.typing import T_State
from nonebot.rule import to_me
from configs.path_config import IMAGE_PATH, DATA_PATH
from utils.message_builder import image
from .data_source import create_help_img, get_plugin_help
from utils.utils import get_message_text
from pathlib import Path
import os
__zx_plugin_name__ = "帮助"
group_help_path = Path(DATA_PATH) / "group_help"
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()
group_help_path.mkdir(exist_ok=True, parents=True)
for x in os.listdir(group_help_path):
group_help_image = group_help_path / x
group_help_image.unlink()
_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: 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(None, help_image, simple_help_image)
await _help.finish(image("help.png"))
@simple_help.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
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', '').strip()
msg = get_plugin_help(msg, is_super)
if msg:
await _help.send(image(b64=msg))
else:
await _help.send("没有此功能的帮助信息...")
else:
if isinstance(event, GroupMessageEvent):
_image_path = group_help_path / f"{event.group_id}.png"
if not _image_path.exists():
await create_help_img(event.group_id, help_image, _image_path)
await simple_help.send(image(_image_path))
else:
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(None, help_image, simple_help_image)
await _help.finish(image("simple_help.png"))
from nonebot import on_command
from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent,
GroupMessageEvent,
Message
)
from nonebot.params import CommandArg
from nonebot.rule import to_me
from configs.path_config import IMAGE_PATH, DATA_PATH
from utils.message_builder import image
from ._data_source import create_help_img, get_plugin_help
from ._utils import GROUP_HELP_PATH
import os
__zx_plugin_name__ = "帮助"
__plugin_configs__ = {
"TYPE": {"value": "normal", "help": "帮助图片样式 ['normal', 'HTML']", "default_value": "normal"}
}
simple_help_image = IMAGE_PATH / "simple_help.png"
if simple_help_image.exists():
simple_help_image.unlink()
simple_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True)
@simple_help.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
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', '').strip()
msg = get_plugin_help(msg, is_super)
if msg:
await simple_help.send(image(b64=msg))
else:
await simple_help.send("没有此功能的帮助信息...")
else:
if isinstance(event, GroupMessageEvent):
_image_path = GROUP_HELP_PATH / f"{event.group_id}.png"
if not _image_path.exists():
await create_help_img(event.group_id)
await simple_help.send(image(_image_path))
else:
if not simple_help_image.exists():
if simple_help_image.exists():
simple_help_image.unlink()
await create_help_img(None)
await simple_help.finish(image("simple_help.png"))
+14
View File
@@ -0,0 +1,14 @@
from typing import Optional, List, Any, Union, Dict
from pydantic import BaseModel
class Item(BaseModel):
plugin_name: str
sta: int
class PluginList(BaseModel):
plugin_type: str
icon: str
logo: str
items: List[Item]
+71
View File
@@ -0,0 +1,71 @@
from ._utils import HelpImageBuild
from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH
from utils.manager import (
plugins2settings_manager,
admin_manager,
)
from typing import Optional
import nonebot
random_bk_path = IMAGE_PATH / "background" / "help" / "simple_help"
background = IMAGE_PATH / "background" / "0.png"
async def create_help_img(group_id: Optional[int]):
"""
说明:
生成帮助图片
参数:
:param group_id: 群号
"""
await HelpImageBuild().build_image(group_id)
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
) or admin_manager.get_plugin_module(msg)
if module:
try:
plugin = nonebot.plugin.get_plugin(module)
metadata = plugin.metadata
if plugin:
if is_super:
result = plugin.module.__getattribute__(
"__plugin_superuser_usage__"
)
else:
result = (
metadata.usage
if metadata
else plugin.module.__getattribute__("__plugin_usage__")
)
if result:
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 = BuildImage(width, height, font_size=24)
bk = BuildImage(
width,
height,
background=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
+256
View File
@@ -0,0 +1,256 @@
import os
import random
from typing import Dict, List, Optional
from configs.config import Config
from configs.path_config import DATA_PATH, IMAGE_PATH, TEMPLATE_PATH
from utils.decorator import Singleton
from utils.image_utils import BuildImage, build_sort_image, group_image
from utils.manager import group_manager, plugin_data_manager
from utils.manager.models import PluginData, PluginType
from ._config import Item
GROUP_HELP_PATH = DATA_PATH / "group_help"
GROUP_HELP_PATH.mkdir(exist_ok=True, parents=True)
for x in os.listdir(GROUP_HELP_PATH):
group_help_image = GROUP_HELP_PATH / x
group_help_image.unlink()
BACKGROUND_PATH = IMAGE_PATH / "background" / "help" / "simple_help"
LOGO_PATH = TEMPLATE_PATH / "menu" / "res" / "logo"
@Singleton
class HelpImageBuild:
def __init__(self):
self._data: Dict[str, PluginData] = plugin_data_manager.get_data()
self._sort_data: Dict[str, List[PluginData]] = {}
self._image_list = []
self.icon2str = {
"normal": "fa fa-cog",
"原神相关": "fa fa-circle-o",
"常规插件": "fa fa-cubes",
"联系管理员": "fa fa-envelope-o",
"抽卡相关": "fa fa-credit-card-alt",
"来点好康的": "fa fa-picture-o",
"数据统计": "fa fa-bar-chart",
"一些工具": "fa fa-shopping-cart",
"商店": "fa fa-shopping-cart",
"其它": "fa fa-tags",
"群内小游戏": "fa fa-gamepad",
}
def sort_type(self):
"""
说明:
对插件按照菜单类型分类
"""
if not self._sort_data.keys():
for key in self._data.keys():
plugin_data = self._data[key]
if plugin_data.plugin_type == PluginType.NORMAL:
if not self._sort_data.get(plugin_data.menu_type[0]):
self._sort_data[plugin_data.menu_type[0]] = []
self._sort_data[plugin_data.menu_type[0]].append(self._data[key])
async def build_image(self, group_id: Optional[int]):
if group_id:
help_image = GROUP_HELP_PATH / f"{group_id}.png"
else:
help_image = IMAGE_PATH / f"simple_help.png"
build_type = Config.get_config("help", "TYPE")
if build_type == "HTML":
byt = await self.build_html_image(group_id)
with open(help_image, "wb") as f:
f.write(byt)
else:
img = await self.build_pil_image(group_id)
img.save(help_image)
async def build_html_image(self, group_id: Optional[int]) -> bytes:
from nonebot_plugin_htmlrender import template_to_pic
self.sort_type()
classify = {}
for menu in self._sort_data:
for plugin in self._sort_data[menu]:
sta = 0
if not plugin.plugin_status.status:
if group_id and plugin.plugin_status.block_type in ["all", "group"]:
sta = 2
if not group_id and plugin.plugin_status.block_type in [
"all",
"private",
]:
sta = 2
if group_id and not group_manager.get_plugin_super_status(
plugin.model, group_id
):
sta = 2
if group_id and not group_manager.get_plugin_status(
plugin.model, group_id
):
sta = 1
if classify.get(menu):
classify[menu].append(Item(plugin_name=plugin.name, sta=sta))
else:
classify[menu] = [Item(plugin_name=plugin.name, sta=sta)]
max_len = 0
flag_index = -1
max_data = None
plugin_list = []
for index, plu in enumerate(classify.keys()):
if plu in self.icon2str.keys():
icon = self.icon2str[plu]
else:
icon = "fa fa-pencil-square-o"
logo = LOGO_PATH / random.choice(os.listdir(LOGO_PATH))
data = {
"name": plu if plu != "normal" else "功能",
"items": classify[plu],
"icon": icon,
"logo": str(logo.absolute()),
}
if len(classify[plu]) > max_len:
max_len = len(classify[plu])
flag_index = index
max_data = data
plugin_list.append(data)
del plugin_list[flag_index]
plugin_list.insert(0, max_data)
pic = await template_to_pic(
template_path=str((TEMPLATE_PATH / "menu").absolute()),
template_name="zhenxun_menu.html",
templates={"plugin_list": plugin_list},
pages={
"viewport": {"width": 1903, "height": 975},
"base_url": f"file://{TEMPLATE_PATH}",
},
wait=2,
)
return pic
async def build_pil_image(self, group_id: Optional[int]) -> BuildImage:
"""
说明:
构造帮助图片
参数:
:param group_id: 群号
"""
self._image_list = []
self.sort_type()
font_size = 24
build_type = Config.get_config("help", "TYPE")
_image = BuildImage(0, 0, plain_text="1", font_size=font_size)
for idx, menu_type in enumerate(self._sort_data.keys()):
plugin_list = self._sort_data[menu_type]
wh_list = [_image.getsize(x.name) for x in plugin_list]
wh_list.append(_image.getsize(menu_type))
# sum_height = sum([x[1] for x in wh_list])
if build_type == "VV":
sum_height = 50 * len(plugin_list) + 10
else:
sum_height = (font_size + 6) * len(plugin_list) + 10
max_width = max([x[0] for x in wh_list]) + 20
bk = BuildImage(
max_width + 40,
sum_height + 50,
font_size=30,
color="#a7d1fc",
font="CJGaoDeGuo.otf",
)
title_size = bk.getsize(menu_type)
max_width = max_width if max_width > title_size[0] else title_size[0]
B = BuildImage(
max_width + 40,
sum_height,
font_size=font_size,
color="white" if not idx % 2 else "black",
)
curr_h = 10
for i, plugin_data in enumerate(plugin_list):
text_color = (255, 255, 255) if idx % 2 else (0, 0, 0)
if group_id and not group_manager.get_plugin_status(
plugin_data.model, group_id
):
text_color = (252, 75, 13)
pos = None
# 禁用状态划线
if (
not plugin_data.plugin_status.status
and plugin_data.plugin_status.block_type in ["group", "all"]
) or (group_id and not group_manager.get_plugin_super_status(
plugin_data.model, group_id
)):
w = curr_h + int(B.getsize(plugin_data.name)[1] / 2) + 2
pos = (
7,
w,
B.getsize(plugin_data.name)[0] + 35,
w,
)
if build_type == "VV":
name_image = await self.build_name_image(
max_width,
plugin_data.name,
"black" if not idx % 2 else "white",
text_color,
pos,
)
await B.apaste(
name_image, (0, curr_h), True, center_type="by_width"
)
curr_h += name_image.h + 5
else:
await B.atext(
(10, curr_h), f"{i + 1}.{plugin_data.name}", text_color
)
if pos:
await B.aline(pos, (236, 66, 7), 3)
curr_h += font_size + 5
if menu_type == "normal":
menu_type = "功能"
await bk.atext((0, 14), menu_type, center_type="by_width")
await bk.apaste(B, (0, 50))
await bk.atransparent(2)
# await bk.acircle_corner(point_list=['lt', 'rt'])
self._image_list.append(bk)
image_group, h = group_image(self._image_list)
B = await build_sort_image(
image_group,
h,
background_path=BACKGROUND_PATH,
background_handle=lambda image: image.filter("GaussianBlur", 5),
)
w = 10
h = 10
for msg in [
"目前支持的功能列表:",
"可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法",
"或者使用 ‘详细帮助’ 来获取所有功能方法",
]:
text = BuildImage(
0,
0,
plain_text=msg,
font_size=24,
font="HYWenHei-85W.ttf",
)
B.paste(text, (w, h), True)
h += 50
if msg == "目前支持的功能列表:":
w += 50
await B.apaste(
BuildImage(
0,
0,
plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护",
font_size=24,
font="HYWenHei-85W.ttf",
font_color=(231, 74, 57),
),
(300, 10),
True,
)
return B
-367
View File
@@ -1,367 +0,0 @@
from utils.image_utils import CreateImg
from configs.path_config import IMAGE_PATH
from utils.manager import (
plugins2settings_manager,
admin_manager,
plugins_manager,
group_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
import os
random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help"
background = Path(IMAGE_PATH) / "background" / "0.png"
async def create_help_img(
group_id: Optional[int], help_image: Path, simple_help_image: Path
):
"""
生成帮助图片
:param group_id: 群号
:param help_image: 图片路径
:param simple_help_image: 简易帮助图片路径
"""
return await asyncio.get_event_loop().run_in_executor(
None, _create_help_img, group_id, help_image, simple_help_image
)
def _create_help_img(
group_id: Optional[int], help_image: Path, simple_help_image: Path
):
"""
生成帮助图片
:param group_id: 群号
: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] = {
"module": matcher.module,
"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):
# 禁用flag
flag = True
if plugins_manager.get_plugin_status(
matchers_data[type_][k]["module"], "all"
):
flag = False
if group_id:
flag = flag and plugins_manager.get_plugin_status(
matchers_data[type_][k]["module"], "group"
)
simple_help_str += (
f"{i+1}.{k}<|_|~|>"
f"{group_manager.get_plugin_status(matchers_data[type_][k]['module'], group_id) if group_id else '_'}|"
f"{flag}\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.split("<|_|~|>")[0])[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",
)
# 切分,判断插件开关状态
_s_height = 10
for _s in simple_help_str.split("\n"):
text_color = (255, 255, 255) if ix % 2 else (0, 0, 0)
_line_flag = False
if "<|_|~|>" in _s:
_x = _s.split("<|_|~|>")
_flag_sp = _x[-1].split("|")
if group_id:
if _flag_sp[0].lower() != "true":
text_color = (252, 75, 13)
if _flag_sp[1].lower() == "true":
_line_flag = True
_s = _x[0]
B.text((10, _s_height), _s, text_color)
if _line_flag:
B.line(
(
7,
_s_height + int(B.getsize(_s)[1] / 2) + 2,
B.getsize(_s)[0] + 11,
_s_height + int(B.getsize(_s)[1] / 2) + 2,
),
(236, 66, 7),
3,
)
_s_height += B.getsize("1")[1] + 5
# 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
if not group_id:
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,
)
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,
font="yuanshen.ttf",
)
B.paste(text, (w, h), True)
h += 50
if msg == "目前支持的功能列表:":
w += 50
B.paste(
CreateImg(
0,
0,
plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护",
font_size=24,
font="yuanshen.ttf",
font_color=(231, 74, 57)
),
(300, 10),
True,
)
B.save(simple_help_image)
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 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 not module:
module = admin_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__")
if result:
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
Regular → Executable
+36 -38
View File
@@ -1,38 +1,36 @@
from configs.config import Config
import nonebot
Config.add_plugin_config(
"hook",
"CHECK_NOTICE_INFO_CD",
300,
name="基础hook配置",
help_="群检测,个人权限检测等各种检测提示信息cd",
default_value=300
)
Config.add_plugin_config(
"hook",
"MALICIOUS_BAN_TIME",
30,
help_="恶意命令触发检测触发后ban的时长(分钟)",
default_value=30
)
Config.add_plugin_config(
"hook",
"MALICIOUS_CHECK_TIME",
5,
help_="恶意命令触发检测规定时间内(秒)",
default_value=5
)
Config.add_plugin_config(
"hook",
"MALICIOUS_BAN_COUNT",
6,
help_="恶意命令触发检测最大触发次数",
default_value=6
)
nonebot.load_plugins("basic_plugins/hooks")
from configs.config import Config
Config.add_plugin_config(
"hook",
"CHECK_NOTICE_INFO_CD",
300,
name="基础hook配置",
help_="群检测,个人权限检测等各种检测提示信息cd",
default_value=300
)
Config.add_plugin_config(
"hook",
"MALICIOUS_BAN_TIME",
30,
help_="恶意命令触发检测触发后ban的时长(分钟)",
default_value=30
)
Config.add_plugin_config(
"hook",
"MALICIOUS_CHECK_TIME",
5,
help_="恶意命令触发检测规定时间内(秒)",
default_value=5
)
Config.add_plugin_config(
"hook",
"MALICIOUS_BAN_COUNT",
6,
help_="恶意命令触发检测最大触发次数",
default_value=6
)
+511
View File
@@ -0,0 +1,511 @@
from typing import Optional
import nonebot
from nonebot.adapters.onebot.v11 import (
GroupMessageEvent,
PrivateMessageEvent,
Bot,
Event,
MessageEvent,
Message,
PokeNotifyEvent,
)
from nonebot.exception import ActionFailed, IgnoredException
from nonebot.internal.matcher import Matcher
from models.bag_user import BagUser
from models.ban_user import BanUser
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from models.user_shop_gold_log import UserShopGoldLog
from utils.decorator import Singleton
from utils.manager import (
plugins2block_manager,
StaticData,
plugins2settings_manager,
group_manager,
admin_manager,
plugins_manager,
plugins2cd_manager,
plugins2count_manager,
)
from utils.message_builder import at
from utils.utils import FreqLimiter
from configs.config import Config
import time
ignore_rst_module = ["ai", "poke", "dialogue"]
other_limit_plugins = ["poke"]
class StatusMessageManager(StaticData):
def __init__(self):
super().__init__(None)
def add(self, id_: int):
self._data[id_] = time.time()
def delete(self, id_: int):
if self._data.get(id_):
del self._data[id_]
def check(self, id_: int, t: int = 30) -> bool:
if self._data.get(id_):
if time.time() - self._data[id_] > t:
del self._data[id_]
return True
return False
return True
status_message_manager = StatusMessageManager()
def set_block_limit_false(event, module):
"""
设置用户block为false
:param event: event
:param 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 send_msg(msg: str, bot: Bot, event: MessageEvent):
"""
说明:
发送信息
参数:
:param msg: pass
:param bot: pass
:param event: pass
"""
if "[uname]" in msg:
uname = event.sender.card or event.sender.nickname
msg = msg.replace("[uname]", uname)
if "[nickname]" in msg:
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)
msg = msg.replace("[nickname]", nickname)
if "[at]" in msg and isinstance(event, GroupMessageEvent):
msg = msg.replace("[at]", str(at(event.user_id)))
try:
if isinstance(event, GroupMessageEvent):
status_message_manager.add(event.group_id)
await bot.send_group_msg(group_id=event.group_id, message=Message(msg))
else:
status_message_manager.add(event.user_id)
await bot.send_private_msg(user_id=event.user_id, message=Message(msg))
except ActionFailed:
pass
class IsSuperuserException(Exception):
pass
@Singleton
class AuthChecker:
"""
权限检查
"""
def __init__(self):
self._flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
self._flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
self._flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
self._flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
async def auth(self, matcher: Matcher, bot: Bot, event: Event):
"""
说明:
权限检查
参数:
:param matcher: matcher
:param bot: bot
:param event: event
"""
try:
plugin_name = matcher.plugin_name
cost_gold = await self.auth_cost(plugin_name, bot, event)
if str(event.user_id) not in bot.config.superusers:
await self.auth_basic(plugin_name, bot, event)
self.auth_group(plugin_name, bot, event)
await self.auth_admin(plugin_name, matcher, bot, event)
await self.auth_plugin(plugin_name, matcher, bot, event)
await self.auth_limit(plugin_name, bot, event)
if cost_gold:
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
except IsSuperuserException:
return
async def auth_limit(self, plugin_name: str, bot: Bot, event: Event):
"""
说明:
插件限制
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
if plugins2cd_manager.check_plugin_cd_status(plugin_name):
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(plugin_name)
check_type = plugin_cd_data.check_type
limit_type = plugin_cd_data.limit_type
msg = 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(plugin_name).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(plugin_name, cd_type_):
if msg:
await send_msg(msg, bot, event)
raise IgnoredException(f"{plugin_name} 正在cd中...")
else:
plugins2cd_manager.start_cd(plugin_name, cd_type_)
# Block
if plugins2block_manager.check_plugin_block_status(plugin_name):
plugin_block_data = plugins2block_manager.get_plugin_block_data(plugin_name)
check_type = plugin_block_data.check_type
limit_type = plugin_block_data.limit_type
msg = 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_, plugin_name):
if msg:
await send_msg(msg, bot, event)
raise IgnoredException(f"{event.user_id}正在调用{plugin_name}....")
else:
plugins2block_manager.set_true(block_type_, plugin_name)
# Count
if (
plugins2count_manager.check_plugin_count_status(plugin_name)
and event.user_id not in bot.config.superusers
):
plugin_count_data = plugins2count_manager.get_plugin_count_data(plugin_name)
limit_type = plugin_count_data.limit_type
msg = plugin_count_data.rst
count_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
count_type_ = event.group_id
if not plugins2count_manager.check(plugin_name, count_type_):
if msg:
await send_msg(msg, bot, event)
raise IgnoredException(f"{plugin_name} count次数限制...")
else:
plugins2count_manager.increase(plugin_name, count_type_)
async def auth_plugin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
"""
说明:
插件状态
参数:
:param plugin_name: 模块名
:param matcher: matcher
:param bot: bot
:param event: event
"""
if plugin_name in plugins2settings_manager.keys() and matcher.priority not in [
1,
999,
]:
# 戳一戳单独判断
if (
isinstance(event, GroupMessageEvent)
or isinstance(event, PokeNotifyEvent)
or matcher.plugin_name in other_limit_plugins
):
if status_message_manager.get(event.group_id) is None:
status_message_manager.delete(event.group_id)
if plugins2settings_manager[
plugin_name
].level > group_manager.get_group_level(event.group_id):
try:
if (
self._flmt_g.check(event.user_id)
and plugin_name not in ignore_rst_module
):
self._flmt_g.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id, message="群权限不足..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("群权限不足")
# 插件状态
if not group_manager.get_plugin_status(plugin_name, event.group_id):
try:
if plugin_name not in ignore_rst_module and self._flmt_s.check(
event.group_id
):
self._flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该群未开启此功能.."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("未开启此功能...")
# 管理员禁用
if not group_manager.get_plugin_status(
f"{plugin_name}:super", event.group_id
):
try:
if (
self._flmt_s.check(event.group_id)
and plugin_name not in ignore_rst_module
):
self._flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="管理员禁用了此群该功能..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("管理员禁用了此群该功能...")
# 群聊禁用
if not plugins_manager.get_plugin_status(
plugin_name, block_type="group"
):
try:
if (
self._flmt_c.check(event.group_id)
and plugin_name not in ignore_rst_module
):
self._flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该功能在群聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("该插件在群聊中已被禁用...")
else:
# 私聊禁用
if not plugins_manager.get_plugin_status(
plugin_name, block_type="private"
):
try:
if self._flmt_c.check(event.user_id):
self._flmt_c.start_cd(event.user_id)
await bot.send_private_msg(
user_id=event.user_id, message="该功能在私聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.user_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("该插件在私聊中已被禁用...")
# 维护
if not plugins_manager.get_plugin_status(plugin_name, block_type="all"):
if isinstance(
event, GroupMessageEvent
) and group_manager.check_group_is_white(event.group_id):
raise IsSuperuserException()
try:
if isinstance(event, GroupMessageEvent):
if (
self._flmt_c.check(event.group_id)
and plugin_name not in ignore_rst_module
):
self._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 event.is_tome():
id_ = (
event.group_id
if isinstance(event, GroupMessageEvent)
else event.user_id
)
status_message_manager.add(id_)
set_block_limit_false(event, plugin_name)
raise IgnoredException("此功能正在维护...")
async def auth_admin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
"""
说明:
管理员命令 个人权限
参数:
:param plugin_name: 模块名
:param matcher: matcher
:param bot: bot
:param event: event
"""
if plugin_name in admin_manager.keys() and matcher.priority not in [1, 999]:
if isinstance(event, GroupMessageEvent):
# 个人权限
if (
not await LevelUser.check_level(
event.user_id,
event.group_id,
admin_manager.get_plugin_level(plugin_name),
)
and admin_manager.get_plugin_level(plugin_name) > 0
):
try:
if self._flmt.check(event.user_id):
self._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(plugin_name)}",
)
except ActionFailed:
pass
set_block_limit_false(event, plugin_name)
if event.is_tome():
status_message_manager.add(event.group_id)
raise IgnoredException("权限不足")
else:
if not await LevelUser.check_level(
event.user_id, 0, admin_manager.get_plugin_level(plugin_name)
):
try:
await bot.send_private_msg(
user_id=event.user_id,
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(plugin_name)}",
)
except ActionFailed:
pass
set_block_limit_false(event, plugin_name)
if event.is_tome():
status_message_manager.add(event.user_id)
raise IgnoredException("权限不足")
def auth_group(self, plugin_name: str, bot: Bot, event: Event):
"""
说明:
群黑名单检测 群总开关检测
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
if isinstance(event, GroupMessageEvent) or plugin_name in other_limit_plugins:
try:
if (
group_manager.get_group_level(event.group_id) < 0
and str(event.user_id) not in bot.config.superusers
):
raise IgnoredException("群黑名单")
if not group_manager.check_group_bot_status(event.group_id):
try:
if str(event.get_message()) != "醒来":
raise IgnoredException("功能总开关关闭状态")
except ValueError:
raise IgnoredException("功能总开关关闭状态")
except AttributeError:
pass
async def auth_basic(self, plugin_name: str, bot: Bot, event: Event):
"""
说明:
检测是否满足超级用户权限,是否被ban等
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
try:
if (
(
not isinstance(event, MessageEvent)
and plugin_name not in other_limit_plugins
)
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 plugins2settings_manager.get_plugin_data(plugin_name)
and not plugins2settings_manager.get_plugin_data(
plugin_name
).limit_superuser
):
raise IsSuperuserException()
_plugin = nonebot.plugin.get_plugin(plugin_name)
_module = _plugin.module
_plugin_name = _module.__getattribute__("__zx_plugin_name__")
if (
"[superuser]" in _plugin_name.lower()
and str(event.user_id) in bot.config.superusers
):
raise IsSuperuserException()
except AttributeError:
pass
async def auth_cost(self, plugin_name: str, bot: Bot, event: Event) -> int:
"""
说明:
检测是否满足金币条件
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
cost_gold = 0
if isinstance(event, GroupMessageEvent) and (
psm := plugins2settings_manager.get_plugin_data(plugin_name)
):
if psm.cost_gold > 0:
if (
await BagUser.get_gold(event.user_id, event.group_id)
< psm.cost_gold
):
await send_msg(f"金币不足..该功能需要{psm.cost_gold}金币..", bot, event)
raise IgnoredException(f"{plugin_name} 金币限制...")
# 当插件不阻塞超级用户时,超级用户提前扣除金币
if (
str(event.user_id) in bot.config.superusers
and not psm.limit_superuser
):
await BagUser.spend_gold(
event.user_id, event.group_id, psm.cost_gold
)
await UserShopGoldLog.add_shop_log(
event.user_id, event.group_id, 2, plugin_name, psm.cost_gold, 1
)
cost_gold = psm.cost_gold
return cost_gold
Regular → Executable
+36 -210
View File
@@ -1,210 +1,36 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.cqhttp.exception import ActionFailed
from utils.manager import (
plugins2settings_manager,
admin_manager,
group_manager,
plugins_manager,
)
from .utils import set_block_limit_false, status_message_manager
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import (
Bot,
MessageEvent,
GroupMessageEvent,
PokeNotifyEvent,
)
from configs.config import Config
from models.ban_user import BanUser
from utils.utils import FreqLimiter
from utils.message_builder import at
from models.level_user import LevelUser
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
ignore_rst_module = ["ai", "poke", "dialogue"]
# 权限检测
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
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 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_manager.get_plugin_level(module),
)
and admin_manager.get_plugin_level(module) > 0
):
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
set_block_limit_false(event, module)
if event.is_tome():
status_message_manager.add(event.group_id)
raise IgnoredException("权限不足")
else:
if not await LevelUser.check_level(
event.user_id, 0, admin_manager.get_plugin_level(module)
):
try:
await bot.send_private_msg(
user_id=event.user_id,
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}",
)
except ActionFailed:
pass
set_block_limit_false(event, module)
if event.is_tome():
status_message_manager.add(event.user_id)
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 status_message_manager.get(event.group_id) is None:
status_message_manager.delete(event.group_id)
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
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
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
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
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
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("管理员禁用了此群该功能...")
# 群聊禁用
if not plugins_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
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("该插件在群聊中已被禁用...")
else:
# 私聊禁用
if not plugins_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
if event.is_tome():
status_message_manager.add(event.user_id)
set_block_limit_false(event, module)
raise IgnoredException("该插件在私聊中已被禁用...")
# 维护
if not plugins_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 event.is_tome():
id_ = (
event.group_id
if isinstance(event, GroupMessageEvent)
else event.user_id
)
status_message_manager.add(id_)
set_block_limit_false(event, module)
raise IgnoredException("此功能正在维护...")
from typing import Optional
from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent,
Event,
)
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, run_postprocessor
from nonebot.typing import T_State
from ._utils import (
set_block_limit_false,
AuthChecker,
)
# # 权限检测
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: Event):
await AuthChecker().auth(matcher, bot, event)
# 解除命令block阻塞
@run_postprocessor
async def _(
matcher: Matcher,
exception: Optional[Exception],
bot: Bot,
event: Event,
state: T_State,
):
if not isinstance(event, MessageEvent) and matcher.plugin_name != "poke":
return
module = matcher.plugin_name
set_block_limit_false(event, module)
Regular → Executable
+97 -83
View File
@@ -1,83 +1,97 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.cqhttp.exception import ActionFailed
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import (
Bot,
MessageEvent,
GroupMessageEvent,
)
from configs.config import Config
from models.ban_user import BanUser
from utils.utils import is_number, static_flmt
from utils.message_builder import at
Config.add_plugin_config(
"hook",
"BAN_RESULT",
"才不会给你发消息.",
help_="对被ban用户发送的消息",
)
# 检查是否被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]:
if (
await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
):
time = await BanUser.check_ban_time(event.user_id)
if is_number(time):
time = abs(int(time))
if time < 60:
time = str(time) + " 秒"
else:
time = str(int(time / 60)) + " 分钟"
else:
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:
try:
ban_result = Config.get_config("hook", "BAN_RESULT")
if ban_result:
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:
try:
ban_result = Config.get_config("hook", "BAN_RESULT")
if ban_result:
await bot.send_private_msg(
user_id=event.user_id,
message=at(event.user_id)
+ ban_result
+ f" 在..在 {time}后才会理你喔",
)
except ActionFailed:
pass
raise IgnoredException("用户处于黑名单中")
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
Bot,
Event,
MessageEvent,
ActionFailed,
PokeNotifyEvent,
GroupMessageEvent,
)
from configs.config import Config
from models.ban_user import BanUser
from utils.utils import is_number, static_flmt, FreqLimiter
from utils.message_builder import at
from ._utils import ignore_rst_module, other_limit_plugins
Config.add_plugin_config(
"hook",
"BAN_RESULT",
"才不会给你发消息.",
help_="对被ban用户发送的消息",
)
_flmt = FreqLimiter(300)
# 检查是否被ban
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if hasattr(event, "user_id") and (
(
(isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent))
and matcher.priority not in [1, 999]
)
or matcher.plugin_name in other_limit_plugins
):
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 (
await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
):
time = await BanUser.check_ban_time(event.user_id)
if is_number(time):
time = abs(int(time))
if time < 60:
time = str(time) + " 秒"
else:
time = str(int(time / 60)) + " 分钟"
else:
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 != 999:
try:
ban_result = Config.get_config("hook", "BAN_RESULT")
if (
ban_result
and _flmt.check(event.user_id)
and matcher.plugin_name not in ignore_rst_module
):
_flmt.start_cd(event.user_id)
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 != 999:
try:
ban_result = Config.get_config("hook", "BAN_RESULT")
if ban_result and matcher.plugin_name not in ignore_rst_module:
await bot.send_private_msg(
user_id=event.user_id,
message=at(event.user_id)
+ ban_result
+ f" 在..在 {time}后才会理你喔",
)
except ActionFailed:
pass
raise IgnoredException("用户处于黑名单中")
+54 -54
View File
@@ -1,54 +1,54 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.cqhttp.exception import ActionFailed
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import (
Bot,
MessageEvent,
GroupMessageEvent,
)
from configs.config import Config
from models.ban_user import BanUser
from utils.utils import BanCheckLimiter
from utils.message_builder import at
from services.log import logger
_blmt = BanCheckLimiter(
Config.get_config("hook", "MALICIOUS_CHECK_TIME"),
Config.get_config("hook", "MALICIOUS_BAN_COUNT"),
)
# 恶意触发命令检测
@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 state["_prefix"]["raw_command"]:
if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
if await BanUser.ban(
event.user_id,
9,
Config.get_config("hook", "MALICIOUS_BAN_TIME") * 60,
):
logger.info(f"USER {event.user_id} 触发了恶意触发检测")
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:
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"]}')
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
MessageEvent,
GroupMessageEvent,
)
from configs.config import Config
from models.ban_user import BanUser
from utils.utils import BanCheckLimiter
from utils.message_builder import at
from services.log import logger
_blmt = BanCheckLimiter(
Config.get_config("hook", "MALICIOUS_CHECK_TIME"),
Config.get_config("hook", "MALICIOUS_BAN_COUNT"),
)
# 恶意触发命令检测
@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, 999]:
if state["_prefix"]["raw_command"]:
if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
if await BanUser.ban(
event.user_id,
9,
Config.get_config("hook", "MALICIOUS_BAN_TIME") * 60,
):
logger.info(f"USER {event.user_id} 触发了恶意触发检测")
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:
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"]}')
-146
View File
@@ -1,146 +0,0 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
from nonebot.adapters.cqhttp.exception import ActionFailed
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from utils.message_builder import at
from .utils import status_message_manager, set_block_limit_false
from utils.manager import (
plugins2cd_manager,
plugins2block_manager,
plugins2count_manager,
)
from typing import Optional
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import (
Bot,
Event,
MessageEvent,
PrivateMessageEvent,
GroupMessageEvent,
Message,
)
# 命令cd | 命令阻塞 | 命令次数
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
if not isinstance(event, MessageEvent) and matcher.module != "poke":
return
module = matcher.module
if (
isinstance(event, GroupMessageEvent)
and status_message_manager.get(event.group_id) is None
):
status_message_manager.delete(event.group_id)
# Count
if (
plugins2count_manager.check_plugin_count_status(module)
and event.user_id not in bot.config.superusers
):
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
limit_type = plugin_count_data["limit_type"]
rst = plugin_count_data["rst"]
count_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
count_type_ = event.group_id
if not plugins2count_manager.check(module, count_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} count次数限制...")
else:
plugins2count_manager.increase(module, count_type_)
# Cd
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_)
# Block
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
"""
rst = await init_rst(rst, event)
try:
if isinstance(event, GroupMessageEvent):
status_message_manager.add(event.group_id)
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
else:
status_message_manager.add(event.user_id)
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
except ActionFailed:
pass
# 解除命令block阻塞
@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
set_block_limit_false(event, 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
+43 -41
View File
@@ -1,41 +1,43 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.typing import T_State
from .utils import status_message_manager
from nonebot.adapters.cqhttp import (
Bot,
MessageEvent,
PrivateMessageEvent,
GroupMessageEvent,
)
# 为什么AI会自己和自己聊天
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_State):
if not isinstance(event, MessageEvent):
return
if event.user_id == int(bot.self_id):
raise IgnoredException("为什么AI会自己和自己聊天")
# 有命令就别说话了
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
if not isinstance(event, MessageEvent):
return
if matcher.type == "message" and matcher.module == "ai":
if (
isinstance(event, GroupMessageEvent)
and not status_message_manager.check(event.group_id)
):
status_message_manager.delete(event.group_id)
raise IgnoredException("有命令就别说话了")
elif (
isinstance(event, PrivateMessageEvent)
and not status_message_manager.check(event.user_id)
):
print(status_message_manager)
status_message_manager.delete(event.user_id)
raise IgnoredException("有命令就别说话了")
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.typing import T_State
from ._utils import status_message_manager
from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent,
PrivateMessageEvent,
GroupMessageEvent,
)
# 为什么AI会自己和自己聊天
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_State):
if not isinstance(event, MessageEvent):
return
if event.user_id == int(bot.self_id):
raise IgnoredException("为什么AI会自己和自己聊天")
# 有命令就别说话了
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
if not isinstance(event, MessageEvent):
return
if matcher.type == "message" and matcher.plugin_name == "ai":
if (
isinstance(event, GroupMessageEvent)
and not status_message_manager.check(event.group_id)
):
status_message_manager.delete(event.group_id)
raise IgnoredException("有命令就别说话了")
elif (
isinstance(event, PrivateMessageEvent)
and not status_message_manager.check(event.user_id)
):
status_message_manager.delete(event.user_id)
raise IgnoredException("有命令就别说话了")
+56
View File
@@ -0,0 +1,56 @@
from nonebot.exception import MockApiException
from nonebot.adapters.onebot.v11 import Bot, Message
from utils.manager import group_manager
from services.log import logger
from typing import Dict, Any
import re
@Bot.on_calling_api
async def _(bot: Bot, api: str, data: Dict[str, Any]):
r = None
task = None
group_id = None
try:
if (
(
(api == "send_msg" and data.get("message_type") == "group")
or api == "send_group_msg"
)
and (
(
r := re.search(
"^\[\[_task\|(.*)]]",
data["message"].strip()
if isinstance(data["message"], str)
else str(data["message"]["text"]).strip(),
)
)
or (
r := re.search(
"^&#91;&#91;_task\|(.*)&#93;&#93;",
data["message"].strip()
if isinstance(data["message"], str)
else str(data["message"]["text"]).strip(),
)
)
)
and r.group(1) in group_manager.get_task_data().keys()
):
task = r.group(1)
group_id = data["group_id"]
except Exception as e:
logger.error(f"TaskHook ERROR {type(e)}:{e}")
else:
if task and group_id:
if (
group_manager.get_group_level(group_id) < 0
or not group_manager.check_task_status(task, group_id)
):
raise MockApiException(f"被动技能 {task} 处于关闭状态...")
else:
msg = str(data["message"]).strip()
msg = msg.replace(f"&#91;&#91;_task|{task}&#93;&#93;", "").replace(
f"[[_task|{task}]]", ""
)
data["message"] = Message(msg)
-48
View File
@@ -1,48 +0,0 @@
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent
from utils.manager import plugins2block_manager, StaticData
import time
class StatusMessageManager(StaticData):
def __init__(self):
super().__init__(None)
def add(self, id_: int):
self._data[id_] = time.time()
def delete(self, id_: int):
if self._data.get(id_):
del self._data[id_]
def check(self, id_: int, t: int = 30) -> bool:
if self._data.get(id_):
if time.time() - self._data[id_] > t:
del self._data[id_]
return True
return False
return True
status_message_manager = StatusMessageManager()
def set_block_limit_false(event, module):
"""
设置用户block为false
:param event: event
:param 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)
+28 -28
View File
@@ -1,28 +1,28 @@
from nonebot.matcher import Matcher
from nonebot.message import run_postprocessor
from typing import Optional
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, Event
from utils.manager import withdraw_message_manager
import asyncio
# 消息撤回
@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))
from nonebot.matcher import Matcher
from nonebot.message import run_postprocessor
from typing import Optional
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, Event
from utils.manager import withdraw_message_manager
import asyncio
# 消息撤回
@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_)
+22 -14
View File
@@ -1,17 +1,19 @@
from configs.path_config import DATA_PATH
from .init_group_manager import init_group_manager, group_manager
from .init_plugins_config import init_plugins_config
from .init_plugins_data import init_plugins_data, plugins_manager
from .init_none_plugin_count_manager import init_none_plugin_count_manager
from .init_plugins_resources import init_plugins_resources
from .init_plugins_settings import init_plugins_settings
from .init_plugin_info import init_plugin_info
from .init_plugins_limit import (
init_plugins_block_limit,
init_plugins_count_limit,
init_plugins_cd_limit,
)
from .init import init
from .check_plugin_status import check_plugin_status
from nonebot.adapters.cqhttp import Bot
from configs.path_config import DATA_PATH
from nonebot.adapters.onebot.v11 import Bot
from services.log import logger
from nonebot import Driver
import nonebot
@@ -26,26 +28,32 @@ driver: Driver = nonebot.get_driver()
@driver.on_startup
def _():
async def _():
"""
初始化数据
"""
init_plugins_settings(DATA_PATH)
init_plugins_cd_limit(DATA_PATH)
init_plugins_block_limit(DATA_PATH)
init_plugins_count_limit(DATA_PATH)
init_plugins_data(DATA_PATH)
init_plugins_config(DATA_PATH)
config_file = DATA_PATH / "configs" / "plugins2config.yaml"
_flag = not config_file.exists()
init()
init_plugin_info()
init_plugins_settings()
init_plugins_cd_limit()
init_plugins_block_limit()
init_plugins_count_limit()
init_plugins_data()
init_plugins_config()
init_plugins_resources()
init_none_plugin_count_manager()
x = group_manager.get_super_old_data()
if x:
for key in x.keys():
plugins_manager.block_plugin(key, block_type=x[key])
# x = group_manager.get_super_old_data()
# if x:
# for key in x.keys():
# plugins_manager.block_plugin(key, block_type=x[key])
if _flag:
raise Exception("首次运行,已在configs目录下生成配置文件config.yaml,修改后重启即可...")
logger.info("初始化数据完成...")
@driver.on_bot_connect
async def _(bot: Bot):
await init_group_manager()
# await init_group_manager()
await check_plugin_status(bot)
+18 -18
View File
@@ -1,18 +1,18 @@
from utils.manager import plugins_manager
from nonebot.adapters.cqhttp import Bot
async def check_plugin_status(bot: Bot):
"""
遍历查看插件加载情况
"""
rst = ""
for plugin in plugins_manager.keys():
data = plugins_manager.get(plugin)
if data.get("error") or data.get("error") is None:
rst += f'{plugin}:{data["plugin_name"]}\n'
if rst:
rst = "以下插件加载失败..\n" + rst
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]), message=rst[:-1]
)
from utils.manager import plugins_manager
from nonebot.adapters.onebot.v11 import Bot
async def check_plugin_status(bot: Bot):
"""
遍历查看插件加载情况
"""
msg = ""
for plugin in plugins_manager.keys():
data = plugins_manager.get(plugin)
if data.error:
msg += f'{plugin}:{data.plugin_name}\n'
if msg and bot.config.superusers:
msg = "以下插件加载失败..\n" + msg
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]), message=msg.strip()
)
+14
View File
@@ -0,0 +1,14 @@
from utils.manager import plugins2settings_manager
def init():
if plugins2settings_manager.get("update_pic"):
plugins2settings_manager["update_picture"] = plugins2settings_manager["update_pic"]
plugins2settings_manager.delete("update_pic")
if plugins2settings_manager.get("white2black_img"):
plugins2settings_manager["white2black_image"] = plugins2settings_manager["white2black_img"]
plugins2settings_manager.delete("white2black_img")
if plugins2settings_manager.get("send_img"):
plugins2settings_manager["send_image"] = plugins2settings_manager["send_img"]
plugins2settings_manager.delete("send_img")
+73 -73
View File
@@ -1,73 +1,73 @@
from pathlib import Path
from utils.manager import group_manager
from services.db_context import db
from asyncpg.exceptions import DuplicateColumnError
from services.log import logger
try:
import ujson as json
except ModuleNotFoundError:
import json
try:
from models.group_remind import GroupRemind
except ModuleNotFoundError:
pass
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()
from pathlib import Path
from utils.manager import group_manager
from services.db_context import db
from asyncpg.exceptions import DuplicateColumnError
from services.log import logger
try:
import ujson as json
except ModuleNotFoundError:
import json
try:
from models.group_remind import GroupRemind
except ModuleNotFoundError:
pass
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()
+62 -45
View File
@@ -1,45 +1,62 @@
from utils.manager import (
none_plugin_count_manager,
plugins2count_manager,
plugins2cd_manager,
plugins2settings_manager,
plugins2block_manager,
plugins_manager,
resources_manager
)
from services.log import logger
from utils.utils import get_matchers
try:
import ujson as json
except ModuleNotFoundError:
import json
def init_none_plugin_count_manager():
"""
清除已删除插件数据
"""
modules = [x.module for x in get_matchers()]
for module in none_plugin_count_manager.keys():
if module not in modules:
none_plugin_count_manager.add_count(module)
else:
none_plugin_count_manager.reset(module)
if none_plugin_count_manager.check(module):
try:
plugin_name = plugins_manager.get(module)["plugin_name"]
except (AttributeError, KeyError):
plugin_name = ""
try:
plugins2settings_manager.delete(module)
plugins2count_manager.delete(module)
plugins2cd_manager.delete(module)
plugins2block_manager.delete(module)
plugins_manager.delete(module)
resources_manager.remove_resource(module)
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
except Exception as e:
logger.error(
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}"
)
from utils.manager import (
none_plugin_count_manager,
plugins2count_manager,
plugins2cd_manager,
plugins2settings_manager,
plugins2block_manager,
plugins_manager,
)
from services.log import logger
from utils.utils import get_matchers
try:
import ujson as json
except ModuleNotFoundError:
import json
def init_none_plugin_count_manager():
"""
清除已删除插件数据
"""
modules = [x.plugin_name for x in get_matchers(True)]
plugins_manager_list = list(plugins_manager.keys())
for module in plugins_manager_list:
try:
if module not in modules or none_plugin_count_manager.check(module):
try:
plugin_name = plugins_manager.get(module).plugin_name
except (AttributeError, KeyError):
plugin_name = ""
if none_plugin_count_manager.check(module):
try:
plugins2settings_manager.delete(module)
plugins2count_manager.delete(module)
plugins2cd_manager.delete(module)
plugins2block_manager.delete(module)
plugins_manager.delete(module)
plugins_manager.save()
# resources_manager.remove_resource(module)
none_plugin_count_manager.delete(module)
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
except Exception as e:
logger.exception(
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}"
)
else:
none_plugin_count_manager.add_count(module)
logger.info(
f"{module}:{plugin_name} 插件疑似已删除,"
f"加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,"
f"当前次数:{none_plugin_count_manager.get(module)}"
)
else:
none_plugin_count_manager.reset(module)
except Exception as e:
logger.error(f"清除插件数据错误 {type(e)}:{e}")
plugins2settings_manager.save()
plugins2count_manager.save()
plugins2cd_manager.save()
plugins2block_manager.save()
plugins_manager.save()
none_plugin_count_manager.save()
@@ -0,0 +1,124 @@
import random
from types import ModuleType
from typing import Any
from configs.config import Config
from services import logger
from utils.manager import (plugin_data_manager, plugins2block_manager,
plugins2cd_manager, plugins2count_manager,
plugins2settings_manager, plugins_manager)
from utils.manager.models import (Plugin, PluginBlock, PluginCd, PluginCount,
PluginData, PluginSetting, PluginType)
from utils.utils import get_matchers
def get_attr(module: ModuleType, name: str, default: Any = None) -> Any:
"""
说明:
获取属性
参数:
:param module: module
:param name: name
:param default: default
"""
return getattr(module, name) if hasattr(module, name) else default
def init_plugin_info():
for matcher in [x for x in get_matchers(True) if x.plugin]:
try:
plugin = matcher.plugin
metadata = plugin.metadata
extra = metadata.extra if metadata else {}
if hasattr(plugin, "module"):
module = plugin.module
plugin_model = matcher.plugin_name
plugin_name = (
metadata.name
if metadata and metadata.name
else get_attr(module, "__zx_plugin_name__", matcher.plugin_name)
)
if not plugin_name:
logger.warning(f"配置文件 模块:{plugin_model} 获取 plugin_name 失败...")
continue
if "[Admin]" in plugin_name:
plugin_type = PluginType.ADMIN
plugin_name = plugin_name.replace("[Admin]", "").strip()
elif "[Hidden]" in plugin_name:
plugin_type = PluginType.HIDDEN
plugin_name = plugin_name.replace("[Hidden]", "").strip()
elif "[Superuser]" in plugin_name:
plugin_type = PluginType.SUPERUSER
plugin_name = plugin_name.replace("[Superuser]", "").strip()
else:
plugin_type = PluginType.NORMAL
plugin_usage = (
metadata.usage
if metadata and metadata.usage
else get_attr(module, "__plugin_usage__")
)
plugin_des = (
metadata.description
if metadata and metadata.description
else get_attr(module, "__plugin_des__")
)
menu_type = get_attr(module, "__plugin_type__") or ("normal",)
plugin_setting = get_attr(module, "__plugin_settings__")
if plugin_setting:
plugin_setting = PluginSetting(**plugin_setting)
plugin_setting.plugin_type = menu_type
plugin_superuser_usage = get_attr(module, "__plugin_super_usage__")
plugin_task = get_attr(module, "__plugin_task__")
plugin_version = extra.get("__plugin_version__") or get_attr(
module, "__plugin_version__"
)
plugin_author = extra.get("__plugin_author__") or get_attr(
module, "__plugin_author__"
)
plugin_cd = get_attr(module, "__plugin_cd_limit__")
if plugin_cd:
plugin_cd = PluginCd(**plugin_cd)
plugin_block = get_attr(module, "__plugin_block_limit__")
if plugin_block:
plugin_block = PluginBlock(**plugin_block)
plugin_count = get_attr(module, "__plugin_count_limit__")
if plugin_count:
plugin_count = PluginCount(**plugin_count)
plugin_resources = get_attr(module, "__plugin_resources__")
plugin_configs = get_attr(module, "__plugin_configs__")
if settings := plugins2settings_manager.get(plugin_model):
plugin_setting = settings
if plugin_cd_limit := plugins2cd_manager.get(plugin_model):
plugin_cd = plugin_cd_limit
if plugin_block_limit := plugins2block_manager.get(plugin_model):
plugin_block = plugin_block_limit
if plugin_count_limit := plugins2count_manager.get(plugin_model):
plugin_count = plugin_count_limit
if plugin_cfg := Config.get(plugin_model):
plugin_configs = plugin_cfg
plugin_status = plugins_manager.get(plugin_model)
if not plugin_status:
plugin_status = Plugin(plugin_name=plugin_model)
plugin_status.author = plugin_author
plugin_status.version = plugin_version
plugin_data = PluginData(
model=plugin_model,
name=plugin_name.strip(),
plugin_type=plugin_type,
usage=plugin_usage,
superuser_usage=plugin_superuser_usage,
des=plugin_des,
task=plugin_task,
menu_type=menu_type,
plugin_setting=plugin_setting,
plugin_cd=plugin_cd,
plugin_block=plugin_block,
plugin_count=plugin_count,
plugin_resources=plugin_resources,
plugin_configs=plugin_configs,
plugin_status=plugin_status,
)
plugin_data_manager.add_plugin_info(plugin_data)
except Exception as e:
logger.error(f"构造插件数据失败 {matcher.plugin_name} - {type(e)}:{e}")
+159 -147
View File
@@ -1,147 +1,159 @@
from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import admin_manager, plugins_manager
from configs.config import Config
from services.log import logger
from utils.utils import get_matchers
from ruamel import yaml
import nonebot
_yaml = YAML(typ="safe")
def init_plugins_config(data_path):
"""
初始化插件数据配置
"""
plugins2config_file = Path(data_path) / "configs" / "plugins2config.yaml"
plugins2config_file.parent.mkdir(parents=True, exist_ok=True)
_data = {}
if plugins2config_file.exists():
_data = _yaml.load(open(plugins2config_file, "r", encoding="utf8"))
_matchers = get_matchers()
for matcher in _matchers:
_plugin = nonebot.plugin.get_plugin(matcher.module)
try:
_module = _plugin.module
except AttributeError:
continue
try:
plugin_version = _module.__getattribute__("__plugin_version__")
except AttributeError:
plugin_version = None
try:
plugin_configs = _module.__getattribute__("__plugin_configs__")
except AttributeError:
continue
# 插件配置版本更新或为Version为None或不在存储配置内
if (
plugin_version is None
or (
_data.get(matcher.module)
and _data[matcher.module].keys() != plugin_configs.keys()
)
or plugin_version > plugins_manager.get(matcher.module)["version"]
or matcher.module not in _data.keys()
):
for key in plugin_configs:
if isinstance(plugin_configs[key], dict):
Config.add_plugin_config(
matcher.module,
key,
plugin_configs[key].get("value"),
help_=plugin_configs[key].get("help"),
default_value=plugin_configs[key].get("default_value"),
_override=True,
)
else:
Config.add_plugin_config(matcher.module, key, plugin_configs[key])
else:
plugin_configs = _data[matcher.module]
for key in plugin_configs:
Config.add_plugin_config(
matcher.module,
key,
plugin_configs[key]["value"],
help_=plugin_configs[key]["help"],
default_value=plugin_configs[key]["default_value"],
_override=True,
)
if not Config.is_empty():
Config.save()
_data = round_trip_load(open(plugins2config_file, encoding="utf8"))
for plugin in _data.keys():
try:
plugin_name = plugins_manager.get(plugin)["plugin_name"]
except (AttributeError, TypeError):
plugin_name = plugin
_data[plugin].yaml_set_start_comment(plugin_name, indent=2)
# 初始化未设置的管理员权限等级
for k, v in Config.get_admin_level_data():
admin_manager.set_admin_level(k, v)
# 存完插件基本设置
with open(plugins2config_file, "w", encoding="utf8") as wf:
round_trip_dump(
_data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
# 再开始读取用户配置
user_config_file = Path() / "configs" / "config.yaml"
_data = {}
_tmp_data = {}
if user_config_file.exists():
with open(user_config_file, "r", encoding="utf8") as f:
_data = _yaml.load(f)
for plugin in Config.keys():
_tmp_data[plugin] = {}
for k in Config[plugin].keys():
if _data.get(plugin) and k in _data[plugin].keys():
Config.set_config(plugin, k, _data[plugin][k])
_tmp_data[plugin][k] = Config.get_config(plugin, k)
Config.save()
temp_file = Path() / "configs" / "temp_config.yaml"
try:
with open(temp_file, "w", encoding="utf8") as wf:
yaml.dump(
_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
with open(temp_file, "r", encoding="utf8") as rf:
_data = round_trip_load(rf)
# 添加注释
for plugin in _data.keys():
rst = ""
plugin_name = None
try:
plugin_data = Config.get(plugin)
for x in list(Config.get(plugin).keys()):
try:
_x = plugin_data[x].get("name")
if _x:
plugin_name = _x
except AttributeError:
pass
except (KeyError, AttributeError):
plugin_name = None
if not plugin_name:
try:
plugin_name = plugins_manager.get(plugin)["plugin_name"]
except (AttributeError, TypeError):
plugin_name = plugin
plugin_name = (
plugin_name.replace("[Hidden]", "")
.replace("[Superuser]", "")
.replace("[Admin]", "")
.strip()
)
rst += plugin_name + "\n"
for k in _data[plugin].keys():
rst += f'{k}: {Config[plugin][k]["help"]}' + "\n"
_data[plugin].yaml_set_start_comment(rst[:-1], indent=2)
with open(Path() / "configs" / "config.yaml", "w", encoding="utf8") as wf:
round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
except Exception as e:
logger.error(f"生成简易配置注释错误 {type(e)}:{e}")
if temp_file.exists():
temp_file.unlink()
from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import admin_manager, plugins_manager, plugin_data_manager
from configs.config import Config
from services.log import logger
from utils.text_utils import prompt2cn
from utils.utils import get_matchers
from configs.path_config import DATA_PATH
from ruamel import yaml
_yaml = YAML(typ="safe")
def init_plugins_config():
"""
初始化插件数据配置
"""
plugins2config_file = DATA_PATH / "configs" / "plugins2config.yaml"
_data = Config.get_data()
# 优先使用 metadata 数据
for matcher in get_matchers(True):
if plugin_data := plugin_data_manager.get(matcher.plugin_name):
# 插件配置版本更新或为Version为None或不在存储配置内,当使用metadata时,必定更新
if plugin_data.plugin_configs and (
isinstance(plugin_data.plugin_status.version, str)
or (
plugin_data.plugin_status.version is None
or (
_data.get(matcher.plugin_name)
and _data[matcher.plugin_name].keys()
!= plugin_data.plugin_configs.keys()
)
or plugin_data.plugin_status.version
> plugins_manager.get(matcher.plugin_name).version
or matcher.plugin_name not in _data.keys()
)
):
plugin_configs = plugin_data.plugin_configs
for key in plugin_configs:
if isinstance(plugin_data.plugin_configs[key], dict):
Config.add_plugin_config(
matcher.plugin_name,
key,
plugin_configs[key].get("value"),
help_=plugin_configs[key].get("help"),
default_value=plugin_configs[key].get("default_value"),
_override=True,
)
else:
Config.add_plugin_config(
matcher.plugin_name, key, plugin_configs[key]
)
elif plugin_configs := _data.get(matcher.plugin_name):
for key in plugin_configs:
Config.add_plugin_config(
matcher.plugin_name,
key,
plugin_configs[key]["value"],
help_=plugin_configs[key]["help"],
default_value=plugin_configs[key]["default_value"],
_override=True,
)
if not Config.is_empty():
Config.save()
_data = round_trip_load(open(plugins2config_file, encoding="utf8"))
for plugin in _data.keys():
try:
plugin_name = plugins_manager.get(plugin).plugin_name
except (AttributeError, TypeError):
plugin_name = plugin
_data[plugin].yaml_set_start_comment(plugin_name, indent=2)
# 初始化未设置的管理员权限等级
for k, v in Config.get_admin_level_data():
admin_manager.set_admin_level(k, v)
# 存完插件基本设置
with open(plugins2config_file, "w", encoding="utf8") as wf:
round_trip_dump(
_data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
_replace_config()
def _replace_config():
"""
说明:
定时任务加载的配置读取替换
"""
# 再开始读取用户配置
user_config_file = Path() / "configs" / "config.yaml"
_data = {}
_tmp_data = {}
if user_config_file.exists():
with open(user_config_file, "r", encoding="utf8") as f:
_data = _yaml.load(f)
# 数据替换
for plugin in Config.keys():
_tmp_data[plugin] = {}
for k in Config[plugin].keys():
try:
if _data.get(plugin) and k in _data[plugin].keys():
Config.set_config(plugin, k, _data[plugin][k])
if level2module := Config.get_level2module(plugin, k):
try:
admin_manager.set_admin_level(
level2module, _data[plugin][k]
)
except KeyError:
logger.warning(
f"{level2module} 设置权限等级失败:{_data[plugin][k]}"
)
_tmp_data[plugin][k] = Config.get_config(plugin, k)
except AttributeError as e:
raise AttributeError(
f"{e}\n" + prompt2cn("可能为config.yaml配置文件填写不规范", 46)
)
Config.save()
temp_file = Path() / "configs" / "temp_config.yaml"
try:
with open(temp_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
with open(temp_file, "r", encoding="utf8") as rf:
_data = round_trip_load(rf)
# 添加注释
for plugin in _data.keys():
rst = ""
plugin_name = None
try:
plugin_data = Config.get(plugin)
for x in list(Config.get(plugin).keys()):
try:
_x = plugin_data[x].get("name")
if _x:
plugin_name = _x
except AttributeError:
pass
except (KeyError, AttributeError):
plugin_name = None
if not plugin_name:
try:
plugin_name = plugins_manager.get(plugin).plugin_name
except (AttributeError, TypeError):
plugin_name = plugin
plugin_name = (
plugin_name.replace("[Hidden]", "")
.replace("[Superuser]", "")
.replace("[Admin]", "")
.strip()
)
rst += plugin_name + "\n"
for k in _data[plugin].keys():
rst += f'{k}: {Config[plugin][k]["help"]}' + "\n"
_data[plugin].yaml_set_start_comment(rst[:-1], indent=2)
with open(Path() / "configs" / "config.yaml", "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
except Exception as e:
logger.error(f"生成简易配置注释错误 {type(e)}:{e}")
if temp_file.exists():
temp_file.unlink()
+57 -82
View File
@@ -1,82 +1,57 @@
from pathlib import Path
from ruamel.yaml import YAML
from utils.manager import plugins_manager
from utils.utils import get_matchers
import nonebot
try:
import ujson as json
except ModuleNotFoundError:
import json
_yaml = YAML(typ="safe")
def init_plugins_data(data_path):
"""
初始化插件数据信息
"""
plugin2data_file = Path(data_path) / "manager" / "plugin_manager.json"
plugin2data_file.parent.mkdir(parents=True, exist_ok=True)
_data = {}
if plugin2data_file.exists():
_data = json.load(open(plugin2data_file, "r", encoding="utf8"))
_matchers = get_matchers()
for matcher in _matchers:
_plugin = nonebot.plugin.get_plugin(matcher.module)
try:
_module = _plugin.module
except AttributeError:
if matcher.module not in _data.keys():
plugins_manager.add_plugin_data(
matcher.module, matcher.module, error=True
)
else:
plugins_manager.set_module_data(matcher.module, "error", True)
plugin_data = plugins_manager.get(matcher.module)
if plugin_data:
plugins_manager.set_module_data(
matcher.module, "version", plugin_data.get("version")
)
else:
try:
plugin_version = _module.__getattribute__("__plugin_version__")
except AttributeError:
plugin_version = None
try:
plugin_name = _module.__getattribute__("__zx_plugin_name__")
except AttributeError:
plugin_name = matcher.module
try:
plugin_author = _module.__getattribute__("__plugin_author__")
except AttributeError:
plugin_author = None
if matcher.module in plugins_manager.keys():
plugins_manager.set_module_data(matcher.module, "error", False)
if matcher.module not in plugins_manager.keys():
plugins_manager.add_plugin_data(
matcher.module,
plugin_name=plugin_name,
author=plugin_author,
version=plugin_version,
)
elif plugins_manager[matcher.module]["version"] is None or (
plugin_version is not None
and plugin_version > plugins_manager[matcher.module]["version"]
):
plugins_manager.set_module_data(
matcher.module, "plugin_name", plugin_name
)
plugins_manager.set_module_data(matcher.module, "author", plugin_author)
plugins_manager.set_module_data(
matcher.module, "version", plugin_version
)
if matcher.module in _data.keys():
plugins_manager.set_module_data(
matcher.module, "error", _data[matcher.module]["error"]
)
plugins_manager.set_module_data(
matcher.module, "plugin_name", _data[matcher.module]["plugin_name"]
)
plugins_manager.save()
from ruamel.yaml import YAML
from utils.manager import plugins_manager, plugin_data_manager
from utils.utils import get_matchers
from services.log import logger
try:
import ujson as json
except ModuleNotFoundError:
import json
_yaml = YAML(typ="safe")
def init_plugins_data():
"""
初始化插件数据信息
"""
for matcher in get_matchers(True):
_plugin = matcher.plugin
if not _plugin:
continue
try:
_module = _plugin.module
except AttributeError:
if matcher.plugin_name not in plugins_manager.keys():
plugins_manager.add_plugin_data(
matcher.plugin_name, matcher.plugin_name, error=True
)
else:
plugins_manager[matcher.plugin_name].error = True
else:
if plugin_data := plugin_data_manager.get(matcher.plugin_name):
try:
plugin_version = plugin_data.plugin_status.version
plugin_name = plugin_data.name
plugin_author = plugin_data.plugin_status.author
if matcher.plugin_name in plugins_manager.keys():
plugins_manager[matcher.plugin_name].error = False
if matcher.plugin_name not in plugins_manager.keys():
plugins_manager.add_plugin_data(
matcher.plugin_name,
plugin_name=plugin_name,
author=plugin_author,
version=plugin_version,
)
elif isinstance(plugin_version, str) or plugins_manager[matcher.plugin_name].version is None or (
plugin_version is not None
and plugin_version > float(plugins_manager[matcher.plugin_name].version)
):
plugins_manager[matcher.plugin_name].plugin_name = plugin_name
plugins_manager[matcher.plugin_name].author = plugin_author
plugins_manager[matcher.plugin_name].version = plugin_version
except Exception as e:
logger.error(f"插件数据 {matcher.plugin_name} 加载发生错误 {type(e)}:{e}")
plugins_manager.save()
+64 -157
View File
@@ -1,157 +1,64 @@
from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import (
plugins2cd_manager,
plugins2block_manager,
plugins2count_manager,
)
from utils.utils import get_matchers
from ruamel import yaml
import nonebot
_yaml = YAML(typ="safe")
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)
try:
_module = _plugin.module
plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
plugins2cd_manager.add_cd_limit(
matcher.module, data_dict=plugin_cd_limit
)
except AttributeError:
pass
if not plugins2cd_manager.keys():
plugins2cd_manager.add_cd_limit(
"这是一个示例"
)
_tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()}
with open(plugins2cd_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_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, Dumper=yaml.RoundTripDumper, allow_unicode=True)
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)
try:
_module = _plugin.module
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
plugins2block_manager.add_block_limit(
matcher.module, data_dict=plugin_block_limit
)
except AttributeError:
pass
if not plugins2block_manager.keys():
plugins2block_manager.add_block_limit(
"这是一个示例"
)
_tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()}
with open(plugins2block_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2block_file, encoding="utf8"))
_data["PluginBlockLimit"].yaml_set_start_comment(
"""# 用户调用阻塞
# 即 当用户调用此功能还未结束时
# 用发送消息阻止用户重复调用此命令直到该命令结束
# key:模块名称
# status:此限制的开关状态
# check_type:'private'/'group'/'all',限制私聊/群聊/全部
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
# 示例:'user':阻塞用户,'group':阻塞群聊
# 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, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2block_manager.reload_block_limit()
def init_plugins_count_limit(data_path):
"""
加载次数限制
"""
plugins2count_file = Path(data_path) / "configs" / "plugins2count.yaml"
plugins2count_file.parent.mkdir(exist_ok=True, parents=True)
_data = {}
_matchers = get_matchers()
for matcher in _matchers:
if not plugins2count_manager.get_plugin_count_data(matcher.module):
_plugin = nonebot.plugin.get_plugin(matcher.module)
try:
_module = _plugin.module
plugin_count_limit = _module.__getattribute__("__plugin_count_limit__")
plugins2count_manager.add_count_limit(
matcher.module, data_dict=plugin_count_limit
)
except AttributeError:
pass
if not plugins2count_manager.keys():
plugins2count_manager.add_count_limit(
"这是一个示例"
)
_tmp_data = {"PluginCountLimit": plugins2count_manager.get_data()}
with open(plugins2count_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2count_file, encoding="utf8"))
_data["PluginCountLimit"].yaml_set_start_comment(
"""# 命令每日次数限制
# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
# 每日调用直到 00:00 刷新
# key:模块名称
# max_count: 每日调用上限
# status:此限制的开关状态
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
# 示例:'user':用户上限,'group':群聊上限
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(plugins2count_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2count_manager.reload_count_limit()
from utils.manager import (
plugins2cd_manager,
plugins2block_manager,
plugins2count_manager,
plugin_data_manager,
)
from utils.utils import get_matchers
from configs.path_config import DATA_PATH
def init_plugins_cd_limit():
"""
加载 cd 限制
"""
plugins2cd_file = DATA_PATH / "configs" / "plugins2cd.yaml"
plugins2cd_file.parent.mkdir(exist_ok=True, parents=True)
for matcher in get_matchers(True):
if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name) and (
plugin_data := plugin_data_manager.get(matcher.plugin_name)
):
if plugin_data.plugin_cd:
plugins2cd_manager.add_cd_limit(
matcher.plugin_name, plugin_data.plugin_cd
)
if not plugins2cd_manager.keys():
plugins2cd_manager.add_cd_limit("这是一个示例")
plugins2cd_manager.save()
plugins2cd_manager.reload_cd_limit()
def init_plugins_block_limit():
"""
加载阻塞限制
"""
for matcher in get_matchers(True):
if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name) and (
plugin_data := plugin_data_manager.get(matcher.plugin_name)
):
if plugin_data.plugin_block:
plugins2block_manager.add_block_limit(
matcher.plugin_name, plugin_data.plugin_block
)
if not plugins2block_manager.keys():
plugins2block_manager.add_block_limit("这是一个示例")
plugins2block_manager.save()
plugins2block_manager.reload_block_limit()
def init_plugins_count_limit():
"""
加载次数限制
"""
for matcher in get_matchers(True):
if not plugins2count_manager.get_plugin_count_data(matcher.plugin_name) and (
plugin_data := plugin_data_manager.get(matcher.plugin_name)
):
if plugin_data.plugin_count:
plugins2count_manager.add_count_limit(
matcher.plugin_name, plugin_data.plugin_count
)
if not plugins2count_manager.keys():
plugins2count_manager.add_count_limit("这是一个示例")
plugins2count_manager.save()
plugins2count_manager.reload_count_limit()
+25 -43
View File
@@ -1,43 +1,25 @@
from utils.manager import resources_manager
from utils.utils import get_matchers
from services.log import logger
from pathlib import Path
import nonebot
def init_plugins_resources():
"""
资源文件路径的移动
"""
_tmp = []
for matcher in get_matchers():
if matcher.module not in _tmp:
_tmp.append(matcher.module)
_plugin = nonebot.plugin.get_plugin(matcher.module)
try:
_module = _plugin.module
except AttributeError:
logger.warning(f"插件 {matcher.module} 加载失败...,资源控制未加载...")
else:
try:
resources = _module.__getattribute__("__plugin_resources__")
except AttributeError:
pass
else:
path = Path(_module.__getattribute__("__file__")).parent
for resource in resources.keys():
resources_manager.add_resource(matcher.module, (path / resource).absolute(), resources[resource])
resources_manager.save()
resources_manager.start_move()
from utils.manager import resources_manager, plugin_data_manager
from utils.utils import get_matchers
from services.log import logger
from pathlib import Path
def init_plugins_resources():
"""
资源文件路径的移动
"""
for matcher in get_matchers(True):
if plugin_data := plugin_data_manager.get(matcher.plugin_name):
try:
_module = matcher.plugin.module
except AttributeError:
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,资源控制未加载...")
else:
if resources := plugin_data.plugin_resources:
path = Path(_module.__getattribute__("__file__")).parent
for resource in resources.keys():
resources_manager.add_resource(
matcher.plugin_name, path / resource, resources[resource]
)
resources_manager.save()
resources_manager.start_move()
+42 -130
View File
@@ -1,130 +1,42 @@
from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import plugins2settings_manager, admin_manager
from services.log import logger
from utils.utils import get_matchers
from ruamel import yaml
import nonebot
_yaml = YAML(typ="safe")
def init_plugins_settings(data_path: str):
"""
初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
"""
plugins2settings_file = Path(data_path) / "configs" / "plugins2settings.yaml"
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
_matchers = get_matchers()
_data = {}
if plugins2settings_file.exists():
with open(plugins2settings_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)
try:
_module = _plugin.module
except AttributeError:
logger.warning(f"插件 {matcher.module} 加载失败...,插件控制未加载.")
else:
try:
plugin_name = _module.__getattribute__("__zx_plugin_name__")
if "[admin]" in plugin_name.lower():
try:
admin_settings = _module.__getattribute__(
"__plugin_settings__"
)
level = admin_settings["admin_level"]
cmd = admin_settings.get("cmd")
except (AttributeError, KeyError):
level = 5
cmd = None
if not level:
level = 5
admin_manager.add_admin_plugin_settings(
matcher.module, cmd, 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(plugins2settings_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2settings_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(plugins2settings_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")
from utils.manager import plugins2settings_manager, admin_manager, plugin_data_manager
from services.log import logger
from utils.manager.models import PluginType
from utils.utils import get_matchers
import nonebot
def init_plugins_settings():
"""
初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
"""
for x in plugins2settings_manager.keys():
try:
_plugin = nonebot.plugin.get_plugin(x)
_module = _plugin.module
_module.__getattribute__("__zx_plugin_name__")
except (KeyError, AttributeError) as e:
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
for matcher in get_matchers(True):
try:
if matcher.plugin_name not in plugins2settings_manager.keys():
_plugin = matcher.plugin
try:
_module = _plugin.module
except AttributeError:
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
else:
if plugin_data := plugin_data_manager.get(matcher.plugin_name):
if plugin_settings := plugin_data.plugin_setting:
# 管理员命令
if plugin_data.plugin_type == PluginType.ADMIN:
admin_manager.add_admin_plugin_settings(
matcher.plugin_name, plugin_settings.cmd, plugin_settings.level
)
else:
plugins2settings_manager.add_plugin_settings(
matcher.plugin_name, plugin_settings
)
except Exception as e:
logger.error(f'{matcher.plugin_name} 初始化 plugin_settings 发生错误 {type(e)}:{e}')
plugins2settings_manager.save()
logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")
+149 -150
View File
@@ -1,150 +1,149 @@
from nonebot import on_request, on_message
from nonebot.adapters.cqhttp import (
Bot,
FriendRequestEvent,
GroupRequestEvent,
MessageEvent,
)
from models.friend_user import FriendUser
from datetime import datetime
from configs.config import NICKNAME, Config
from nonebot.adapters.cqhttp.exception import ActionFailed
from utils.manager import requests_manager
from models.group_info import GroupInfo
from utils.utils import scheduler
import asyncio
import time
import re
__zx_plugin_name__ = "好友群聊处理请求 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_configs__ = {
"AUTO_ADD_FRIEND": {"value": False, "help": "是否自动同意好友添加", "default_value": False}
}
friend_req = on_request(priority=5, block=True)
group_req = on_request(priority=5, block=True)
x = on_message(priority=5, block=False)
exists_data = {"private": {}, "group": {}}
@friend_req.handle()
async def _(bot: Bot, event: FriendRequestEvent, state: dict):
print(event)
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"]
sex = user["sex"]
age = str(user["age"])
comment = event.comment
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份好友申请*****\n"
f"昵称:{nickname}({event.user_id})\n"
f"自动同意:{'√' if Config.get_config('auto_invite', 'AUTO_ADD_FRIEND') else '×'}\n"
f"日期:{str(datetime.now()).split('.')[0]}\n"
f"备注:{event.comment}",
)
if Config.get_config("auto_invite", "AUTO_ADD_FRIEND"):
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.add_friend_info(user["user_id"], user["nickname"])
else:
requests_manager.add_request(
event.user_id,
"private",
event.flag,
nickname=nickname,
sex=sex,
age=age,
comment=comment,
)
@group_req.handle()
async def _(bot: Bot, event: GroupRequestEvent, state: dict):
global exists_data
if event.sub_type == "invite":
if str(event.user_id) in bot.config.superusers:
try:
await bot.set_group_add_request(
flag=event.flag, sub_type="invite", approve=True
)
if await GroupInfo.get_group_info(event.group_id):
await GroupInfo.set_group_flag(event.group_id, 1)
else:
group_info = await bot.get_group_info(group_id=event.group_id)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
except ActionFailed:
pass
else:
user = await bot.get_stranger_info(user_id=event.user_id)
sex = user["sex"]
age = str(user["age"])
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"
"等待管理员处理吧!",
)
requests_manager.add_request(
event.user_id,
"group",
event.flag,
invite_group=event.group_id,
nickname=nickname,
sex=sex,
age=age,
)
@x.handle()
async def _(bot: Bot, event: MessageEvent, state: dict):
await asyncio.sleep(0.1)
r = re.search(r'groupcode="(.*?)"', str(event.get_message()))
if r:
group_id = int(r.group(1))
else:
return
r = re.search(r'groupname="(.*?)"', str(event.get_message()))
if r:
group_name = r.group(1)
else:
group_name = "None"
requests_manager.set_group_name(group_name, group_id)
@scheduler.scheduled_job(
"interval",
minutes=5,
)
async def _():
global exists_data
exists_data = {"private": {}, "group": {}}
from nonebot import on_request, on_message
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
FriendRequestEvent,
GroupRequestEvent,
MessageEvent,
)
from models.friend_user import FriendUser
from datetime import datetime
from configs.config import NICKNAME, Config
from utils.manager import requests_manager
from models.group_info import GroupInfo
from utils.utils import scheduler
import asyncio
import time
import re
__zx_plugin_name__ = "好友群聊处理请求 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_configs__ = {
"AUTO_ADD_FRIEND": {"value": False, "help": "是否自动同意好友添加", "default_value": False}
}
friend_req = on_request(priority=5, block=True)
group_req = on_request(priority=5, block=True)
x = on_message(priority=999, block=False, rule=lambda: False)
exists_data = {"private": {}, "group": {}}
@friend_req.handle()
async def _(bot: Bot, event: FriendRequestEvent):
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"]
sex = user["sex"]
age = str(user["age"])
comment = event.comment
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份好友申请*****\n"
f"昵称:{nickname}({event.user_id})\n"
f"自动同意:{'√' if Config.get_config('invite_manager', 'AUTO_ADD_FRIEND') else '×'}\n"
f"日期:{str(datetime.now()).split('.')[0]}\n"
f"备注:{event.comment}",
)
if Config.get_config("invite_manager", "AUTO_ADD_FRIEND"):
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.add_friend_info(user["user_id"], user["nickname"])
else:
requests_manager.add_request(
event.user_id,
"private",
event.flag,
nickname=nickname,
sex=sex,
age=age,
comment=comment,
)
@group_req.handle()
async def _(bot: Bot, event: GroupRequestEvent):
global exists_data
if event.sub_type == "invite":
if str(event.user_id) in bot.config.superusers:
try:
if await GroupInfo.get_group_info(event.group_id):
await GroupInfo.set_group_flag(event.group_id, 1)
else:
group_info = await bot.get_group_info(group_id=event.group_id)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
await bot.set_group_add_request(
flag=event.flag, sub_type="invite", approve=True
)
except ActionFailed:
pass
else:
user = await bot.get_stranger_info(user_id=event.user_id)
sex = user["sex"]
age = str(user["age"])
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"
"等待管理员处理吧!",
)
requests_manager.add_request(
event.user_id,
"group",
event.flag,
invite_group=event.group_id,
nickname=nickname,
sex=sex,
age=age,
)
@x.handle()
async def _(event: MessageEvent):
await asyncio.sleep(0.1)
r = re.search(r'groupcode="(.*?)"', str(event.get_message()))
if r:
group_id = int(r.group(1))
else:
return
r = re.search(r'groupname="(.*?)"', str(event.get_message()))
if r:
group_name = r.group(1)
else:
group_name = "None"
requests_manager.set_group_name(group_name, group_id)
@scheduler.scheduled_job(
"interval",
minutes=5,
)
async def _():
global exists_data
exists_data = {"private": {}, "group": {}}
Regular → Executable
+207 -194
View File
@@ -1,194 +1,207 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, PrivateMessageEvent
from nonebot.rule import to_me
from utils.utils import get_message_text
from models.group_member_info import GroupInfoUser
from models.friend_user import FriendUser
import random
from models.ban_user import BanUser
from services.log import logger
from configs.config import NICKNAME
__zx_plugin_name__ = "昵称系统"
__plugin_usage__ = f"""
usage:
个人昵称系统,群聊 与 私聊 昵称相互独立
指令:
以后叫我 [昵称]
{NICKNAME}我是谁
""".strip()
__plugin_des__ = "区区昵称,才不想叫呢!"
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
nickname = on_command(
"nickname",
aliases={"以后叫我", "以后请叫我", "称呼我", "以后请称呼我", "以后称呼我", "叫我", "请叫我"},
rule=to_me(),
priority=5,
block=True,
)
my_nickname = on_command(
"my_name", aliases={"我叫什么", "我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
)
cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=True)
@nickname.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg = get_message_text(event.json())
if not msg:
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
if len(msg) > 10:
await nickname.finish("昵称可不能超过10个字!", at_sender=True)
if await GroupInfoUser.set_group_member_nickname(
event.user_id, event.group_id, msg
):
if len(msg) < 5:
if random.random() < 0.5:
msg = "~".join(msg)
await nickname.send(
random.choice(
[
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住的{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
)
)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}")
else:
await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True)
logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败")
@nickname.handle()
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
msg = get_message_text(event.json())
if not msg:
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
if len(msg) > 10:
await nickname.finish("不要超过10个字!", at_sender=True)
if await FriendUser.set_friend_nickname(event.user_id, msg):
await nickname.send(
random.choice(
[
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住的{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
)
)
logger.info(f"USER {event.user_id} 设置昵称 {msg}")
else:
await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True)
logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败")
@my_nickname.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
try:
nickname_ = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
except AttributeError:
nickname_ = ""
if nickname_:
await my_nickname.send(
random.choice(
[
f"我肯定记得你啊,你是{nickname_}啊",
f"我不会忘记你的,你也不要忘记我!{nickname_}",
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
f"嗯?你是失忆了嘛...{nickname_}..",
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
f"哎?{nickname_}..怎么了吗..突然这样问..",
]
)
)
else:
nickname_ = event.sender.card if event.sender.card else event.sender.nickname
await my_nickname.send(
random.choice(
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
).format(nickname_)
)
@my_nickname.handle()
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
if nickname_:
await my_nickname.send(
random.choice(
[
f"我肯定记得你啊,你是{nickname_}啊",
f"我不会忘记你的,你也不要忘记我!{nickname_}",
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
f"嗯?你是失忆了嘛...{nickname_}..",
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
f"哎?{nickname_}..怎么了吗..突然这样问..",
]
)
)
else:
nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"]
await my_nickname.send(
random.choice(
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
).format(nickname_)
)
@cancel_nickname.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
nickname_ = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
if nickname_:
await cancel_nickname.send(
random.choice(
[
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
f"窝知道了..{nickname_}..",
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
f"可..可恶!{nickname_}!太可恶了!呜",
]
)
)
await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "")
await BanUser.ban(event.user_id, 9, 60)
else:
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
@cancel_nickname.handle()
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
if nickname_:
await cancel_nickname.send(
random.choice(
[
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
f"窝知道了..{nickname_}..",
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
f"可..可恶!{nickname_}!太可恶了!呜",
]
)
)
await FriendUser.get_user_name(event.user_id)
await BanUser.ban(event.user_id, 9, 60)
else:
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message, MessageEvent
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.rule import to_me
from models.group_member_info import GroupInfoUser
from models.friend_user import FriendUser
from models.ban_user import BanUser
from services.log import logger
from configs.config import NICKNAME, Config
from nonebot.params import CommandArg
import random
__zx_plugin_name__ = "昵称系统"
__plugin_usage__ = f"""
usage:
个人昵称系统,群聊 与 私聊 昵称相互独立
指令:
以后叫我 [昵称]
{NICKNAME}我是谁
""".strip()
__plugin_des__ = "区区昵称,才不想叫呢!"
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["昵称", "昵称系统"],
}
__plugin_configs__ = {
"BLACK_WORD": {
"value": ["爸", "爹", "爷", "父亲"],
"help": "昵称所屏蔽的关键词,会被替换为 *",
"default_value": None
}
}
nickname = on_command(
"nickname",
aliases={"以后叫我", "以后请叫我", "称呼我", "以后请称呼我", "以后称呼我", "叫我", "请叫我"},
rule=to_me(),
priority=5,
block=True,
)
my_nickname = on_command(
"my_name", aliases={"我叫什么", "我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
)
cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=True)
@nickname.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if not msg:
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
if len(msg) > 10:
await nickname.finish("昵称可不能超过10个字!", at_sender=True)
if msg in bot.config.superusers:
await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True)
_tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
for x in msg:
_tmp += "*" if x in black_word else x
msg = _tmp
if isinstance(event, GroupMessageEvent):
if await GroupInfoUser.set_group_member_nickname(
event.user_id, event.group_id, msg
):
if len(msg) < 5:
if random.random() < 0.3:
msg = "~".join(msg)
await nickname.send(
random.choice(
[
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
)
)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}")
else:
await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True)
logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败")
else:
if await FriendUser.set_friend_nickname(event.user_id, msg):
await nickname.send(
random.choice(
[
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
)
)
logger.info(f"USER {event.user_id} 设置昵称 {msg}")
else:
await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True)
logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败")
@my_nickname.handle()
async def _(event: GroupMessageEvent):
try:
nickname_ = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
except AttributeError:
nickname_ = ""
if nickname_:
await my_nickname.send(
random.choice(
[
f"我肯定记得你啊,你是{nickname_}啊",
f"我不会忘记你的,你也不要忘记我!{nickname_}",
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
f"嗯?你是失忆了嘛...{nickname_}..",
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
f"哎?{nickname_}..怎么了吗..突然这样问..",
]
)
)
else:
nickname_ = event.sender.card or event.sender.nickname
await my_nickname.send(
random.choice(
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
).format(nickname_)
)
@my_nickname.handle()
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
if nickname_:
await my_nickname.send(
random.choice(
[
f"我肯定记得你啊,你是{nickname_}啊",
f"我不会忘记你的,你也不要忘记我!{nickname_}",
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
f"嗯?你是失忆了嘛...{nickname_}..",
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
f"哎?{nickname_}..怎么了吗..突然这样问..",
]
)
)
else:
nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"]
await my_nickname.send(
random.choice(
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
).format(nickname_)
)
@cancel_nickname.handle()
async def _(event: GroupMessageEvent):
nickname_ = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
if nickname_:
await cancel_nickname.send(
random.choice(
[
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
f"窝知道了..{nickname_}..",
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
f"可..可恶!{nickname_}!太可恶了!呜",
]
)
)
await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "")
await BanUser.ban(event.user_id, 9, 60)
else:
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
@cancel_nickname.handle()
async def _(event: PrivateMessageEvent):
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
if nickname_:
await cancel_nickname.send(
random.choice(
[
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
f"窝知道了..{nickname_}..",
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
f"可..可恶!{nickname_}!太可恶了!呜",
]
)
)
await FriendUser.get_user_name(event.user_id)
await BanUser.ban(event.user_id, 9, 60)
else:
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
+68
View File
@@ -0,0 +1,68 @@
from nonebot import on_command, on_regex
from .data_source import show_plugin_repo, install_plugin, uninstall_plugin, download_json
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import CommandArg
from utils.message_builder import image
from nonebot.permission import SUPERUSER
__zx_plugin_name__ = "插件商店 [Superuser]"
__plugin_usage__ = """
usage:
下载安装插件
指令:
查看插件仓库
更新插件仓库
安装插件 [name/id] (重新安装等同于更新)
卸载插件 [name/id]
""".strip()
__plugin_des__ = "从真寻适配仓库中下载插件"
__plugin_cmd__ = ["查看插件仓库", "更新插件仓库", "安装插件 [name/id]", "卸载插件 [name/id]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
show_repo = on_regex("^查看插件仓库$", priority=1, block=True, permission=SUPERUSER)
update_repo = on_regex("^更新插件仓库$", priority=1, block=True, permission=SUPERUSER)
install_plugin_matcher = on_command("安装插件", priority=1, block=True, permission=SUPERUSER)
uninstall_plugin_matcher = on_command("卸载插件", priority=1, block=True, permission=SUPERUSER)
@install_plugin_matcher.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
arg = arg.extract_plain_text().strip()
msg = await install_plugin(arg)
await install_plugin_matcher.send(msg)
@uninstall_plugin_matcher.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
arg = arg.extract_plain_text().strip()
msg = await uninstall_plugin(arg)
await install_plugin_matcher.send(msg)
@update_repo.handle()
async def _(bot: Bot, event: MessageEvent):
code = await download_json()
if code == 200:
await update_repo.finish("更新插件仓库信息成功!")
await update_repo.send("更新插件仓库信息失败!")
@show_repo.handle()
async def _(bot: Bot, event: MessageEvent):
msg = await show_plugin_repo()
if isinstance(msg, int):
await show_repo.finish("文件下载失败或解压失败..")
await show_repo.send(image(b64=msg))
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看插件仓库"
)
+199
View File
@@ -0,0 +1,199 @@
import os
import shutil
import zipfile
from pathlib import Path
from typing import Union, Tuple
from utils.manager import plugins_manager
import ujson as json
from services import logger
from utils.http_utils import AsyncHttpx
from configs.path_config import TEMP_PATH, DATA_PATH
from utils.image_utils import text2image, BuildImage
from utils.utils import is_number
path = DATA_PATH / "plugin_shop"
if not path.exists():
path.mkdir(parents=True, exist_ok=True)
repo_json_url = "https://github.com/zhenxun-org/nonebot_plugins_zhenxun_bot/archive/refs/heads/index.zip"
repo_zip_path = TEMP_PATH / "plugin_repo_json.zip"
plugin_json = path / "zhenxun_plugins.json"
extensive_plugin_path = Path() / "extensive_plugin"
path = DATA_PATH / "plugin_shop"
if not path.exists():
path.mkdir(parents=True, exist_ok=True)
if not extensive_plugin_path.exists():
extensive_plugin_path.mkdir(parents=True, exist_ok=True)
data = {}
async def install_plugin(name: str) -> str:
"""
安装插件
:param name: 插件名或下标
"""
try:
if is_number(name):
name, code = await get_plugin_name(int(name))
if code != 200:
return name
plugin_url = data[name]["download_url"]
url = (await AsyncHttpx.get(plugin_url)).headers.get("Location")
zip_file = TEMP_PATH / f"{name}.zip"
if zip_file.exists():
zip_file.unlink()
if await AsyncHttpx.download_file(url, zip_file):
logger.debug("开始解压插件压缩包...")
# 解压
zf = zipfile.ZipFile(zip_file, "r")
extract_path = TEMP_PATH / f"{name}"
if extract_path.exists():
shutil.rmtree(extract_path.absolute(), ignore_errors=True)
extract_path.mkdir(exist_ok=True, parents=True)
for file in zf.namelist():
zf.extract(file, extract_path)
zf.close()
logger.debug("解压插件压缩包完成...")
logger.debug("开始移动插件文件夹...")
if (extensive_plugin_path / f"{name}").exists():
logger.debug("extensive_plugin目录下文件夹已存在,删除该目录插件文件夹...")
shutil.rmtree(
(extensive_plugin_path / f"{name}").absolute(), ignore_errors=True
)
extract_path.rename(extensive_plugin_path / f"{name}")
tmp = ""
if "pyproject.toml" in os.listdir(extensive_plugin_path / f"{name}"):
tmp = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
os.system(
f"poetry run pip install -r {(extensive_plugin_path / f'{name}' / 'pyproject.toml').absolute()}"
)
elif "requirements.txt" in os.listdir(extensive_plugin_path / f"{name}"):
tmp = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
os.system(
f"poetry run pip install -r {(extensive_plugin_path / f'{name}' / 'requirements.txt').absolute()}"
)
with open(extensive_plugin_path / f"{name}" / "plugin_info.json", "w") as f:
json.dump(data[name], f, ensure_ascii=False, indent=4)
logger.debug("移动插件文件夹完成...")
logger.info(f"成功安装插件 {name} 成功!\n{tmp}")
return f"成功安装插件 {name},请重启真寻!"
except Exception as e:
logger.error(f"安装插件 {name} 失败 {type(e)}:{e}")
return f"安装插件 {name} 失败 {type(e)}:{e}"
async def uninstall_plugin(name: str) -> str:
"""
删除插件
:param name: 插件名或下标
"""
try:
if is_number(name):
name, code = await get_plugin_name(int(name))
if code != 200:
return name
if name not in os.listdir(extensive_plugin_path):
return f"未安装 {name} 插件!"
shutil.rmtree((extensive_plugin_path / name).absolute(), ignore_errors=True)
logger.info(f"插件 {name} 删除成功!")
return f"插件 {name} 删除成功!"
except Exception as e:
logger.error(f"删除插件 {name} 失败 {type(e)}:{e}")
return f"删除插件 {name} 失败 {type(e)}:{e}"
async def show_plugin_repo() -> Union[int, str]:
"""
获取插件仓库数据并格式化
"""
if not plugin_json.exists():
code = await download_json()
if code != 200:
return code
plugin_info = json.load(open(plugin_json, "r", encoding="utf8"))
plugins_data = plugins_manager.get_data()
load_plugin_list = plugins_data.keys()
image_list = []
w, h = 0, 0
line_height = 10
for i, key in enumerate(plugin_info.keys()):
data[key] = {
"名称": plugin_info[key]["plugin_name"],
"模块": key,
"作者": plugin_info[key]["author"],
"版本": plugin_info[key]["version"],
"简介": plugin_info[key]["introduction"],
"download_url": plugin_info[key]["download_url"],
"github_url": plugin_info[key]["github_url"],
}
status = ""
version = ""
if key in load_plugin_list:
status = "<f font_color=#1a7e30>[已安装]</f>"
version = f"<f font_color=#1a7e30>[{plugins_data[key].version}]</f>"
s = (
f'id:{i+1}\n名称:{plugin_info[key]["plugin_name"]}'
f' \t\t{status}\n'
f"模块:{key}\n"
f'作者:{plugin_info[key]["author"]}\n'
f'版本:{plugin_info[key]["version"]} \t\t{version}\n'
f'简介:{plugin_info[key]["introduction"]}\n'
f"-------------------"
)
img = await text2image(s, font_size=20, color="#f9f6f2")
w = w if w > img.w else img.w
h += img.h + line_height
image_list.append(img)
A = BuildImage(w + 50, h + 50, color="#f9f6f2")
cur_h = 25
for img in image_list:
await A.apaste(img, (25, cur_h))
cur_h += img.h + line_height
return A.pic2bs4()
async def download_json() -> int:
"""
下载插件库json文件
"""
try:
url = (await AsyncHttpx.get(repo_json_url)).headers.get("Location")
if repo_zip_path.exists():
repo_zip_path.unlink()
if await AsyncHttpx.download_file(url, repo_zip_path):
zf = zipfile.ZipFile(repo_zip_path, "r")
extract_path = path / "temp"
for file in zf.namelist():
zf.extract(file, extract_path)
zf.close()
if plugin_json.exists():
plugin_json.unlink()
(
extract_path
/ "nonebot_plugins_zhenxun_bot-index"
/ "zhenxun_plugins.json"
).rename(plugin_json)
shutil.rmtree(extract_path.absolute(), ignore_errors=True)
return 200
except Exception as e:
logger.error(f"下载插件库压缩包失败或解压失败 {type(e)}:{e}")
return 999
async def get_plugin_name(name: int) -> Tuple[str, int]:
"""
通过下标获取插件名
:param name: 下标
"""
name = int(name)
if not data:
await show_plugin_repo()
if name < 1 or name > len(data.keys()):
return "下标超过上下限!", 999
name = list(data.keys())[name - 1]
return name, 200
Regular → Executable
+218 -111
View File
@@ -1,111 +1,218 @@
from nonebot import Driver
from services.db_context import db
from asyncpg.exceptions import DuplicateColumnError
from models.group_info import GroupInfo
from nonebot.adapters.cqhttp import Bot
from utils.user_agent import get_user_agent
from services.log import logger
from configs.path_config import TEXT_PATH
from asyncio.exceptions import TimeoutError
from pathlib import Path
import aiohttp
import nonebot
try:
import ujson as json
except ModuleNotFoundError:
import json
driver: Driver = nonebot.get_driver()
@driver.on_startup
async def update_city():
"""
部分插件需要中国省份城市
这里直接更新,避免插件内代码重复
:return:
"""
china_city = Path(TEXT_PATH) / "china_city.json"
data = {}
try:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
) as res:
provinces_data = json.loads(await res.text(encoding="utf8"))
for province in provinces_data.keys():
data[provinces_data[province]] = []
async with session.get(
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
timeout=5,
) as res:
city_data = json.loads(await res.text(encoding="utf8"))
for city in city_data.keys():
data[provinces_data[province]].append(city_data[city])
with open(china_city, "w", encoding="utf8") as f:
json.dump(data, f, indent=4, ensure_ascii=False)
logger.info("自动更新城市列表完成.....")
except TimeoutError:
logger.info("自动更新城市列表超时.....")
@driver.on_startup
async def _():
"""
数据库表结构变换
"""
sql_str = [
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;" # group_info表添加一个group_flag
]
for sql in sql_str:
try:
query = db.text(sql)
await db.first(query)
except DuplicateColumnError:
pass
@driver.on_bot_connect
async def _(bot: Bot):
"""
版本某些需要的变换
"""
# 清空不存在的群聊信息,并将已所有已存在的群聊group_flag设置为1(认证所有已存在的群)
if not await GroupInfo.get_group_info(114514):
# 标识符,该功能只需执行一次
await GroupInfo.add_group_info(
114514,
"114514",
114514,
114514,
1
)
group_list = await bot.get_group_list()
group_list = [g["group_id"] for g in group_list]
_gl = [x.group_id for x in await GroupInfo.get_all_group()]
if 114514 in _gl:
_gl.remove(114514)
for group_id in _gl:
if group_id in group_list:
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 1)
else:
group_info = await bot.get_group_info(group_id=group_id)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
)
logger.info(f"已将群聊 {group_id} 添加认证...")
else:
await GroupInfo.delete_group_info(group_id)
logger.info(f"移除不存在的群聊信息:{group_id}")
import random
from asyncpg.exceptions import (
DuplicateColumnError,
UndefinedColumnError,
PostgresSyntaxError,
)
from nonebot import Driver
from services.db_context import db
from models.group_info import GroupInfo
from models.bag_user import BagUser
from nonebot.adapters.onebot.v11 import Bot
from services.log import logger
from configs.path_config import TEXT_PATH
from asyncio.exceptions import TimeoutError
from typing import List
from utils.http_utils import AsyncHttpx
from utils.utils import GDict
from utils.utils import scheduler
import nonebot
try:
import ujson as json
except ModuleNotFoundError:
import json
driver: Driver = nonebot.get_driver()
@driver.on_startup
async def update_city():
"""
部分插件需要中国省份城市
这里直接更新,避免插件内代码重复
"""
china_city = TEXT_PATH / "china_city.json"
data = {}
if not china_city.exists():
try:
res = await AsyncHttpx.get(
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
)
res.encoding = "utf8"
provinces_data = json.loads(res.text)
for province in provinces_data.keys():
data[provinces_data[province]] = []
res = await AsyncHttpx.get(
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
timeout=5,
)
res.encoding = "utf8"
city_data = json.loads(res.text)
for city in city_data.keys():
data[provinces_data[province]].append(city_data[city])
with open(china_city, "w", encoding="utf8") as f:
json.dump(data, f, indent=4, ensure_ascii=False)
logger.info("自动更新城市列表完成.....")
except TimeoutError:
logger.warning("自动更新城市列表超时.....")
except ValueError:
logger.warning("自动城市列表失败.....")
except Exception as e:
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
@driver.on_startup
async def _():
"""
数据库表结构变换
"""
_flag = []
sql_str = [
(
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;",
"group_info",
), # group_info表添加一个group_flag
(
"ALTER TABLE bag_users rename belonging_group To group_id;",
"bag_users",
), # 将 bag_users 的 belonging_group 改为 group_id
(
"ALTER TABLE group_info_users rename belonging_group To group_id;",
"group_info_users",
),
(
"ALTER TABLE sign_group_users rename belonging_group To group_id;",
"sign_group_users",
),
(
"ALTER TABLE open_cases_users rename belonging_group To group_id;",
"open_cases_users",
),
(
"ALTER TABLE bag_users ADD property json NOT NULL DEFAULT '{}';",
"bag_users",
), # bag_users 新增字段 property 替代 props
(
"ALTER TABLE genshin ADD auto_sign_time timestamp with time zone;",
"genshin"
), # 新增原神自动签到字段
(
"ALTER TABLE genshin ADD resin_remind boolean DEFAULT False;",
"genshin"
), # 新增原神自动签到字段
(
"ALTER TABLE genshin ADD resin_recovery_time timestamp with time zone;",
"genshin"
), # 新增原神自动签到字段
(
"ALTER TABLE genshin ADD bind_group Integer;",
"genshin"
), # 新增原神群号绑定字段
(
"ALTER TABLE genshin ADD login_ticket VARCHAR(255) DEFAULT '';",
"genshin"
), # 新增米游社login_ticket绑定字段
(
"ALTER TABLE genshin ADD stuid VARCHAR(255) DEFAULT '';",
"genshin"
), # 新增米游社stuid绑定字段
(
"ALTER TABLE genshin ADD stoken VARCHAR(255) DEFAULT '';",
"genshin"
), # 新增米游社stoken绑定字段
(
"ALTER TABLE chat_history ADD plain_text Text;",
"chat_history"
), # 新增纯文本
(
"ALTER TABLE goods_info ADD daily_limit Integer DEFAULT 0;",
"goods_info"
), # 新增纯文本
(
"ALTER TABLE goods_info ADD daily_purchase_limit Json DEFAULT '{}';",
"goods_info"
), # 新增纯文本
]
for sql in sql_str + GDict.get('run_sql', []):
try:
if isinstance(sql, str):
flag = f'{random.randint(1, 10000)}'
else:
flag = sql[1]
sql = sql[0]
query = db.text(sql)
await db.first(query)
logger.info(f"完成sql操作:{sql}")
_flag.append(flag)
except (DuplicateColumnError, UndefinedColumnError):
pass
except PostgresSyntaxError:
logger.error(f"语法错误:执行sql失败:{sql}")
# bag_user 将文本转为字典格式
await __database_script(_flag)
@driver.on_bot_connect
async def _(bot: Bot):
"""
版本某些需要的变换
"""
# 清空不存在的群聊信息,并将已所有已存在的群聊group_flag设置为1(认证所有已存在的群)
if not await GroupInfo.get_group_info(114514):
# 标识符,该功能只需执行一次
await GroupInfo.add_group_info(114514, "114514", 114514, 114514, 1)
group_list = await bot.get_group_list()
group_list = [g["group_id"] for g in group_list]
_gl = [x.group_id for x in await GroupInfo.get_all_group()]
if 114514 in _gl:
_gl.remove(114514)
for group_id in _gl:
if group_id in group_list:
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 1)
else:
group_info = await bot.get_group_info(group_id=group_id)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
logger.info(f"已将群聊 {group_id} 添加认证...")
else:
await GroupInfo.delete_group_info(group_id)
logger.info(f"移除不存在的群聊信息:{group_id}")
async def __database_script(_flag: List[str]):
# bag_user 将文本转为字典格式
if "bag_users" in _flag:
for x in await BagUser.get_all_users():
props = {}
if x.props:
for prop in [p for p in x.props.split(",") if p]:
if props.get(prop):
props[prop] += 1
else:
props[prop] = 1
logger.info(
f"__database_script USER {x.user_qq} GROUP {x.group_id} 更新数据 {props}"
)
await x.update(
property=props,
props="",
).apply()
# 自动更新城市列表
@scheduler.scheduled_job(
"cron",
hour=6,
minute=1,
)
async def _():
await update_city()
+23
View File
@@ -0,0 +1,23 @@
from configs.config import Config
from nonebot import Driver
from utils.decorator.shop import shop_register
import nonebot
driver: Driver = nonebot.get_driver()
Config.add_plugin_config(
"shop",
"IMPORT_DEFAULT_SHOP_GOODS",
True,
help_="导入商店自带的三个商品",
default_value=True
)
nonebot.load_plugins("basic_plugins/shop")
@driver.on_bot_connect
async def _():
await shop_register.load_register()
+109
View File
@@ -0,0 +1,109 @@
from nonebot import on_command
from models.user_shop_gold_log import UserShopGoldLog
from services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.params import CommandArg
from utils.utils import is_number
from models.bag_user import BagUser
from services.db_context import db
from nonebot.adapters.onebot.v11.permission import GROUP
from models.goods_info import GoodsInfo
import time
__zx_plugin_name__ = "商店 - 购买道具"
__plugin_usage__ = """
usage:
购买道具
指令:
购买 [序号或名称] ?[数量=1]
示例:购买 好感双倍加持卡Ⅰ
示例:购买 1 4
""".strip()
__plugin_des__ = "商店 - 购买道具"
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
__plugin_type__ = ("商店",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["商店", "购买道具"],
}
__plugin_cd_limit__ = {"cd": 3}
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
@buy.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
goods = None
if arg.extract_plain_text().strip() in ["神秘药水"]:
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
goods_list = [
x
for x in await GoodsInfo.get_all_goods()
if x.goods_limit_time > time.time() or x.goods_limit_time == 0
]
goods_name_list = [x.goods_name for x in goods_list]
msg = arg.extract_plain_text().strip().split()
num = 1
if len(msg) > 1:
if is_number(msg[1]) and int(msg[1]) > 0:
num = int(msg[1])
else:
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
if is_number(msg[0]):
msg = int(msg[0])
if msg > len(goods_name_list) or msg < 1:
await buy.finish("请输入正确的商品id!", at_sender=True)
goods = goods_list[msg - 1]
else:
if msg[0] in goods_name_list:
for i in range(len(goods_name_list)):
if msg[0] == goods_name_list[i]:
goods = goods_list[i]
break
else:
await buy.finish("请输入正确的商品名称!")
else:
await buy.finish("请输入正确的商品名称!", at_sender=True)
async with db.transaction():
if (
await BagUser.get_gold(event.user_id, event.group_id)
) < goods.goods_price * num * goods.goods_discount:
await buy.finish("您的金币好像不太够哦", at_sender=True)
flag, n = await GoodsInfo.check_user_daily_purchase(
goods, event.user_id, event.group_id, num
)
if flag:
await buy.finish(f"该次购买将超过每日次数限制,目前该道具还可以购买{n}次哦", at_sender=True)
if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
await GoodsInfo.add_user_daily_purchase(
goods, event.user_id, event.group_id, num
)
await buy.send(
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
at_sender=True,
)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} "
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
)
await UserShopGoldLog.add_shop_log(
event.user_id,
event.group_id,
0,
goods.goods_name,
num,
goods.goods_price * num * goods.goods_discount,
)
else:
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} "
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 失败!"
)
@@ -1,11 +1,12 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from nonebot.typing import T_State
from nonebot.adapters.cqhttp.permission import GROUP
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, ActionFailed
from nonebot.params import CommandArg
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.data_utils import init_rank
from models.bag_user import BagUser
from utils.image_utils import text2image
from utils.message_builder import image
from utils.utils import get_message_text, is_number
from utils.utils import is_number
__zx_plugin_name__ = "商店 - 我的金币"
__plugin_usage__ = """
@@ -33,13 +34,17 @@ gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP)
@my_gold.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await my_gold.finish(await BagUser.get_my_total_gold(event.user_id, event.group_id))
async def _(event: GroupMessageEvent):
msg = await BagUser.get_user_total_gold(event.user_id, event.group_id)
try:
await my_gold.send(msg)
except ActionFailed:
await my_gold.send(image(b64=(await text2image(msg, color="#f9f6f2", padding=10)).pic2bs4()))
@gold_rank.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
num = get_message_text(event.json())
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
num = arg.extract_plain_text().strip()
if is_number(num) and 51 > int(num) > 10:
num = int(num)
else:
@@ -1,52 +1,45 @@
from nonebot import on_command
from services.log import logger
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from nonebot.typing import T_State
from models.bag_user import BagUser
from nonebot.adapters.cqhttp.permission import GROUP
__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": ["商店", "我的道具"],
}
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
@my_props.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
props = await BagUser.get_props(event.user_id, event.group_id)
if props:
pname_list = []
pnum_list = []
rst = ""
props = props[:-1].split(",")
for p in props:
if p != "":
if p in pname_list:
pnum_list[pname_list.index(p)] += 1
else:
pname_list.append(p)
pnum_list.append(1)
for i in range(len(pname_list)):
rst += f"{i+1}.{pname_list[i]}\t×{pnum_list[i]}\n"
await my_props.send("\n" + rst[:-1], at_sender=True)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
else:
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
from nonebot import on_command
from utils.message_builder import image
from ._data_source import create_bag_image
from services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from models.bag_user import BagUser
from nonebot.adapters.onebot.v11.permission import GROUP
__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": ["商店", "我的道具"],
}
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
@my_props.handle()
async def _(event: GroupMessageEvent):
props = await BagUser.get_property(event.user_id, event.group_id)
if props:
await my_props.send(image(b64=await create_bag_image(props)))
# rst = ""
# for i, p in enumerate(props.keys()):
# rst += f"{i+1}.{p}\t×{props[p]}\n"
# await my_props.send("\n" + rst[:-1], at_sender=True)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
else:
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
+121
View File
@@ -0,0 +1,121 @@
from typing import Dict, List, Optional
from models.bag_user import BagUser
from models.goods_info import GoodsInfo
from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH
icon_path = IMAGE_PATH / "shop_icon"
async def create_bag_image(props: Dict[str, int]):
"""
说明:
创建背包道具图片
参数:
:param props: 道具仓库字典
"""
goods_list = await GoodsInfo.get_all_goods()
active_props = await _init_prop(props, [x for x in goods_list if not x.is_passive])
passive_props = await _init_prop(props, [x for x in goods_list if x.is_passive])
active_w = 0
active_h = 0
passive_w = 0
passive_h = 0
if active_props:
img = BuildImage(
active_props.w,
active_props.h + 70,
font="CJGaoDeGuo.otf",
font_size=30,
color="#f9f6f2",
)
await img.apaste(active_props, (0, 70))
await img.atext((0, 30), "主动道具")
active_props = img
active_w = img.w
active_h = img.h
if passive_props:
img = BuildImage(
passive_props.w,
passive_props.h + 70,
font="CJGaoDeGuo.otf",
font_size=30,
color="#f9f6f2",
)
await img.apaste(passive_props, (0, 70))
await img.atext((0, 30), "被动道具")
passive_props = img
passive_w = img.w
passive_h = img.h
A = BuildImage(
active_w + passive_w + 100,
max(active_h, passive_h) + 60,
font="CJGaoDeGuo.otf",
font_size=30,
color="#f9f6f2",
)
curr_w = 50
if active_props:
await A.apaste(active_props, (curr_w, 0))
curr_w += active_props.w + 10
if passive_props:
await A.apaste(passive_props, (curr_w, 0))
if active_props and passive_props:
await A.aline(
(active_props.w + 45, 70, active_props.w + 45, A.h - 20), fill=(0, 0, 0)
)
return A.pic2bs4()
async def _init_prop(
props: Dict[str, int], _props: List[GoodsInfo]
) -> Optional[BuildImage]:
"""
说明:
构造道具列表图片
参数:
:param props: 道具仓库字典
:param _props: 道具列表
"""
active_name = [x.goods_name for x in _props]
name_list = [x for x in props.keys() if x in active_name]
if not name_list:
return None
temp_img = BuildImage(0, 0, font_size=20)
image_list = []
num_list = []
for i, name in enumerate(name_list):
img = BuildImage(
temp_img.getsize(name)[0] + 50,
30,
font="msyh.ttf",
font_size=20,
color="#f9f6f2",
)
await img.atext((30, 5), f"{i + 1}.{name}")
goods = [x for x in _props if x.goods_name == name][0]
if goods.icon and (icon_path / goods.icon).exists():
icon = BuildImage(30, 30, background=icon_path / goods.icon)
await img.apaste(icon, alpha=True)
image_list.append(img)
num_list.append(
BuildImage(
30, 30, font_size=20, font="msyh.ttf", plain_text=f"×{props[name]}"
)
)
max_w = 0
num_max_w = 0
h = 0
for img, num in zip(image_list, num_list):
h += img.h
max_w = max_w if max_w > img.w else img.w
num_max_w = num_max_w if num_max_w > num.w else num.w
A = BuildImage(max_w + num_max_w + 30, h, color="#f9f6f2")
curr_h = 0
for img, num in zip(image_list, num_list):
await A.apaste(img, (0, curr_h))
await A.apaste(num, (max_w + 20, curr_h + 5), True)
curr_h += img.h
return A
@@ -1,26 +1,26 @@
from utils.utils import scheduler
from models.bag_user import BagUser
from services.log import logger
__zx_plugin_name__ = "每日金币重置 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
# 重置每日金币
@scheduler.scheduled_job(
"cron",
hour=0,
minute=1,
)
async def _():
try:
user_list = await BagUser.get_all_users()
for user in user_list:
await user.update(
get_today_gold=0,
spend_today_gold=0,
).apply()
except Exception as e:
logger.error(f"重置每日金币错误 e:{e}")
from utils.utils import scheduler
from models.bag_user import BagUser
from services.log import logger
__zx_plugin_name__ = "每日金币重置 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
# 重置每日金币
@scheduler.scheduled_job(
"cron",
hour=0,
minute=1,
)
async def _():
try:
user_list = await BagUser.get_all_users()
for user in user_list:
await user.update(
get_today_gold=0,
spend_today_gold=0,
).apply()
except Exception as e:
logger.error(f"重置每日金币错误 e:{e}")
+139
View File
@@ -0,0 +1,139 @@
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info, GoodsInfo
from nonebot.adapters.onebot.v11 import MessageEvent, Message
from nonebot import on_command
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from nonebot.permission import SUPERUSER
from utils.utils import is_number, scheduler
from nonebot.params import CommandArg
from services.log import logger
import os
__zx_plugin_name__ = "商店"
__plugin_usage__ = """
usage:
商店项目,这可不是奸商
指令:
商店
""".strip()
__plugin_superuser_usage__ = """
usage:
商品操作
指令:
添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)
删除商品 [名称或序号]
修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时]
示例:添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
示例:添加商品 name:可疑的药 price:5 des:效果未知
示例:删除商品 2
示例:修改商品 name:1 price:900 修改序号为1的商品的价格为900
* 修改商品只需添加需要值即可 *
""".strip()
__plugin_des__ = "商店系统[金币回收计划]"
__plugin_cmd__ = [
"商店",
"添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)) [_superuser]",
"删除商品 [名称或序号] [_superuser]",
"修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时] [_superuser]",
]
__plugin_type__ = ('商店',)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["商店"],
}
__plugin_block_limit__ = {
"limit_type": "group"
}
shop_help = on_command("商店", priority=5, block=True)
shop_add_goods = on_command("添加商品", priority=5, permission=SUPERUSER, block=True)
shop_del_goods = on_command("删除商品", priority=5, permission=SUPERUSER, block=True)
shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER, block=True)
@shop_help.handle()
async def _():
await shop_help.send(image(b64=await create_shop_help()))
@shop_add_goods.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if msg:
data = parse_goods_info(msg)
if isinstance(data, str):
await shop_add_goods.finish(data)
if not data.get("name") or not data.get("price") or not data.get("des"):
await shop_add_goods.finish("name:price:des 参数不可缺少!")
if await register_goods(**data):
await shop_add_goods.send(f"添加商品 {data['name']} 成功!\n"
f"名称:{data['name']}\n"
f"价格:{data['price']}金币\n"
f"简介:{data['des']}\n"
f"折扣:{data.get('discount')}\n"
f"限时:{data.get('limit_time')}", at_sender=True)
logger.info(f"USER {event.user_id} 添加商品 {msg} 成功")
else:
await shop_add_goods.send(f"添加商品 {msg} 失败了...", at_sender=True)
logger.warning(f"USER {event.user_id} 添加商品 {msg} 失败")
@shop_del_goods.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if msg:
name = ""
id_ = 0
if is_number(msg):
id_ = int(msg)
else:
name = msg
rst, goods_name, code = await delete_goods(name, id_)
if code == 200:
await shop_del_goods.send(f"删除商品 {goods_name} 成功了...", at_sender=True)
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
os.remove(f"{IMAGE_PATH}/shop_help.png")
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 成功")
else:
await shop_del_goods.send(f"删除商品 {goods_name} 失败了...", at_sender=True)
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 失败")
@shop_update_goods.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if msg:
data = parse_goods_info(msg)
if isinstance(data, str):
await shop_add_goods.finish(data)
if not data.get("name"):
await shop_add_goods.finish("name 参数不可缺少!")
flag, name, text = await update_goods(**data)
if flag:
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功")
else:
await shop_update_goods.send(name, at_sender=True)
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败")
@scheduler.scheduled_job(
"cron",
hour=0,
minute=0,
)
async def _():
try:
await GoodsInfo.reset_daily_purchase()
logger.info("商品每日限购次数重置成功...")
except Exception as e:
logger.error(f"商品每日限购次数重置发生错误 {type(e)}:{e}")
@@ -0,0 +1,359 @@
from PIL import Image
from models.goods_info import GoodsInfo
from utils.image_utils import BuildImage, text2image
from utils.utils import is_number
from configs.path_config import IMAGE_PATH
from typing import Optional, Union, Tuple
from utils.utils import GDict
import time
icon_path = IMAGE_PATH / 'shop_icon'
GDict['run_sql'].append("ALTER TABLE goods_info ADD is_passive boolean DEFAULT False;")
GDict['run_sql'].append("ALTER TABLE goods_info ADD icon VARCHAR(255);")
# 创建商店界面
async def create_shop_help() -> str:
"""
制作商店图片
:return: 图片base64
"""
goods_lst = await GoodsInfo.get_all_goods()
_dc = {}
font_h = BuildImage(0, 0).getsize("正")[1]
h = 10
_list = []
for goods in goods_lst:
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time:
_list.append(goods)
# A = BuildImage(1100, h, color="#f9f6f2")
total_n = 0
image_list = []
for idx, goods in enumerate(_list):
name_image = BuildImage(
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
)
await name_image.atext(
(15, 0), f"{idx + 1}.{goods.goods_name}", center_type="by_height"
)
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
await name_image.atext((390, 0), "售价:", center_type="by_height")
if goods.goods_discount != 1:
discount_price = int(goods.goods_discount * goods.goods_price)
old_price_image = BuildImage(0, 0, plain_text=str(goods.goods_price), font_color=(194, 194, 194), font="CJGaoDeGuo.otf", font_size=15)
await old_price_image.aline((0, int(old_price_image.h / 2), old_price_image.w + 1, int(old_price_image.h / 2)), (0, 0, 0))
await name_image.apaste(
old_price_image, (440, 0), True
)
await name_image.atext(
(440, 15), str(discount_price), (255, 255, 255)
)
else:
await name_image.atext(
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
)
await name_image.atext(
(
440
+ BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w,
0,
),
f" 金币",
center_type="by_height",
)
des_image = None
font_img = BuildImage(
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
)
p = font_img.getsize('简介:')[0] + 20
if goods.goods_description:
des_list = goods.goods_description.split('\n')
desc = ''
for des in des_list:
if font_img.getsize(des)[0] > font_img.w - p - 20:
msg = ''
tmp = ''
for i in range(len(des)):
if font_img.getsize(tmp)[0] < font_img.w - p - 20:
tmp += des[i]
else:
msg += tmp + '\n'
tmp = des[i]
desc += msg
if tmp:
desc += tmp
else:
desc += des + '\n'
if desc[-1] == '\n':
desc = desc[:-1]
des_image = await text2image(desc, color="#a29ad6")
goods_image = BuildImage(
600, (50 + des_image.h) if des_image else 50, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
)
if des_image:
await goods_image.atext((15, 50), '简介:')
await goods_image.apaste(des_image, (p, 50))
await name_image.acircle_corner(5)
await goods_image.apaste(name_image, (0, 5), True, center_type="by_width")
await goods_image.acircle_corner(20)
bk = BuildImage(1180, (50 + des_image.h) if des_image else 50, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
if goods.icon and (icon_path / goods.icon).exists():
icon = BuildImage(70, 70, background=icon_path / goods.icon)
await bk.apaste(icon)
await bk.apaste(goods_image, (70, 0), alpha=True)
n = 0
_w = 650
# 添加限时图标和时间
if goods.goods_limit_time > 0:
n += 140
_limit_time_logo = BuildImage(
40, 40, background=f"{IMAGE_PATH}/other/time.png"
)
await bk.apaste(_limit_time_logo, (_w + 50, 0), True)
await bk.apaste(
BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"),
(_w + 90, 10),
True,
)
limit_time = time.strftime(
"%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)
).split()
y_m_d = limit_time[0]
_h_m = limit_time[1].split(":")
h_m = _h_m[0] + "时 " + _h_m[1] + "分"
await bk.atext((_w + 55, 38), str(y_m_d))
await bk.atext((_w + 65, 57), str(h_m))
_w += 140
if goods.goods_discount != 1:
n += 140
_discount_logo = BuildImage(30, 30, background=f"{IMAGE_PATH}/other/discount.png")
await bk.apaste(_discount_logo, (_w + 50, 10), True)
await bk.apaste(
BuildImage(0, 0, plain_text="折扣!", font_size=23, font="CJGaoDeGuo.otf"),
(_w + 90, 15),
True,
)
await bk.apaste(
BuildImage(0, 0, plain_text=f"{10 * goods.goods_discount:.1f} 折", font_size=30, font="CJGaoDeGuo.otf", font_color=(85, 156, 75)),
(_w + 50, 44),
True,
)
_w += 140
if goods.daily_limit != 0:
n += 140
_daily_limit_logo = BuildImage(35, 35, background=f"{IMAGE_PATH}/other/daily_limit.png")
await bk.apaste(_daily_limit_logo, (_w + 50, 10), True)
await bk.apaste(
BuildImage(0, 0, plain_text="限购!", font_size=23, font="CJGaoDeGuo.otf"),
(_w + 90, 20),
True,
)
await bk.apaste(
BuildImage(0, 0, plain_text=f"{goods.daily_limit}", font_size=30, font="CJGaoDeGuo.otf"),
(_w + 72, 45),
True,
)
if total_n < n:
total_n = n
if n:
await bk.aline((650, -1, 650 + n, -1), "#a29ad6", 5)
# await bk.aline((650, 80, 650 + n, 80), "#a29ad6", 5)
# 添加限时图标和时间
image_list.append(bk)
# await A.apaste(bk, (0, current_h), True)
# current_h += 90
h = 0
current_h = 0
for img in image_list:
h += img.h + 10
A = BuildImage(1100, h, color="#f9f6f2")
for img in image_list:
await A.apaste(img, (0, current_h), True)
current_h += img.h + 10
w = 950
if total_n:
w += total_n
h = A.h + 230 + 100
h = 1000 if h < 1000 else h
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan_3.png")
zx_img.transpose(Image.FLIP_LEFT_RIGHT)
zx_img.replace_color_tran(((240, 240, 240), (255, 255, 255)), (249, 246, 242))
await shop.apaste(zx_img, (0, 100))
shop.paste(A, (20 + zx_img.w, 230))
await shop.apaste(shop_logo, (450, 30), True)
shop.text(
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
"注【通过 序号 或者 商品名称 购买】",
)
shop.text((20 + zx_img.w, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
return shop.pic2bs4()
async def register_goods(
name: str,
price: int,
des: str,
discount: Optional[float] = 1,
limit_time: Optional[int] = 0,
daily_limit: Optional[int] = 0,
is_passive: Optional[bool] = False,
icon: Optional[str] = None,
) -> bool:
"""
添加商品
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
添加商品 name:可疑的药 price:5 des:效果未知
:param name: 商品名称
:param price: 商品价格
:param des: 商品简介
:param discount: 商品折扣
:param limit_time: 商品限时销售时间,单位为小时
:param daily_limit: 每日购买次数限制
:param is_passive: 是否为被动
:param icon: 图标
:return: 是否添加成功
"""
if not await GoodsInfo.get_goods_info(name):
limit_time = float(limit_time) if limit_time else limit_time
discount = discount if discount is not None else 1
limit_time = (
int(time.time() + limit_time * 60 * 60)
if limit_time is not None and limit_time != 0
else 0
)
return await GoodsInfo.add_goods(
name, int(price), des, float(discount), limit_time, daily_limit, is_passive, icon
)
return False
# 删除商品
async def delete_goods(name: str, id_: int) -> "str, str, int":
"""
删除商品
:param name: 商品名称
:param id_: 商品id
:return: 删除状况
"""
goods_lst = await GoodsInfo.get_all_goods()
if id_:
if id_ < 1 or id_ > len(goods_lst):
return "序号错误,没有该序号商品...", "", 999
goods_name = goods_lst[id_ - 1].goods_name
if await GoodsInfo.delete_goods(goods_name):
return f"删除商品 {goods_name} 成功!", goods_name, 200
else:
return f"删除商品 {goods_name} 失败!", goods_name, 999
if name:
if await GoodsInfo.delete_goods(name):
return f"删除商品 {name} 成功!", name, 200
else:
return f"删除商品 {name} 失败!", name, 999
# 更新商品信息
async def update_goods(**kwargs) -> Tuple[bool, str, str]:
"""
更新商品信息
:param kwargs: kwargs
:return: 更新状况
"""
if kwargs:
goods_lst = await GoodsInfo.get_all_goods()
if is_number(kwargs["name"]):
if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst):
return False, "序号错误,没有该序号的商品...", ""
goods = goods_lst[int(kwargs["name"]) - 1]
else:
goods = await GoodsInfo.get_goods_info(kwargs["name"])
if not goods:
return False, "名称错误,没有该名称的商品...", ""
name: str = goods.goods_name
price = goods.goods_price
des = goods.goods_description
discount = goods.goods_discount
limit_time = goods.goods_limit_time
daily_limit = goods.daily_limit
is_passive = goods.is_passive
new_time = 0
tmp = ""
if kwargs.get("price"):
tmp += f'价格:{price} --> {kwargs["price"]}\n'
price = kwargs["price"]
if kwargs.get("des"):
tmp += f'描述:{des} --> {kwargs["des"]}\n'
des = kwargs["des"]
if kwargs.get("discount"):
tmp += f'折扣:{discount} --> {kwargs["discount"]}\n'
discount = kwargs["discount"]
if kwargs.get("limit_time"):
kwargs["limit_time"] = float(kwargs["limit_time"])
new_time = time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime(time.time() + kwargs["limit_time"] * 60 * 60),
) if kwargs["limit_time"] != 0 else 0
tmp += f"限时至: {new_time}\n" if new_time else "取消了限时\n"
limit_time = kwargs["limit_time"]
if kwargs.get("daily_limit"):
tmp += f'每日购买限制:{daily_limit} --> {kwargs["daily_limit"]}\n' if daily_limit else "取消了购买限制\n"
daily_limit = int(kwargs["daily_limit"])
if kwargs.get("is_passive"):
tmp += f'被动道具:{is_passive} --> {kwargs["is_passive"]}\n'
des = kwargs["is_passive"]
await GoodsInfo.update_goods(
name,
int(price),
des,
float(discount),
int(
time.time() + limit_time * 60 * 60
if limit_time != 0 and new_time
else 0
),
daily_limit,
is_passive
)
return True, name, tmp[:-1],
def parse_goods_info(msg: str) -> Union[dict, str]:
"""
解析格式数据
:param msg: 消息
:return: 解析完毕的数据data
"""
if "name:" not in msg:
return "必须指定修改的商品名称或序号!"
data = {}
for x in msg.split():
sp = x.split(":", maxsplit=1)
if str(sp[1]).strip():
sp[1] = sp[1].strip()
if sp[0] == "name":
data["name"] = sp[1]
elif sp[0] == "price":
if not is_number(sp[1]) or int(sp[1]) < 0:
return "price参数不合法,必须大于等于0!"
data["price"] = sp[1]
elif sp[0] == "des":
data["des"] = sp[1]
elif sp[0] == "discount":
if not is_number(sp[1]) or float(sp[1]) < 0:
return "discount参数不合法,必须大于0!"
data["discount"] = sp[1]
elif sp[0] == "limit_time":
if not is_number(sp[1]) or float(sp[1]) < 0:
return "limit_time参数不合法,必须为数字且大于0!"
data["limit_time"] = sp[1]
elif sp[0] == "daily_limit":
if not is_number(sp[1]) or float(sp[1]) < 0:
return "daily_limit参数不合法,必须为数字且大于0!"
data["daily_limit"] = sp[1]
return data
+107
View File
@@ -0,0 +1,107 @@
from typing import Any, Tuple
from nonebot import on_command, on_regex
from models.user_shop_gold_log import UserShopGoldLog
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
from nonebot.params import CommandArg, RegexGroup
from utils.decorator.shop import NotMeetUseConditionsException
from utils.utils import is_number
from models.bag_user import BagUser
from nonebot.adapters.onebot.v11.permission import GROUP
from services.db_context import db
from .data_source import effect, register_use, func_manager, build_params
__zx_plugin_name__ = "商店 - 使用道具"
__plugin_usage__ = """
usage:
普通的使用道具
指令:
使用道具 [序号或道具名称] ?[数量]=1 ?[其他信息]
示例:使用道具好感度双倍加持卡 使用道具好感度双倍加持卡
示例:使用道具1 使用第一个道具
示例:使用道具1 10 使用10个第一个道具
示例:使用道具1 1 来点色图 使用第一个道具并附带信息
* 序号以 ”我的道具“ 为准 *
""".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": ["商店", "使用道具"],
}
use_props = on_command(r"使用道具", priority=5, block=True, permission=GROUP)
@use_props.handle()
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text()
num = 1
text = ""
prop_n = None
index = None
split = msg.split()
if size := len(split):
if size == 1:
prop_n = split[0].strip()
index = 1
if size > 1 and is_number(split[1].strip()):
prop_n = split[0].strip()
num = int(split[1].strip())
index = 2
else:
await use_props.finish("缺少参数,请查看帮助", at_sender=True)
if index:
text = " ".join(split[index:])
property_ = await BagUser.get_property(event.user_id, event.group_id, True)
if property_:
name = None
if prop_n and is_number(prop_n):
if 0 < int(prop_n) <= len(property_):
name = list(property_.keys())[int(prop_n) - 1]
else:
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
else:
if prop_n not in property_.keys():
await use_props.finish("道具名称错误!", at_sender=True)
name = prop_n
_user_prop_count = property_[name]
if num > _user_prop_count:
await use_props.finish(f"道具数量不足,无法使用{num}次!")
if num > (n := func_manager.get_max_num_limit(name)):
await use_props.finish(f"该道具单次只能使用 {n} 个!")
model, kwargs = build_params(bot, event, name, num, text)
try:
await func_manager.run_handle(type_="before_handle", param=model, **kwargs)
except NotMeetUseConditionsException as e:
await use_props.finish(e.get_info(), at_sender=True)
async with db.transaction():
if await BagUser.delete_property(event.user_id, event.group_id, name, num):
if func_manager.check_send_success_message(name):
await use_props.send(f"使用道具 {name} {num} 次成功!", at_sender=True)
if msg := await effect(bot, event, name, num, text, event.message):
await use_props.send(msg, at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次成功"
)
await UserShopGoldLog.add_shop_log(
event.user_id, event.group_id, 1, name, num
)
else:
await use_props.send(f"使用道具 {name} {num} 次失败!", at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次失败"
)
await func_manager.run_handle(type_="after_handle", param=model, **kwargs)
else:
await use_props.send("您的背包里没有任何的道具噢", at_sender=True)
+236
View File
@@ -0,0 +1,236 @@
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment, Message
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot
from pydantic import create_model
from utils.models import ShopParam
from typing import Optional, Union, Callable, List, Tuple, Dict, Any
from types import MappingProxyType
import inspect
import asyncio
class GoodsUseFuncManager:
def __init__(self):
self._data = {}
def register_use_before_handle(self, goods_name: str, fun_list: List[Callable]):
"""
说明:
注册商品使用前函数
参数:
:param goods_name: 商品名称
:param fun_list: 函数列表
"""
if fun_list:
self._data[goods_name]["before_handle"] = fun_list
logger.info(f"register_use_before_handle 成功注册商品:{goods_name} 的{len(fun_list)}个使用前函数")
def register_use_after_handle(self, goods_name: str, fun_list: List[Callable]):
"""
说明:
注册商品使用后函数
参数:
:param goods_name: 商品名称
:param fun_list: 函数列表
"""
if fun_list:
self._data[goods_name]["after_handle"] = fun_list
logger.info(f"register_use_after_handle 成功注册商品:{goods_name} 的{len(fun_list)}个使用后函数")
def register_use(self, goods_name: str, **kwargs):
"""
注册商品使用方法
:param goods_name: 商品名称
:param kwargs: kwargs
"""
self._data[goods_name] = kwargs
def exists(self, goods_name: str) -> bool:
"""
判断商品使用方法是否被注册
:param goods_name: 商品名称
"""
return bool(self._data.get(goods_name))
def get_max_num_limit(self, goods_name: str) -> int:
"""
获取单次商品使用数量
:param goods_name: 商品名称
"""
if self.exists(goods_name):
return self._data[goods_name]["kwargs"]["max_num_limit"]
return 1
def _parse_args(self, args_: MappingProxyType, param: ShopParam, **kwargs):
param_list_ = []
_bot = param.bot
param.bot = None
param_json = param.dict()
param_json["bot"] = _bot
for par in args_.keys():
if par in ["shop_param"]:
param_list_.append(param)
elif par not in ["args", "kwargs"]:
param_list_.append(param_json.get(par))
if kwargs.get(par) is not None:
del kwargs[par]
return param_list_
async def use(
self, param: ShopParam, **kwargs
) -> Optional[Union[str, MessageSegment]]:
"""
使用道具
:param param: BaseModel
:param kwargs: kwargs
"""
goods_name = param.goods_name
if self.exists(goods_name):
# 使用方法
args = inspect.signature(self._data[goods_name]["func"]).parameters
if args and list(args.keys())[0] != "kwargs":
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
return await self._data[goods_name]["func"](
*self._parse_args(args, param, **kwargs)
)
else:
return self._data[goods_name]["func"](
*self._parse_args(args, param, **kwargs)
)
else:
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
return await self._data[goods_name]["func"](
**kwargs,
)
else:
return self._data[goods_name]["func"](
**kwargs,
)
async def run_handle(self, goods_name: str, type_: str, param: ShopParam, **kwargs):
if self._data[goods_name].get(type_):
for func in self._data[goods_name].get(type_):
args = inspect.signature(func).parameters
if args and list(args.keys())[0] != "kwargs":
if asyncio.iscoroutinefunction(func):
await func(*self._parse_args(args, param, **kwargs))
else:
func(*self._parse_args(args, param, **kwargs))
else:
if asyncio.iscoroutinefunction(func):
await func(**kwargs)
else:
func(**kwargs)
def check_send_success_message(self, goods_name: str) -> bool:
"""
检查是否发送使用成功信息
:param goods_name: 商品名称
"""
if self.exists(goods_name):
return bool(self._data[goods_name]["kwargs"]["send_success_msg"])
return False
def get_kwargs(self, goods_name: str) -> dict:
"""
获取商品使用方法的kwargs
:param goods_name: 商品名称
"""
if self.exists(goods_name):
return self._data[goods_name]["kwargs"]
return {}
def init_model(self, goods_name: str, bot: Bot, event: GroupMessageEvent, num: int, text: str):
return self._data[goods_name]["model"](
**{
"goods_name": goods_name,
"bot": bot,
"event": event,
"user_id": event.user_id,
"group_id": event.group_id,
"num": num,
"message": event.message,
"text": text
}
)
func_manager = GoodsUseFuncManager()
def build_params(
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int, text: str
) -> Tuple[ShopParam, Dict[str, Any]]:
"""
说明:
构造参数
参数:
:param bot: bot
:param event: event
:param goods_name: 商品名称
:param num: 数量
:param text: 其他信息
:return:
"""
_kwargs = func_manager.get_kwargs(goods_name)
return (
func_manager.init_model(goods_name, bot, event, num, text),
{
**_kwargs,
"_bot": bot,
"event": event,
"group_id": event.group_id,
"user_id": event.user_id,
"num": num,
"text": text,
"message": event.message,
"goods_name": goods_name,
},
)
async def effect(
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int, text: str, message: Message
) -> Optional[Union[str, MessageSegment]]:
"""
商品生效
:param bot: Bot
:param event: GroupMessageEvent
:param goods_name: 商品名称
:param num: 使用数量
:param text: 其他信息
:param message: Message
:return: 使用是否成功
"""
# 优先使用注册的商品插件
# try:
if func_manager.exists(goods_name):
_kwargs = func_manager.get_kwargs(goods_name)
model, kwargs = build_params(bot, event, goods_name, num, text)
return await func_manager.use(model, **kwargs)
# except Exception as e:
# logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
return None
def register_use(goods_name: str, func: Callable, **kwargs):
"""
注册商品使用方法
:param goods_name: 商品名称
:param func: 使用函数
:param kwargs: kwargs
"""
if func_manager.exists(goods_name):
raise ValueError("该商品使用函数已被注册!")
# 发送使用成功信息
kwargs["send_success_msg"] = kwargs.get("send_success_msg", True)
kwargs["max_num_limit"] = kwargs.get("max_num_limit", 1)
func_manager.register_use(
goods_name,
**{
"func": func,
"model": create_model(f"{goods_name}_model", __base__=ShopParam, **kwargs),
"kwargs": kwargs,
},
)
logger.info(f"register_use 成功注册商品:{goods_name} 的使用函数")
+11 -10
View File
@@ -1,10 +1,11 @@
import nonebot
nonebot.load_plugins('basic_plugins/super_cmd')
import nonebot
from pathlib import Path
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
+153 -152
View File
@@ -1,152 +1,153 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
from nonebot.rule import to_me
from utils.utils import get_message_text, is_number
from utils.manager import requests_manager
from utils.message_builder import image
from models.group_info import GroupInfo
__zx_plugin_name__ = "显示所有好友群组 [Superuser]"
__plugin_usage__ = """
usage:
显示所有好友群组
指令:
查看所有好友/查看所有群组
同意好友请求 [id]
拒绝好友请求 [id]
同意群聊请求 [id]
拒绝群聊请求 [id]
查看所有请求
清空所有请求
""".strip()
__plugin_des__ = "显示所有好友群组"
__plugin_cmd__ = [
"查看所有好友/查看所有群组",
"同意好友请求 [id]",
"拒绝好友请求 [id]",
"同意群聊请求 [id]",
"拒绝群聊请求 [id]",
"查看所有请求",
"清空所有请求",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
cls_group = on_command(
"查看所有群组", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
cls_friend = on_command(
"查看所有好友", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
friend_handle = on_command(
"同意好友请求", aliases={"拒绝好友请求"}, permission=SUPERUSER, priority=1, block=True
)
group_handle = on_command(
"同意群聊请求", aliases={"拒绝群聊请求"}, permission=SUPERUSER, priority=1, block=True
)
clear_request = on_command("清空所有请求", permission=SUPERUSER, priority=1, block=True)
cls_request = on_command("查看所有请求", permission=SUPERUSER, priority=1, block=True)
@cls_group.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
gl = await bot.get_group_list(self_id=int(bot.self_id))
msg = ["{group_id} {group_name}".format_map(g) for g in gl]
msg = "\n".join(msg)
msg = f"bot:{bot.self_id}\n| 群号 | 群名 | 共{len(gl)}个群\n" + msg
await bot.send_private_msg(
self_id=int(bot.self_id),
user_id=int(list(bot.config.superusers)[0]),
message=msg,
)
@cls_friend.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
gl = await bot.get_friend_list(self_id=int(bot.self_id))
msg = ["{user_id} {nickname}".format_map(g) for g in gl]
msg = "\n".join(msg)
msg = f"| QQ号 | 昵称 | 共{len(gl)}个好友\n" + msg
await bot.send_private_msg(
self_id=int(bot.self_id),
user_id=int(list(bot.config.superusers)[0]),
message=msg,
)
@friend_handle.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
id_ = get_message_text(event.json())
if is_number(id_):
id_ = int(id_)
if state["_prefix"]["raw_command"][:2] == "同意":
if await requests_manager.approve(bot, id_, "private"):
await friend_handle.send("同意好友请求成功..")
else:
await friend_handle.send("同意好友请求失败,可能是未找到此id的请求..")
else:
if await requests_manager.refused(bot, id_, "private"):
await friend_handle.send("拒绝好友请求成功..")
else:
await friend_handle.send("拒绝好友请求失败,可能是未找到此id的请求..")
else:
await friend_handle.send("id必须为纯数字!")
@group_handle.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
id_ = get_message_text(event.json())
if is_number(id_):
id_ = int(id_)
if state["_prefix"]["raw_command"][:2] == "同意":
rid = await requests_manager.approve(bot, id_, "group")
if rid:
await friend_handle.send("同意群聊请求成功..")
if await GroupInfo.get_group_info(rid):
await GroupInfo.set_group_flag(rid, 1)
else:
group_info = await bot.get_group_info(group_id=rid)
await GroupInfo.add_group_info(
rid,
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
)
else:
await friend_handle.send("同意群聊请求失败,可能是未找到此id的请求..")
else:
if await requests_manager.refused(bot, id_, "group"):
await friend_handle.send("拒绝群聊请求成功..")
else:
await friend_handle.send("拒绝群聊请求失败,可能是未找到此id的请求..")
else:
await friend_handle.send("id必须为纯数字!")
@cls_request.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
_str = ""
for type_ in ["private", "group"]:
msg = await requests_manager.show(type_)
if msg:
_str += image(b64=msg)
else:
_str += "没有任何好友请求.." if type_ == "private" else "没有任何群聊请求.."
if type_ == "private":
_str += '\n--------------------\n'
await cls_request.send(Message(_str))
@clear_request.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
requests_manager.clear()
await cls_request.send("已清空所有好友/群聊请求..")
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.adapters.onebot.v11 import Bot, Message
from nonebot.params import Command, CommandArg
from typing import Tuple
from nonebot.rule import to_me
from utils.utils import is_number
from utils.manager import requests_manager
from utils.message_builder import image
from models.group_info import GroupInfo
__zx_plugin_name__ = "显示所有好友群组 [Superuser]"
__plugin_usage__ = """
usage:
显示所有好友群组
指令:
查看所有好友/查看所有群组
同意好友请求 [id]
拒绝好友请求 [id]
同意群聊请求 [id]
拒绝群聊请求 [id]
查看所有请求
清空所有请求
""".strip()
__plugin_des__ = "显示所有好友群组"
__plugin_cmd__ = [
"查看所有好友/查看所有群组",
"同意好友请求 [id]",
"拒绝好友请求 [id]",
"同意群聊请求 [id]",
"拒绝群聊请求 [id]",
"查看所有请求",
"清空所有请求",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
cls_group = on_command(
"查看所有群组", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
cls_friend = on_command(
"查看所有好友", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
friend_handle = on_command(
"同意好友请求", aliases={"拒绝好友请求"}, permission=SUPERUSER, priority=1, block=True
)
group_handle = on_command(
"同意群聊请求", aliases={"拒绝群聊请求"}, permission=SUPERUSER, priority=1, block=True
)
clear_request = on_command("清空所有请求", permission=SUPERUSER, priority=1, block=True)
cls_request = on_command("查看所有请求", permission=SUPERUSER, priority=1, block=True)
@cls_group.handle()
async def _(bot: Bot):
gl = await bot.get_group_list()
msg = ["{group_id} {group_name}".format_map(g) for g in gl]
msg = "\n".join(msg)
msg = f"bot:{bot.self_id}\n| 群号 | 群名 | 共{len(gl)}个群\n" + msg
await cls_group.send(msg)
@cls_friend.handle()
async def _(bot: Bot):
gl = await bot.get_friend_list()
msg = ["{user_id} {nickname}".format_map(g) for g in gl]
msg = "\n".join(msg)
msg = f"| QQ号 | 昵称 | 共{len(gl)}个好友\n" + msg
await cls_friend.send(msg)
@friend_handle.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
id_ = arg.extract_plain_text().strip()
if is_number(id_):
id_ = int(id_)
if cmd[:2] == "同意":
flag = await requests_manager.approve(bot, id_, "private")
else:
flag = await requests_manager.refused(bot, id_, "private")
if flag == 1:
await friend_handle.send(f"{cmd[:2]}好友请求失败,该请求已失效..")
requests_manager.delete_request(id_, "private")
elif flag == 2:
await friend_handle.send(f"{cmd[:2]}好友请求失败,未找到此id的请求..")
else:
await friend_handle.send(f"{cmd[:2]}好友请求成功!")
else:
await friend_handle.send("id必须为纯数字!")
@group_handle.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
id_ = arg.extract_plain_text().strip()
flag = None
if is_number(id_):
id_ = int(id_)
if cmd[:2] == "同意":
rid = requests_manager.get_group_id(id_)
if rid:
if await GroupInfo.get_group_info(rid):
await GroupInfo.set_group_flag(rid, 1)
else:
group_info = await bot.get_group_info(group_id=rid)
await GroupInfo.add_group_info(
rid,
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
)
flag = await requests_manager.approve(bot, id_, "group")
else:
await group_handle.send("同意群聊请求失败,未找到此id的请求..")
else:
flag = await requests_manager.refused(bot, id_, "group")
if flag == 1:
await group_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..")
requests_manager.delete_request(id_, "group")
elif flag == 2:
await group_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..")
else:
await group_handle.send(f"{cmd[:2]}群聊请求成功!")
else:
await group_handle.send("id必须为纯数字!")
@cls_request.handle()
async def _():
_str = ""
for type_ in ["private", "group"]:
msg = await requests_manager.show(type_)
if msg:
_str += image(b64=msg)
else:
_str += "没有任何好友请求.." if type_ == "private" else "没有任何群聊请求.."
if type_ == "private":
_str += '\n--------------------\n'
await cls_request.send(Message(_str))
@clear_request.handle()
async def _():
requests_manager.clear()
await clear_request.send("已清空所有好友/群聊请求..")
+66 -67
View File
@@ -1,67 +1,66 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent
from configs.path_config import TEMP_PATH
from nonebot.rule import to_me
from utils.utils import scheduler
from services.log import logger
from utils.manager import resources_manager
import asyncio
import time
import os
__zx_plugin_name__ = "清理临时数据 [Superuser]"
__plugin_usage__ = """
usage:
清理临时数据
指令:
清理临时数据
""".strip()
__plugin_des__ = "清理临时数据"
__plugin_cmd__ = [
"清理临时数据",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
clear_data = on_command(
"清理临时数据", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
resources_manager.add_temp_dir(TEMP_PATH)
@clear_data.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
await clear_data.send("开始清理临时数据....")
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
def _clear_data() -> float:
size = 0
for dir_ in resources_manager.get_temp_data_dir():
if dir_.exists():
for file in os.listdir(dir_):
file = dir_ / file
try:
if time.time() - os.path.getatime(file) > 300:
file_size = os.path.getsize(file)
file.unlink()
size += file_size
except Exception as e:
logger.error(f"清理临时数据错误...{type(e)}:{e}")
return float(size)
@scheduler.scheduled_job(
"cron",
hour=1,
minute=1,
)
async def _():
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
logger.info("自动清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
from nonebot import on_command
from nonebot.permission import SUPERUSER
from configs.path_config import TEMP_PATH
from nonebot.rule import to_me
from utils.utils import scheduler
from services.log import logger
from utils.manager import resources_manager
import asyncio
import time
import os
__zx_plugin_name__ = "清理临时数据 [Superuser]"
__plugin_usage__ = """
usage:
清理临时数据
指令:
清理临时数据
""".strip()
__plugin_des__ = "清理临时数据"
__plugin_cmd__ = [
"清理临时数据",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
clear_data = on_command(
"清理临时数据", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
resources_manager.add_temp_dir(TEMP_PATH)
@clear_data.handle()
async def _():
await clear_data.send("开始清理临时数据....")
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
def _clear_data() -> float:
size = 0
for dir_ in resources_manager.get_temp_data_dir():
if dir_.exists():
for file in os.listdir(dir_):
file = dir_ / file
if file.is_file():
try:
if time.time() - os.path.getatime(file) > 300:
file_size = os.path.getsize(file)
file.unlink()
size += file_size
except Exception as e:
logger.error(f"清理临时数据错误...{type(e)}:{e}")
return float(size)
@scheduler.scheduled_job(
"cron",
hour=1,
minute=1,
)
async def _():
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
logger.info("自动清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
-74
View File
@@ -1,74 +0,0 @@
# async def open_remind(group: int, name: str) -> str:
# _name = ""
# if name == "zwa":
# _name = "早晚安"
# if name == "dz":
# _name = "地震播报"
# if name == "hy":
# _name = "群欢迎"
# if name == "kxcz":
# _name = "开箱重置提醒"
# if name == "gb":
# _name = "广播"
# if await GroupRemind.get_status(group, name):
# return f"该群已经开启过 {_name} 通知,请勿重复开启!"
# if await GroupRemind.set_status(group, name, True):
# return f"成功开启 {_name} 通知!0v0"
# else:
# return f"开启 {_name} 通知失败了..."
#
#
# async def close_remind(group: int, name: str) -> str:
# _name = ""
# if name == "zwa":
# _name = "早晚安"
# if name == "dz":
# _name = "地震播报"
# if name == "hy":
# _name = "群欢迎"
# if name == "kxcz":
# _name = "开箱重置提醒"
# if name == "gb":
# _name = "广播"
# if not await GroupRemind.get_status(group, name):
# return f"该群已经取消过 {_name} 通知,请勿重复取消!"
# if await GroupRemind.set_status(group, name, False):
# return f"成功关闭 {_name} 通知!0v0"
# else:
# return f"关闭 {_name} 通知失败了..."
# cmd_list = ['总开关', '签到', '发送图片', '色图', '黑白草图', 'coser', '鸡汤/语录', '骂我', '开箱', '鲁迅说', '假消息', '商店系统',
# '操作图片', '查询皮肤', '天气', '疫情', '识番', '搜番', '点歌', 'pixiv', 'rss', '方舟一井', '查干员', '骰子娘', '原神一井']
#
#
# def check_group_switch_json(group_id):
# if not os.path.exists(DATA_PATH + f'rule/group_switch/'):
# os.mkdir(DATA_PATH + f'rule/group_switch/')
# if not os.path.exists(DATA_PATH + f'rule/group_switch/{group_id}.json'):
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as f:
# data = {}
# for cmd in cmd_list:
# data[cmd] = True
# f.write(json.dumps(data, ensure_ascii=False))
# else:
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'r', encoding='utf8') as f:
# try:
# data = json.load(f)
# except ValueError:
# data = {}
# if len(data.keys()) - 1 != len(cmd_list):
# for cmd in cmd_list:
# if cmd not in data.keys():
# data[cmd] = True
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as wf:
# wf.write(json.dumps(data, ensure_ascii=False))
# reload(data)
# for file in os.listdir(DATA_PATH + 'group_help'):
# os.remove(DATA_PATH + f'group_help/{file}')
def reload(data):
static_group_dict = data
+86
View File
@@ -0,0 +1,86 @@
from nonebot.adapters.onebot.v11 import Message, Bot, MessageEvent
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.message_builder import custom_forward_msg
from services.db_context import db
from nonebot.params import CommandArg
from services.log import logger
import asyncio
__zx_plugin_name__ = "执行sql [Superuser]"
__plugin_usage__ = """
usage:
执行一段sql语句
指令:
exec [sql语句] ([查询页数,19条/页])
查看所有表
""".strip()
__plugin_des__ = "执行一段sql语句"
__plugin_cmd__ = [
"exec [sql语句]",
]
__plugin_version__ = 0.2
__plugin_author__ = "HibiKier"
exec_ = on_command("exec", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
tables = on_command("查看所有表", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
@exec_.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
sql = arg.extract_plain_text().strip()
async with db.transaction():
try:
# 判断是否为SELECT语句
if sql.lower().startswith("select"):
# 分割语句
try:
page = int(sql.split(" ")[-1]) - 1
sql_list = sql.split(" ")[:-1]
except ValueError:
page = 0
sql_list = sql.split(" ")
# 拼接语句
sql = " ".join(sql_list)
query = db.text(sql)
res = await db.all(query)
msg_list = [f"第{page+1}页查询结果:"]
# logger.info(res)
# 获取所有字段
keys = res[0].keys()
# 每页10条
for i in res[page * 10 : (page + 1) * 10]:
msg = ""
for key in keys:
msg += f"{key}: {i[key]}\n"
msg += f"第{page+1}页第{res.index(i)+1}条"
msg_list.append(msg)
# 检查是私聊还是群聊
try:
forward_msg_list = custom_forward_msg(msg_list, bot.self_id)
await bot.send_group_forward_msg(group_id=event.group_id, messages=forward_msg_list)
except:
for msg in msg_list:
await exec_.send(msg)
await asyncio.sleep(0.2)
return
query = db.text(sql)
await db.first(query)
await exec_.send("执行 sql 语句成功.")
except Exception as e:
await exec_.send(f"执行 sql 语句失败 {type(e)}:{e}")
logger.error(f"执行 sql 语句失败 {type(e)}:{e}")
@tables.handle()
async def _(bot: Bot, event: MessageEvent):
# 获取所有表
query = db.text("select tablename from pg_tables where schemaname = 'public'")
res = await db.all(query)
msg = "数据库中的所有表名:\n"
for tablename in res:
msg += str(tablename["tablename"]) + "\n"
await tables.finish(msg)
+204 -200
View File
@@ -1,200 +1,204 @@
from nonebot import on_command, on_regex
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GROUP, GroupMessageEvent
from nonebot.rule import to_me
from utils.utils import get_message_text, is_number
from utils.manager import group_manager, plugins2settings_manager
from models.group_info import GroupInfo
from services.log import logger
from configs.config import NICKNAME
from nonebot.adapters.cqhttp.exception import ActionFailed
__zx_plugin_name__ = "管理群操作 [Superuser]"
__plugin_usage__ = """
usage:
群权限 | 群白名单 | 退出群 操作
指令:
退群 [group_id]
修改群权限 [group_id] [等级]
添加群白名单 *[group_id]
删除群白名单 *[group_id]
添加群认证 *[group_id]
删除群认证 *[group_id]
查看群白名单
""".strip()
__plugin_des__ = "管理群操作"
__plugin_cmd__ = [
"退群 [group_id]",
"修改群权限 [group_id] [等级]",
"添加群白名单 *[group_id]",
"删除群白名单 *[group_id]",
"添加群认证 *[group_id]",
"删除群认证 *[group_id]",
"查看群白名单",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
del_group = on_command("退群", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
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
)
group_auth = on_command(
"添加群认证", aliases={"删除群认证"}, priority=1, permission=SUPERUSER, block=True
)
@del_group.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
group_id = get_message_text(event.json())
if group_id:
if is_number(group_id):
try:
await bot.set_group_leave(group_id=int(group_id))
logger.info(f"退出群聊 {group_id} 成功")
await del_group.send(f"退出群聊 {group_id} 成功", at_sender=True)
group_manager.delete_group(int(group_id))
await GroupInfo.delete_group_info(int(group_id))
except Exception as e:
logger.info(f"退出群聊 {group_id} 失败 e:{e}")
else:
await del_group.finish(f"请输入正确的群号", at_sender=True)
else:
await del_group.finish(f"请输入群号", at_sender=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("没有任何群在群白名单...")
@group_auth.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json()).split()
for group_id in msg:
if not is_number(group_id):
await group_auth.send(f"{group_id}非纯数字,已跳过该项..")
group_id = int(group_id)
if state["_prefix"]["raw_command"][:2] == "添加":
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 1)
else:
try:
group_info = await bot.get_group_info(group_id=group_id)
except ActionFailed:
group_info = {
"group_id": group_id,
"group_name": "_",
"max_member_count": -1,
"member_count": -1,
}
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
else:
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 0)
await group_auth.send(
f'已为 {group_id} {state["_prefix"]["raw_command"][:2]}群认证..'
)
from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent,
GROUP,
GroupMessageEvent,
Message,
ActionFailed,
)
from nonebot import on_command, on_regex
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from nonebot.rule import to_me
from utils.utils import is_number
from utils.manager import group_manager, plugins2settings_manager
from models.group_info import GroupInfo
from services.log import logger
from configs.config import NICKNAME
from nonebot.params import Command, CommandArg
from typing import Tuple
__zx_plugin_name__ = "管理群操作 [Superuser]"
__plugin_usage__ = """
usage:
群权限 | 群白名单 | 退出群 操作
指令:
退群 [group_id]
修改群权限 [group_id] [等级]
添加群白名单 *[group_id]
删除群白名单 *[group_id]
添加群认证 *[group_id]
删除群认证 *[group_id]
查看群白名单
""".strip()
__plugin_des__ = "管理群操作"
__plugin_cmd__ = [
"退群 [group_id]",
"修改群权限 [group_id] [等级]",
"添加群白名单 *[group_id]",
"删除群白名单 *[group_id]",
"添加群认证 *[group_id]",
"删除群认证 *[group_id]",
"查看群白名单",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
del_group = on_command("退群", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
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
)
group_auth = on_command(
"添加群认证", aliases={"删除群认证"}, priority=1, permission=SUPERUSER, block=True
)
@del_group.handle()
async def _(bot: Bot, arg: Message = CommandArg()):
group_id = arg.extract_plain_text().strip()
if group_id:
if is_number(group_id):
try:
await bot.set_group_leave(group_id=int(group_id))
logger.info(f"退出群聊 {group_id} 成功")
await del_group.send(f"退出群聊 {group_id} 成功", at_sender=True)
group_manager.delete_group(int(group_id))
await GroupInfo.delete_group_info(int(group_id))
except Exception as e:
logger.info(f"退出群聊 {group_id} 失败 e:{e}")
else:
await del_group.finish(f"请输入正确的群号", at_sender=True)
else:
await del_group.finish(f"请输入群号", at_sender=True)
@add_group_level.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
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 _(event: GroupMessageEvent):
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 _():
await what_up_group_level.finish(
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限"
)
@manager_group_whitelist.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
msg = arg.extract_plain_text().strip().split()
all_group = [g["group_id"] for g in await bot.get_group_list()]
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 cmd 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) + " " + cmd)
else:
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
@show_group_whitelist.handle()
async def _():
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("没有任何群在群白名单...")
@group_auth.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
msg = arg.extract_plain_text().strip().split()
for group_id in msg:
if not is_number(group_id):
await group_auth.send(f"{group_id}非纯数字,已跳过该项..")
group_id = int(group_id)
if cmd[:2] == "添加":
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 1)
else:
try:
group_info = await bot.get_group_info(group_id=group_id)
except ActionFailed:
group_info = {
"group_id": group_id,
"group_name": "_",
"max_member_count": -1,
"member_count": -1,
}
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
else:
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 0)
await group_auth.send(f"已为 {group_id} {cmd[:2]}群认证..")
+72 -40
View File
@@ -1,40 +1,72 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.manager import (
plugins2cd_manager,
plugins2settings_manager,
plugins2block_manager,
group_manager,
)
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent
__zx_plugin_name__ = "重载插件配置 [Superuser]"
__plugin_usage__ = """
usage:
重载插件配置
指令:
重载插件配置
""".strip()
__plugin_des__ = "重载插件配置"
__plugin_cmd__ = [
"重载插件配置",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
reload_plugins_manager = on_command(
"重载插件限制", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
@reload_plugins_manager.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
plugins2settings_manager.reload()
plugins2cd_manager.reload()
plugins2block_manager.reload()
group_manager.reload()
await reload_plugins_manager.send("重载完成...")
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.manager import (
plugins2cd_manager,
plugins2settings_manager,
plugins2block_manager,
group_manager,
)
from configs.config import Config
from services.log import logger
from utils.utils import scheduler
__zx_plugin_name__ = "重载插件配置 [Superuser]"
__plugin_usage__ = """
usage:
重载插件配置
plugins2settings,
plugins2cd
plugins2block
group_manager
指令:
重载插件配置
""".strip()
__plugin_des__ = "重载插件配置"
__plugin_cmd__ = [
"重载插件配置",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_configs__ = {
"AUTO_RELOAD": {
"value": False,
"help": "自动重载配置文件",
"default_value": False
},
"AUTO_RELOAD_TIME": {
"value": 180,
"help": "控制自动重载配置文件时长",
"default_value": 180
}
}
reload_plugins_manager = on_command(
"重载配置", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
@reload_plugins_manager.handle()
async def _():
plugins2settings_manager.reload()
plugins2cd_manager.reload()
plugins2block_manager.reload()
group_manager.reload()
Config.reload()
await reload_plugins_manager.send("重载完成...")
@scheduler.scheduled_job(
'interval',
seconds=Config.get_config("reload_setting", "AUTO_RELOAD_TIME", 180),
)
async def _():
if Config.get_config("reload_setting", "AUTO_RELOAD"):
plugins2settings_manager.reload()
plugins2cd_manager.reload()
plugins2block_manager.reload()
group_manager.reload()
Config.reload()
logger.debug("已自动重载所有配置文件...")
+101 -89
View File
@@ -1,89 +1,101 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from models.level_user import LevelUser
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, Message
from utils.utils import get_message_at, get_message_text, is_number
from services.log import logger
from utils.message_builder import at
__zx_plugin_name__ = "用户权限管理 [Superuser]"
__plugin_usage__ = """
usage:
增删改用户的权限
指令:
添加权限 [at] [权限]
添加权限 [qq] [group_id] [权限]
删除权限 [at]
""".strip()
__plugin_des__ = "增删改用户的权限"
__plugin_cmd__ = [
"添加权限 [at] [权限]",
"添加权限 [qq] [group_id] [权限]",
"删除权限 [at]",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
super_cmd = on_command(
"添加管理",
aliases={"删除管理", "添加权限", "删除权限"},
priority=1,
permission=SUPERUSER,
block=True,
)
@super_cmd.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
group_id = -1
level = 0
try:
args = get_message_text(event.json()).strip().split()
qq = get_message_at(event.json())
flag = -1
if not qq:
if len(args) > 2:
if is_number(args[0]) and is_number(args[1]) and is_number(args[2]):
qq = int(args[0])
group_id = int(args[1])
level = int(args[2])
flag = 1
else:
await super_cmd.finish("所有参数必须是数字!", at_sender=True)
else:
await super_cmd.finish(
"权限参数不完全\n\t格式:添加/删除权限 [at] [level]"
"\n\t格式:添加/删除权限 [qq] [group] [level]",
at_sender=True,
)
else:
qq = qq[0]
group_id = event.group_id
flag = 2
if state["_prefix"]["raw_command"][:2] == "添加":
if is_number(args[0]):
level = int(args[0])
else:
await super_cmd.finish("权限等级必须是数字!", at_sender=True)
if await LevelUser.set_level(qq, group_id, level, 1):
result = "添加管理成功, 权限: " + str(level)
else:
result = "管理已存在, 更新权限: " + str(level)
else:
if await LevelUser.delete_level(qq, event.group_id):
result = "删除管理成功!"
else:
result = "该账号无管理权限!"
if flag == 2:
await super_cmd.send(result)
elif flag == 1:
await bot.send_group_msg(
group_id=group_id,
message=Message(f"{at(qq)}管理员修改了你的权限" f"\n--------\n你当前的权限等级:{level}"),
)
await super_cmd.send("修改成功")
except Exception as e:
await super_cmd.send("执行指令失败!")
logger.error(f"执行指令失败 e:{e}")
from nonebot import on_command
from nonebot.permission import SUPERUSER
from models.level_user import LevelUser
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
from utils.utils import get_message_at, is_number
from services.log import logger
from utils.message_builder import at
from nonebot.params import Command, CommandArg
from typing import Tuple
__zx_plugin_name__ = "用户权限管理 [Superuser]"
__plugin_usage__ = """
usage:
增删改用户的权限
指令:
添加权限 [at] [权限]
添加权限 [qq] [group_id] [权限]
删除权限 [at]
""".strip()
__plugin_des__ = "增删改用户的权限"
__plugin_cmd__ = [
"添加权限 [at] [权限]",
"添加权限 [qq] [group_id] [权限]",
"删除权限 [at]",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
super_cmd = on_command(
"添加管理",
aliases={"删除管理", "添加权限", "删除权限"},
priority=1,
permission=SUPERUSER,
block=True,
)
@super_cmd.handle()
async def _(
bot: Bot,
event: MessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
):
group_id = event.group_id if isinstance(event, GroupMessageEvent) else -1
level = None
args = arg.extract_plain_text().strip().split()
qq = get_message_at(event.json())
flag = 2
try:
if qq:
qq = qq[0]
if cmd[0][:2] == "添加" and args and is_number(args[0]):
level = int(args[0])
else:
if cmd[0][:2] == "添加":
if (
len(args) > 2
and is_number(args[0])
and is_number(args[1])
and is_number(args[2])
):
qq = int(args[0])
group_id = int(args[1])
level = int(args[2])
else:
if len(args) > 1 and is_number(args[0]) and is_number(args[1]):
qq = int(args[0])
group_id = int(args[1])
flag = 1
level = -1 if cmd[0][:2] == "删除" else level
if group_id == -1 or not level or not qq:
raise IndexError()
except IndexError:
await super_cmd.finish(__plugin_usage__)
try:
if cmd[0][:2] == "添加":
if await LevelUser.set_level(qq, group_id, level, 1):
result = f"添加管理成功, 权限: {level}"
else:
result = f"管理已存在, 更新权限: {level}"
else:
if await LevelUser.delete_level(qq, event.group_id):
result = "删除管理成功!"
else:
result = "该账号无管理权限!"
if flag == 2:
await super_cmd.send(result)
elif flag == 1:
await bot.send_group_msg(
group_id=group_id,
message=Message(
f"{at(qq)}管理员修改了你的权限"
f"\n--------\n你当前的权限等级:{level if level != -1 else 0}"
),
)
await super_cmd.send("修改成功")
except Exception as e:
await super_cmd.send("执行指令失败!")
logger.error(f"执行指令失败 e:{e}")
+57 -55
View File
@@ -1,56 +1,58 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent
from nonebot.rule import to_me
from utils.utils import get_message_text, is_number
from services.log import logger
from utils.manager import group_manager
__zx_plugin_name__ = "超级用户被动开关 [Superuser]"
__plugin_usage__ = """
usage:
超级用户被动开关
指令:
开启/关闭广播通知
""".strip()
__plugin_des__ = "超级用户被动开关"
__plugin_cmd__ = [
"开启/关闭广播通知",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
oc_gb = on_command(
"开启广播通知",
aliases={"关闭广播通知"},
rule=to_me(),
permission=SUPERUSER,
priority=1,
block=True,
)
@oc_gb.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
group = get_message_text(event.json())
if group:
if is_number(group):
group = int(group)
for g in await bot.get_group_list():
if g["group_id"] == group:
break
else:
await oc_gb.finish("没有加入这个群...", at_sender=True)
if state["_prefix"]["raw_command"] == "开启广播通知":
logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播")
await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True)
else:
logger.info(f"USER {event.user_id} 关闭了 GROUP {group} 的广播")
await oc_gb.finish(await group_manager.close_group_task(group, "broadcast"), at_sender=True)
else:
await oc_gb.finish("请输入正确的群号", at_sender=True)
else:
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message
from nonebot.rule import to_me
from utils.utils import is_number
from services.log import logger
from utils.manager import group_manager
from nonebot.params import Command, CommandArg
from typing import Tuple
__zx_plugin_name__ = "超级用户被动开关 [Superuser]"
__plugin_usage__ = """
usage:
超级用户被动开关
指令:
开启/关闭广播通知
""".strip()
__plugin_des__ = "超级用户被动开关"
__plugin_cmd__ = [
"开启/关闭广播通知",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
oc_gb = on_command(
"开启广播通知",
aliases={"关闭广播通知"},
rule=to_me(),
permission=SUPERUSER,
priority=1,
block=True,
)
@oc_gb.handle()
async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
group = arg.extract_plain_text().strip()
if group:
if is_number(group):
group = int(group)
for g in await bot.get_group_list():
if g["group_id"] == group:
break
else:
await oc_gb.finish("没有加入这个群...", at_sender=True)
if cmd == "开启广播通知":
logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播")
await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True)
else:
logger.info(f"USER {event.user_id} 关闭了 GROUP {group} 的广播")
await oc_gb.finish(await group_manager.close_group_task(group, "broadcast"), at_sender=True)
else:
await oc_gb.finish("请输入正确的群号", at_sender=True)
else:
await oc_gb.finish("请输入要关闭广播的群号", at_sender=True)
+70 -71
View File
@@ -1,71 +1,70 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent
from nonebot.rule import to_me
from utils.utils import get_bot
from services.log import logger
from models.group_info import GroupInfo
from models.friend_user import FriendUser
__zx_plugin_name__ = "更新群/好友信息 [Superuser]"
__plugin_usage__ = """
usage:
更新群/好友信息
指令:
更新群信息
更新好友信息
""".strip()
__plugin_des__ = "更新群/好友信息"
__plugin_cmd__ = [
"更新群信息",
"更新好友信息",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
update_group_info = on_command(
"更新群信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
update_friend_info = on_command(
"更新好友信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
@update_group_info.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
num = 0
rst = ""
for g in gl:
group_info = await bot.get_group_info(group_id=g)
if await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
):
num += 1
logger.info(f"自动更新群组 {g} 信息成功")
else:
logger.info(f"自动更新群组 {g} 信息失败")
rst += f"{g} 更新失败\n"
await update_group_info.send(f"成功更新了 {num} 个群的信息\n{rst[:-1]}")
@update_friend_info.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
num = 0
rst = ""
fl = await get_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"]} 信息成功')
num += 1
else:
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
rst += f'{f["user_id"]} 更新失败\n'
await update_friend_info.send(f"成功更新了 {num} 个好友的信息\n{rst[:-1]}")
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.utils import get_bot
from services.log import logger
from models.group_info import GroupInfo
from models.friend_user import FriendUser
__zx_plugin_name__ = "更新群/好友信息 [Superuser]"
__plugin_usage__ = """
usage:
更新群/好友信息
指令:
更新群信息
更新好友信息
""".strip()
__plugin_des__ = "更新群/好友信息"
__plugin_cmd__ = [
"更新群信息",
"更新好友信息",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
update_group_info = on_command(
"更新群信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
update_friend_info = on_command(
"更新好友信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
@update_group_info.handle()
async def _():
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
num = 0
rst = ""
for g in gl:
group_info = await bot.get_group_info(group_id=g)
if await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
):
num += 1
logger.info(f"自动更新群组 {g} 信息成功")
else:
logger.info(f"自动更新群组 {g} 信息失败")
rst += f"{g} 更新失败\n"
await update_group_info.send(f"成功更新了 {num} 个群的信息\n{rst[:-1]}")
@update_friend_info.handle()
async def _():
num = 0
rst = ""
fl = await get_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"]} 信息成功')
num += 1
else:
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
rst += f'{f["user_id"]} 更新失败\n'
await update_friend_info.send(f"成功更新了 {num} 个好友的信息\n{rst[:-1]}")
+24 -30
View File
@@ -1,30 +1,24 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from nonebot.adapters import Bot, Event
from nonebot.rule import to_me
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from .data_source import create_help_image
from pathlib import Path
__zx_plugin_name__ = '超级用户帮助 [Superuser]'
superuser_help_image = Path(IMAGE_PATH) / 'superuser_help.png'
if superuser_help_image.exists():
superuser_help_image.unlink()
super_help = on_command(
"超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True
)
@super_help.handle()
async def _(bot: Bot, event: Event, state: T_State):
if not superuser_help_image.exists():
await create_help_image()
x = image(superuser_help_image)
await super_help.finish(x)
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.message_builder import image
from .data_source import create_help_image, SUPERUSER_HELP_IMAGE
__zx_plugin_name__ = '超级用户帮助 [Superuser]'
if SUPERUSER_HELP_IMAGE.exists():
SUPERUSER_HELP_IMAGE.unlink()
super_help = on_command(
"超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True
)
@super_help.handle()
async def _():
if not SUPERUSER_HELP_IMAGE.exists():
await create_help_image()
x = image(SUPERUSER_HELP_IMAGE)
await super_help.finish(x)
+70 -66
View File
@@ -1,80 +1,84 @@
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 nonebot.adapters.cqhttp import Bot
from pathlib import Path
from nonebot import Driver
import asyncio
import nonebot
import nonebot
from configs.path_config import IMAGE_PATH
from nonebot import Driver
from services.log import logger
from utils.image_template import help_template
from utils.image_utils import (BuildImage, build_sort_image, group_image,
text2image)
from utils.manager import plugin_data_manager
from utils.manager.models import PluginType
driver: Driver = nonebot.get_driver()
background = Path(IMAGE_PATH) / "background" / "0.png"
superuser_help_image = Path(IMAGE_PATH) / "superuser_help.png"
SUPERUSER_HELP_IMAGE = IMAGE_PATH / "superuser_help.png"
@driver.on_bot_connect
async def create_help_image(bot: Bot = None):
async def create_help_image():
"""
创建超级用户帮助图片
"""
await asyncio.get_event_loop().run_in_executor(None, _create_help_image)
def _create_help_image():
"""
创建管理员帮助图片
"""
_matchers = get_matchers()
_plugin_name_list = []
width = 0
help_str = "超级用户帮助\n\n* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n"
tmp_img = CreateImg(0, 0, plain_text='1', font_size=24)
for matcher in _matchers:
plugin_name = ""
if SUPERUSER_HELP_IMAGE.exists():
return
plugin_data_ = plugin_data_manager.get_data()
image_list = []
task_list = []
for plugin_data in [
plugin_data_[x]
for x in plugin_data_
if plugin_data_[x].name != "超级用户帮助 [Superuser]"
]:
try:
_plugin = nonebot.plugin.get_plugin(matcher.module)
_module = _plugin.module
try:
plugin_name = _module.__getattribute__("__zx_plugin_name__")
except AttributeError:
continue
is_superuser_usage = False
try:
_ = _module.__getattribute__("__plugin_superuser_usage__")
is_superuser_usage = True
except AttributeError:
pass
if (
("[superuser]" in plugin_name.lower() or is_superuser_usage)
and plugin_name != "超级用户帮助 [Superuser]"
and plugin_name not in _plugin_name_list
and "[hidden]" not in plugin_name.lower()
):
_plugin_name_list.append(plugin_name)
try:
plugin_des = _module.__getattribute__("__plugin_des__")
except AttributeError:
plugin_des = '_'
plugin_cmd = _module.__getattribute__("__plugin_cmd__")
if is_superuser_usage:
plugin_cmd = [x for x in plugin_cmd if "[_superuser]" in x]
plugin_cmd = " / ".join(plugin_cmd).replace('[_superuser]', '').strip()
help_str += f"{plugin_des} -> {plugin_cmd}\n\n"
x = tmp_img.getsize(f"{plugin_des} -> {plugin_cmd}")[0]
width = width if width > x else x
if plugin_data.plugin_type in [PluginType.SUPERUSER, PluginType.ADMIN]:
usage = None
if (
plugin_data.plugin_type == PluginType.SUPERUSER
and plugin_data.usage
):
usage = await text2image(
plugin_data.usage, padding=5, color=(204, 196, 151)
)
if plugin_data.superuser_usage:
usage = await text2image(
plugin_data.superuser_usage, padding=5, color=(204, 196, 151)
)
if usage:
await usage.acircle_corner()
image = await help_template(plugin_data.name, usage)
image_list.append(image)
if plugin_data.task:
for x in plugin_data.task.keys():
task_list.append(plugin_data.task[x])
except Exception as e:
logger.warning(
f"获取超级用户插件 {matcher.module}: {plugin_name} 设置失败... {type(e)}:{e}"
f"获取超级用户插件 {plugin_data.model}: {plugin_data.name} 设置失败... {type(e)}:{e}"
)
height = len(help_str.split("\n")) * 33
width += 500
A = CreateImg(width, height, font_size=24)
_background = CreateImg(width, height, background=background)
A.text((300, 140), help_str)
A.paste(_background, alpha=True)
A.save(superuser_help_image)
logger.info(f"已成功加载 {len(_plugin_name_list)} 条超级用户命令")
task_str = "\n".join(task_list)
task_str = "通过私聊 开启被动/关闭被动 + [被动名称] 来控制全局被动\n----------\n" + task_str
task_image = await text2image(
task_str, padding=5, color=(204, 196, 151)
)
task_image = await help_template("被动任务", task_image)
image_list.append(task_image)
image_group, _ = group_image(image_list)
A = await build_sort_image(image_group, color="#f9f6f2", padding_top=180)
await A.apaste(
BuildImage(0, 0, font="CJGaoDeGuo.otf", plain_text="超级用户帮助", font_size=50),
(50, 30),
True,
)
await A.apaste(
BuildImage(
0,
0,
font="CJGaoDeGuo.otf",
plain_text="注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数",
font_size=30,
font_color="red",
),
(50, 90),
True,
)
await A.asave(SUPERUSER_HELP_IMAGE)
logger.info(f"已成功加载 {len(image_list)} 条超级用户命令")
Regular → Executable
+33 -35
View File
@@ -1,35 +1,33 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, Event
from nonebot.typing import T_State
from utils.message_builder import image
__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": ["更新信息"],
}
update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, block=True)
@update_info.handle()
async def _(bot: Bot, event: Event, state: T_State):
img = image("update_info.png")
if img:
await update_info.finish(image("update_info.png"))
else:
await update_info.finish("目前没有更新信息哦")
from nonebot import on_command
from utils.message_builder import image
__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": ["更新信息"],
}
update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, block=True)
@update_info.handle()
async def _():
img = image("update_info.png")
if img:
await update_info.finish(image("update_info.png"))
else:
await update_info.finish("目前没有更新信息哦")
+6 -4
View File
@@ -1,18 +1,20 @@
import nonebot
from nonebot.adapters.cqhttp import Bot as CQHTTPBot
from nonebot.adapters.onebot.v11 import Adapter
from services.db_context import init, disconnect
nonebot.init()
driver = nonebot.get_driver()
driver.register_adapter("cqhttp", CQHTTPBot)
driver.register_adapter(Adapter)
config = driver.config
driver.on_startup(init)
driver.on_shutdown(disconnect)
# 优先加载定时任务插件
# 优先加载定时任务
nonebot.load_plugin("nonebot_plugin_apscheduler")
nonebot.load_plugins("basic_plugins")
nonebot.load_plugins("plugins")
nonebot.load_plugins("extensive_plugin")
# 最后加载权限控制
nonebot.load_plugins("basic_plugins/hooks")
if __name__ == "__main__":
+7 -2
View File
@@ -2,6 +2,10 @@ from typing import Optional
from pathlib import Path
from .utils import ConfigsManager
import platform
if platform.system() == "Linux":
import os
hostip = os.popen("cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }'").read().replace("\n","")
# 回复消息名称
NICKNAME: str = "小真寻"
@@ -17,8 +21,9 @@ address: str = "" # 数据库地址
port: str = "" # 数据库端口
database: str = "" # 数据库名称
# 全局代理,例如 "http://127.0.0.1:7890"
SYSTEM_PROXY: Optional[str] = None
# 代理,例如 "http://127.0.0.1:7890"
# 如果是WLS 可以 f"http://{hostip}:7890" 使用寄主机的代理
SYSTEM_PROXY: Optional[str] = None # 全局代理
Config = ConfigsManager(Path() / "data" / "configs" / "plugins2config.yaml")
+27 -21
View File
@@ -1,41 +1,47 @@
from pathlib import Path
import os
# 图片路径
IMAGE_PATH = Path("resources/img/")
# 音频路径
VOICE_PATH = Path("resources/voice/")
IMAGE_PATH = Path() / "resources" / "image"
# 语音路径
RECORD_PATH = Path() / "resources" / "record"
# 文本路径
TEXT_PATH = Path("resources/txt/")
TEXT_PATH = Path() / "resources" / "text"
# 日志路径
LOG_PATH = Path("log/")
LOG_PATH = Path() / "log"
# 字体路径
FONT_PATH = Path("resources/ttf/")
FONT_PATH = Path() / "resources" / "font"
# 数据路径
DATA_PATH = Path("data/")
# 临时图片路径
TEMP_PATH = Path("resources/img/temp/")
DATA_PATH = Path() / "data"
# 临时数据路径
TEMP_PATH = Path() / "resources" / "temp"
# 网页模板路径
TEMPLATE_PATH = Path() / "resources" / "template"
def init_path():
global IMAGE_PATH, VOICE_PATH, TEXT_PATH, LOG_PATH, FONT_PATH, DATA_PATH, TEMP_PATH
def load_path():
old_img_dir = Path() / "resources" / "img"
if not IMAGE_PATH.exists() and old_img_dir.exists():
os.rename(old_img_dir, IMAGE_PATH)
old_voice_dir = Path() / "resources" / "voice"
if not RECORD_PATH.exists() and old_voice_dir.exists():
os.rename(old_voice_dir, RECORD_PATH)
old_ttf_dir = Path() / "resources" / "ttf"
if not FONT_PATH.exists() and old_ttf_dir.exists():
os.rename(old_ttf_dir, FONT_PATH)
old_txt_dir = Path() / "resources" / "txt"
if not TEXT_PATH.exists() and old_txt_dir.exists():
os.rename(old_txt_dir, TEXT_PATH)
IMAGE_PATH.mkdir(parents=True, exist_ok=True)
VOICE_PATH.mkdir(parents=True, exist_ok=True)
RECORD_PATH.mkdir(parents=True, exist_ok=True)
TEXT_PATH.mkdir(parents=True, exist_ok=True)
LOG_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()) + '/'
TEXT_PATH = str(TEXT_PATH.absolute()) + '/'
LOG_PATH = str(LOG_PATH.absolute()) + '/'
FONT_PATH = str(FONT_PATH.absolute()) + '/'
DATA_PATH = str(DATA_PATH.absolute()) + '/'
TEMP_PATH = str(TEMP_PATH.absolute()) + '/'
init_path()
load_path()
+88 -11
View File
@@ -1,7 +1,9 @@
import copy
from typing import Optional, Any, Union
from pathlib import Path
from ruamel.yaml import YAML
from ruamel import yaml
from ruamel.yaml.scanner import ScannerError
class ConfigsManager:
@@ -11,14 +13,34 @@ class ConfigsManager:
def __init__(self, file: Path):
self._data: dict = {}
self._simple_data: dict = {}
self._admin_level_data = []
self._simple_file = Path() / "configs" / "config.yaml"
if file:
file.parent.mkdir(exist_ok=True, parents=True)
self.file = file
_yaml = YAML()
if file.exists():
_yaml = YAML()
with open(file, "r", encoding="utf8") as f:
self._data = _yaml.load(f)
if not self._data:
self.file.unlink()
raise ValueError(
"配置文件为空!\n"
"***********************************************************\n"
"****** 配置文件 plugins2config.yaml 为空,已删除,请重启 ******\n"
"***********************************************************"
)
if self._simple_file.exists():
try:
with open(self._simple_file, "r", encoding="utf8") as f:
self._simple_data = _yaml.load(f)
except ScannerError as e:
raise ScannerError(
f"{e}\n**********************************************\n"
f"****** 可能为config.yaml配置文件填写不规范 ******\n"
f"**********************************************"
)
def add_plugin_config(
self,
@@ -29,7 +51,7 @@ class ConfigsManager:
name: Optional[str] = None,
help_: Optional[str] = None,
default_value: Optional[str] = None,
_override: bool = False
_override: bool = False,
):
"""
为插件添加一个配置,不会被覆盖,只有第一个生效
@@ -61,6 +83,7 @@ class ConfigsManager:
"name": name.strip() if isinstance(name, str) else name,
"help": help_.strip() if isinstance(help_, str) else help_,
"default_value": default_value,
"level_module": _module,
}
def remove_plugin_config(self, module: str):
@@ -70,17 +93,26 @@ class ConfigsManager:
"""
if module in self._data.keys():
del self._data[module]
self.save()
def set_config(self, module: str, key: str, value: str):
def set_config(self, module: str, key: str, value: Any, auto_save: bool = False, save_simple_data: bool = True):
"""
设置配置值
:param module: 模块名
:param key: 配置名称
:param value: 值
:param auto_save: 自动保存
:param save_simple_data: 保存至config.yaml
"""
if module in self._data.keys():
if self._data[module].get(key) is not None:
if (
self._data[module].get(key) is not None
and self._data[module][key] != value
):
self._data[module][key]["value"] = value
self._simple_data[module][key] = value
if auto_save:
self.save(save_simple_data=save_simple_data)
def set_help(self, module: str, key: str, help_: str):
"""
@@ -92,8 +124,9 @@ class ConfigsManager:
if module in self._data.keys():
if self._data[module].get(key) is not None:
self._data[module][key]["help"] = help_
self.save()
def set_default_value(self, module: str, key: str, value: str):
def set_default_value(self, module: str, key: str, value: Any):
"""
设置配置默认值
:param module: 模块名
@@ -103,21 +136,39 @@ class ConfigsManager:
if module in self._data.keys():
if self._data[module].get(key) is not None:
self._data[module][key]["default_value"] = value
self.save()
def get_config(self, module: str, key: str) -> Optional[Any]:
def get_config(
self, module: str, key: str, default: Optional[Any] = None
) -> Optional[Any]:
"""
获取指定配置值
:param module: 模块名
:param key: 配置名称
:param default: 没有key值内容的默认返回值
"""
key = key.upper()
if module in self._data.keys():
if self._data[module].get(key) is not None:
if self._data[module][key]["value"] is None:
return self._data[module][key]["default_value"]
return self._data[module][key]["value"]
for key in [key, f"{key} [LEVEL]"]:
if self._data[module].get(key) is not None:
if self._data[module][key]["value"] is None:
return self._data[module][key]["default_value"]
return self._data[module][key]["value"]
if default is not None:
return default
return None
def get_level2module(self, module: str, key: str) -> Optional[str]:
"""
获取指定key所绑定的module,一般为权限等级
:param module: 模块名
:param key: 配置名称
:return:
"""
if self._data.get(module) is not None:
if self._data[module].get(key) is not None:
return self._data[module][key].get("level_module")
def get(self, key: str):
"""
获取插件配置数据
@@ -126,23 +177,49 @@ class ConfigsManager:
if key in self._data.keys():
return self._data[key]
def save(self, path: Union[str, Path] = None):
def save(self, path: Union[str, Path] = None, save_simple_data: bool = False):
"""
保存数据
:param path: 路径
:param save_simple_data: 同时保存至config.yaml
"""
if save_simple_data:
with open(self._simple_file, "w", encoding="utf8") as f:
yaml.dump(
self._simple_data,
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
path = path if path else self.file
with open(path, "w", encoding="utf8") as f:
yaml.dump(
self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def reload(self):
"""
重新加载配置文件
"""
_yaml = YAML()
if self._simple_file.exists():
with open(self._simple_file, "r", encoding="utf8") as f:
self._simple_data = _yaml.load(f)
for key in self._simple_data.keys():
for k in self._simple_data[key].keys():
self._data[key][k]["value"] = self._simple_data[key][k]
self.save()
def get_admin_level_data(self):
"""
获取管理插件等级
"""
return self._admin_level_data
def get_data(self):
return copy.deepcopy(self._data)
def is_empty(self) -> bool:
return not bool(self._data)
+1450 -155
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 799 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Regular → Executable
+130 -127
View File
@@ -1,38 +1,40 @@
from services.db_context import db
from typing import Dict
from typing import Optional, List
from services.log import logger
from .goods_info import GoodsInfo
class BagUser(db.Model):
__tablename__ = "bag_users"
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
belonging_group = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
gold = db.Column(db.Integer(), default=100)
props = db.Column(db.TEXT(), nullable=False, default="")
props = db.Column(db.TEXT(), nullable=False, default="") # 旧道具字段(废弃)
spend_total_gold = db.Column(db.Integer(), default=0)
get_total_gold = db.Column(db.Integer(), default=0)
get_today_gold = db.Column(db.Integer(), default=0)
spend_today_gold = db.Column(db.Integer(), default=0)
property = db.Column(db.JSON(), nullable=False, default={}) # 新道具字段
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "belonging_group", unique=True)
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "group_id", unique=True)
@classmethod
async def get_my_total_gold(cls, user_qq: int, belonging_group: int) -> str:
async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
"""
说明:
说明:
获取金币概况
参数:
参数:
:param user_qq: qq号
:param belonging_group: 所在群号
:param group_id: 所在群号
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first()
if not user:
user = await cls.create(
user_qq=user_qq,
belonging_group=belonging_group,
group_id=group_id,
)
return (
f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}"
@@ -41,191 +43,192 @@ class BagUser(db.Model):
)
@classmethod
async def get_gold(cls, user_qq: int, belonging_group: int) -> int:
async def get_gold(cls, user_qq: int, group_id: int) -> int:
"""
说明:
说明:
获取当前金币
参数:
参数:
:param user_qq: qq号
:param belonging_group: 所在群号
:param group_id: 所在群号
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first()
if user:
return user.gold
else:
await cls.create(
user_qq=user_qq,
belonging_group=belonging_group,
group_id=group_id,
)
return 100
@classmethod
async def get_props(cls, user_qq: int, belonging_group: int) -> str:
async def get_property(cls, user_qq: int, group_id: int, only_active: bool = False) -> Dict[str, int]:
"""
说明:
说明:
获取当前道具
参数:
参数:
:param user_qq: qq号
:param belonging_group: 所在群号
:param group_id: 所在群号
:param only_active: 仅仅获取主动使用的道具
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first()
if user:
return user.props
if only_active and user.property:
data = {}
name_list = [x.goods_name for x in await GoodsInfo.get_all_goods() if not x.is_passive]
for key in [x for x in user.property.keys() if x in name_list]:
data[key] = user.property[key]
return data
return user.property
else:
await cls.create(
user_qq=user_qq,
belonging_group=belonging_group,
group_id=group_id,
)
return ""
return {}
@classmethod
async def add_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
async def add_gold(cls, user_qq: int, group_id: int, num: int):
"""
说明:
说明:
增加金币
参数:
参数:
:param user_qq: qq号
:param belonging_group: 所在群号
:param group_id: 所在群号
:param num: 金币数量
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
try:
if user:
await user.update(
gold=user.gold + num,
get_total_gold=user.get_total_gold + num,
get_today_gold=user.get_today_gold + num,
).apply()
else:
await cls.create(
user_qq=user_qq,
belonging_group=belonging_group,
gold=100 + num,
get_total_gold=num,
get_today_gold=num,
)
return True
except Exception:
return False
if user:
await user.update(
gold=user.gold + num,
get_total_gold=user.get_total_gold + num,
get_today_gold=user.get_today_gold + num,
).apply()
else:
await cls.create(
user_qq=user_qq,
group_id=group_id,
gold=100 + num,
get_total_gold=num,
get_today_gold=num,
)
@classmethod
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
async def spend_gold(cls, user_qq: int, group_id: int, num: int):
"""
说明:
说明:
花费金币
参数:
参数:
:param user_qq: qq号
:param belonging_group: 所在群号
:param group_id: 所在群号
:param num: 金币数量
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
try:
if user:
await user.update(
gold=user.gold - num,
spend_total_gold=user.spend_total_gold + num,
spend_today_gold=user.spend_today_gold + num,
).apply()
else:
await cls.create(
user_qq=user_qq,
belonging_group=belonging_group,
gold=100 - num,
spend_total_gold=num,
spend_today_gold=num,
)
return True
except Exception:
return False
if user:
await user.update(
gold=user.gold - num,
spend_total_gold=user.spend_total_gold + num,
spend_today_gold=user.spend_today_gold + num,
).apply()
else:
await cls.create(
user_qq=user_qq,
group_id=group_id,
gold=100 - num,
spend_total_gold=num,
spend_today_gold=num,
)
@classmethod
async def add_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
async def add_property(cls, user_qq: int, group_id: int, name: str):
"""
说明:
说明:
增加道具
参数:
参数:
:param user_qq: qq号
:param belonging_group: 所在群号
:param group_id: 所在群号
:param name: 道具名称
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
try:
if user:
await user.update(props=user.props + f"{name},").apply()
if user:
p = user.property
if p.get(name) is None:
p[name] = 1
else:
await cls.create(
user_qq=user_qq, belonging_group=belonging_group, props=f"{name},"
)
return True
except Exception:
return False
p[name] += 1
await user.update(property=p).apply()
else:
await cls.create(user_qq=user_qq, group_id=group_id, property={name: 1})
@classmethod
async def del_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
async def delete_property(
cls, user_qq: int, group_id: int, name: str, num: int = 1
) -> bool:
"""
说明:
使用道具
参数:
说明:
使用/删除 道具
参数:
:param user_qq: qq号
:param belonging_group: 所在群号
:param group_id: 所在群号
:param name: 道具名称
:param num: 使用个数
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
try:
if user:
rst = ""
props = user.props
if props.find(name) != -1:
props = props.split(",")
try:
index = props.index(name)
except ValueError:
return False
props = props[:index] + props[index + 1 :]
for p in props:
if p != "":
rst += p + ","
await user.update(props=rst).apply()
return True
if user:
property_ = user.property
if name in property_:
if property_.get(name) == num:
del property_[name]
else:
return False
else:
return False
except Exception:
return False
property_[name] -= num
await user.update(property=property_).apply()
return True
return False
@classmethod
async def buy_property(
cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int
) -> bool:
"""
说明:
购买道具
参数:
:param user_qq: 用户qq
:param group_id: 所在群聊
:param goods: 商品
:param goods_num: 商品数量
"""
try:
# 折扣后金币
spend_gold = goods.goods_discount * goods.goods_price * goods_num
await BagUser.spend_gold(user_qq, group_id, spend_gold)
for _ in range(goods_num):
await BagUser.add_property(user_qq, group_id, goods.goods_name)
return True
except Exception as e:
logger.error(f"buy_property 发生错误 {type(e)}:{e}")
return False
@classmethod
async def get_all_users(cls, group_id: Optional[int] = None) -> List["BagUser"]:
"""
说明:
说明:
获取所有用户数据
参数:
参数:
:param group_id: 群号
"""
if not group_id:
query = await cls.query.gino.all()
else:
query = await cls.query.where((cls.belonging_group == group_id)).gino.all()
query = await cls.query.where((cls.group_id == group_id)).gino.all()
return query
Regular → Executable
+13 -13
View File
@@ -15,9 +15,9 @@ class BanUser(db.Model):
@classmethod
async def check_ban_level(cls, user_qq: int, level: int) -> bool:
"""
说明:
说明:
检测ban掉目标的用户与unban用户的权限等级大小
参数:
参数:
:param user_qq: unban用户的qq号
:param level: ban掉目标用户的权限等级
"""
@@ -31,9 +31,9 @@ class BanUser(db.Model):
@classmethod
async def check_ban_time(cls, user_qq: int) -> str:
"""
说明:
说明:
检测用户被ban时长
参数:
参数:
:param user_qq: qq号
"""
query = cls.query.where((cls.user_qq == user_qq))
@@ -49,9 +49,9 @@ class BanUser(db.Model):
@classmethod
async def is_ban(cls, user_qq: int) -> bool:
"""
说明:
说明:
判断用户是否被ban
参数:
参数:
:param user_qq: qq号
"""
if await cls.check_ban_time(user_qq):
@@ -63,9 +63,9 @@ class BanUser(db.Model):
@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()
@@ -77,12 +77,12 @@ class BanUser(db.Model):
@classmethod
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
"""
说明:
说明:
ban掉目标用户
参数:
参数:
:param user_qq: 目标用户qq号
:param ban_level: 使用ban命令用户的权限
:param duration: ban时长
:param duration: ban时长,秒
"""
query = cls.query.where((cls.user_qq == user_qq))
query = query.with_for_update()
@@ -104,9 +104,9 @@ class BanUser(db.Model):
@classmethod
async def unban(cls, user_qq: int) -> bool:
"""
说明:
说明:
unban用户
参数:
参数:
:param user_qq: qq号
"""
query = cls.query.where((cls.user_qq == user_qq))
+214
View File
@@ -0,0 +1,214 @@
from datetime import datetime, timedelta
from typing import List, Literal, Optional, Tuple, Union
from services.db_context import db
class ChatHistory(db.Model):
__tablename__ = "chat_history"
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger())
text = db.Column(db.Text())
plain_text = db.Column(db.Text())
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
@classmethod
async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str, plain_text: str):
await cls.create(
user_qq=user_qq, group_id=group_id, text=text, plain_text=plain_text, create_time=datetime.now()
)
@classmethod
async def get_user_msg(
cls,
uid: int,
msg_type: Optional[Literal["private", "group"]],
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取用户消息
参数:
:param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊
:param days: 限制日期
"""
return await cls._get_msg(uid, None, "user", msg_type, days).gino.all()
@classmethod
async def get_group_user_msg(
cls,
uid: int,
gid: int,
limit: int = 10,
date_scope: Tuple[datetime, datetime] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊指定用户聊天记录
参数:
:param uid: qq
:param gid: 群号
:param limit: 获取数量
:param date_scope: 日期范围,默认None为全搜索
"""
return (
await cls._get_msg(uid, gid, "group", days=date_scope)
.limit(limit)
.gino.all()
)
@classmethod
async def get_group_user_msg_count(cls, uid: int, gid: int) -> Optional[int]:
"""
说明:
查询群聊指定用户的聊天记录数量
参数:
:param uid: qq
:param gid: 群号
"""
if x := await db.first(
db.text(
f"SELECT COUNT(id) as sum FROM public.chat_history WHERE user_qq = {uid} AND group_id = {gid}"
)
):
return x[0]
return None
@classmethod
async def get_group_msg_rank(
cls,
gid: int,
limit: int = 10,
order: str = "DESC",
date_scope: Optional[Tuple[datetime, datetime]] = None,
) -> Optional[Tuple[int, int]]:
"""
说明:
获取排行数据
参数:
:param gid: 群号
:param limit: 获取数量
:param order: 排序类型,desc,des
:param date_scope: 日期范围
"""
sql = f"SELECT user_qq, COUNT(id) as sum FROM public.chat_history WHERE group_id = {gid} "
if date_scope:
sql += f"AND create_time BETWEEN '{date_scope[0]}' AND '{date_scope[1]}' "
sql += f"GROUP BY user_qq ORDER BY sum {order if order and order.upper() != 'DES' else ''} LIMIT {limit}"
return await db.all(db.text(sql))
@classmethod
async def get_group_first_msg_datetime(cls, gid: int) -> Optional[datetime]:
"""
说明:
获取群第一条记录消息时间
参数:
:param gid:
"""
if (
msg := await cls.query.where(cls.group_id == gid)
.order_by(cls.create_time)
.gino.first()
):
return msg.create_time
return None
@classmethod
async def get_user_msg_count(
cls,
uid: int,
msg_type: Optional[Literal["private", "group"]],
days: Optional[int] = None,
) -> int:
"""
说明:
获取用户消息数量
参数:
:param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊
:param days: 限制日期
"""
return (
await cls._get_msg(uid, None, "user", msg_type, days, True).gino.first()
)[0]
@classmethod
async def get_group_msg(
cls,
gid: int,
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊消息
参数:
:param gid: 用户qq
:param days: 限制日期
"""
return await cls._get_msg(None, gid, "group", None, days).gino.all()
@classmethod
async def get_group_msg_count(
cls,
gid: int,
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊消息数量
参数:
:param gid: 用户qq
:param days: 限制日期
"""
return (await cls._get_msg(None, gid, "group", None, days, True).gino.first())[
0
]
@classmethod
def _get_msg(
cls,
uid: Optional[int],
gid: Optional[int],
type_: Literal["user", "group"],
msg_type: Optional[Literal["private", "group"]] = None,
days: Optional[Union[int, Tuple[datetime, datetime]]] = None,
is_select_count: bool = False,
):
"""
说明:
获取消息查询query
参数:
:param uid: 用户qq
:param gid: 群号
:param type_: 类型,私聊或群聊
:param msg_type: 消息类型,用户或群聊
:param days: 限制日期
"""
if is_select_count:
setattr(ChatHistory, "count", db.func.count(cls.id).label("count"))
query = cls.select("count")
else:
query = cls.query
if type_ == "user":
query = query.where(cls.user_qq == uid)
if msg_type == "private":
query = query.where(cls.group_id == None)
elif msg_type == "group":
query = query.where(cls.group_id != None)
else:
query = query.where(cls.group_id == gid)
if uid:
query = query.where(cls.user_qq == uid)
if days:
if isinstance(days, int):
query = query.where(
cls.create_time >= datetime.now() - timedelta(days=days)
)
elif isinstance(days, tuple):
query = query.where(cls.create_time >= days[0]).where(
cls.create_time <= days[1]
)
return query
Regular → Executable
+17 -11
View File
@@ -1,4 +1,5 @@
from services.db_context import db
from configs.config import Config
class FriendUser(db.Model):
@@ -14,9 +15,9 @@ class FriendUser(db.Model):
@classmethod
async def get_user_name(cls, user_id: int) -> str:
"""
说明:
说明:
获取好友用户名称
参数:
参数:
:param user_id: qq号
"""
query = cls.query.where(cls.user_id == user_id)
@@ -29,9 +30,9 @@ class FriendUser(db.Model):
@classmethod
async def add_friend_info(cls, user_id: int, user_name: str) -> bool:
"""
说明:
说明:
添加好友信息
参数:
参数:
:param user_id: qq号
:param user_name: 用户名称
"""
@@ -54,9 +55,9 @@ class FriendUser(db.Model):
@classmethod
async def delete_friend_info(cls, user_id: int) -> bool:
"""
说明:
说明:
删除好友信息
参数:
参数:
:param user_id: qq号
"""
try:
@@ -71,24 +72,29 @@ class FriendUser(db.Model):
@classmethod
async def get_friend_nickname(cls, user_id: int) -> str:
"""
说明:
说明:
获取用户昵称
参数:
参数:
:param user_id: qq号
"""
query = cls.query.where(cls.user_id == user_id)
user = await query.gino.first()
if user:
if user.nickname:
return user.nickname
_tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
for x in user.nickname:
_tmp += "*" if x in black_word else x
return _tmp
return ""
@classmethod
async def set_friend_nickname(cls, user_id: int, nickname: str) -> bool:
"""
说明:
说明:
设置用户昵称
参数:
参数:
:param user_id: qq号
:param nickname: 昵称
"""
+213
View File
@@ -0,0 +1,213 @@
from services.db_context import db
from typing import Optional, List, Tuple
from services.log import logger
class GoodsInfo(db.Model):
__tablename__ = "goods_info"
id = db.Column(db.Integer(), primary_key=True)
goods_name = db.Column(db.TEXT(), nullable=False) # 名称
goods_price = db.Column(db.Integer(), nullable=False) # 价格
goods_description = db.Column(db.TEXT(), nullable=False) # 商品描述
goods_discount = db.Column(db.Numeric(scale=3, asdecimal=False), default=1) # 打折
goods_limit_time = db.Column(db.BigInteger(), default=0) # 限时
daily_limit = db.Column(db.Integer(), nullable=False, default=0) # 每日购买限制
daily_purchase_limit = db.Column(
db.JSON(), nullable=False, default={}
) # 每日购买限制数据存储
is_passive = db.Column(db.Boolean(), nullable=False, default=0) # 是否为被动
icon = db.Column(db.String(), default=0) # 图标
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
@classmethod
async def add_goods(
cls,
goods_name: str,
goods_price: int,
goods_description: str,
goods_discount: float = 1,
goods_limit_time: int = 0,
daily_limit: int = 0,
is_passive: bool = False,
icon: Optional[str] = None,
) -> bool:
"""
说明:
添加商品
参数:
:param goods_name: 商品名称
:param goods_price: 商品价格
:param goods_description: 商品简介
:param goods_discount: 商品折扣
:param goods_limit_time: 商品限时
:param daily_limit: 每日购买限制
:param is_passive: 是否为被动道具
:param icon: 图标
"""
try:
if not await cls.get_goods_info(goods_name):
await cls.create(
goods_name=goods_name,
goods_price=goods_price,
goods_description=goods_description,
goods_discount=goods_discount,
goods_limit_time=goods_limit_time,
daily_limit=daily_limit,
is_passive=is_passive,
icon=icon
)
return True
except Exception as e:
logger.error(f"GoodsInfo add_goods {goods_name} 发生错误 {type(e)}:{e}")
return False
@classmethod
async def delete_goods(cls, goods_name: str) -> bool:
"""
说明:
删除商品
参数:
:param goods_name: 商品名称
"""
query = (
await cls.query.where(cls.goods_name == goods_name)
.with_for_update()
.gino.first()
)
if not query:
return False
await query.delete()
return True
@classmethod
async def update_goods(
cls,
goods_name: str,
goods_price: Optional[int] = None,
goods_description: Optional[str] = None,
goods_discount: Optional[float] = None,
goods_limit_time: Optional[int] = None,
daily_limit: Optional[int] = None,
is_passive: Optional[bool] = None,
icon: Optional[str] = None,
) -> bool:
"""
说明:
更新商品信息
参数:
:param goods_name: 商品名称
:param goods_price: 商品价格
:param goods_description: 商品简介
:param goods_discount: 商品折扣
:param goods_limit_time: 商品限时时间
:param daily_limit: 每日次数限制
:param is_passive: 是否为被动
:param icon: 图标
"""
try:
query = (
await cls.query.where(cls.goods_name == goods_name)
.with_for_update()
.gino.first()
)
if not query:
return False
await query.update(
goods_price=goods_price or query.goods_price,
goods_description=goods_description or query.goods_description,
goods_discount=goods_discount or query.goods_discount,
goods_limit_time=goods_limit_time if goods_limit_time is not None else query.goods_limit_time,
daily_limit=daily_limit if daily_limit is not None else query.daily_limit,
is_passive=is_passive if is_passive is not None else query.is_passive,
icon=icon or query.icon
).apply()
return True
except Exception as e:
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
return False
@classmethod
async def get_goods_info(cls, goods_name: str) -> "GoodsInfo":
"""
说明:
获取商品对象
参数:
:param goods_name: 商品名称
"""
return await cls.query.where(cls.goods_name == goods_name).gino.first()
@classmethod
async def get_all_goods(cls) -> List["GoodsInfo"]:
"""
说明:
获得全部有序商品对象
"""
query = await cls.query.gino.all()
id_lst = [x.id for x in query]
goods_lst = []
for _ in range(len(query)):
min_id = min(id_lst)
goods_lst.append([x for x in query if x.id == min_id][0])
id_lst.remove(min_id)
return goods_lst
@classmethod
async def add_user_daily_purchase(
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
):
"""
说明:
添加用户明日购买限制
参数:
:param goods: 商品
:param user_id: 用户id
:param group_id: 群号
:param num: 数量
"""
user_id = str(user_id)
group_id = str(group_id)
if goods and goods.daily_limit and goods.daily_limit > 0:
if not goods.daily_purchase_limit.get(group_id):
goods.daily_purchase_limit[group_id] = {}
if not goods.daily_purchase_limit[group_id].get(user_id):
goods.daily_purchase_limit[group_id][user_id] = 0
goods.daily_purchase_limit[group_id][user_id] += num
await goods.update(daily_purchase_limit=goods.daily_purchase_limit).apply()
@classmethod
async def check_user_daily_purchase(
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
) -> Tuple[bool, int]:
"""
说明:
检测用户每日购买上限
参数:
:param goods: 商品
:param user_id: 用户id
:param group_id: 群号
:param num: 数量
"""
user_id = str(user_id)
group_id = str(group_id)
if goods and goods.daily_limit > 0:
if (
not goods.daily_limit
or not goods.daily_purchase_limit.get(group_id)
or not goods.daily_purchase_limit[group_id].get(user_id)
):
return goods.daily_limit - num < 0, goods.daily_limit
if goods.daily_purchase_limit[group_id][user_id] + num > goods.daily_limit:
return (
True,
goods.daily_limit - goods.daily_purchase_limit[group_id][user_id],
)
return False, 0
@classmethod
async def reset_daily_purchase(cls):
"""
重置每次次数限制
"""
await cls.update.values(daily_purchase_limit={}).gino.status()
Regular → Executable
+7 -7
View File
@@ -17,9 +17,9 @@ class GroupInfo(db.Model):
@classmethod
async def get_group_info(cls, group_id: int) -> "GroupInfo":
"""
说明:
说明:
获取群信息
参数:
参数:
:param group_id: 群号
"""
query = cls.query.where(cls.group_id == group_id)
@@ -35,9 +35,9 @@ class GroupInfo(db.Model):
group_flag: Optional[int] = None,
) -> bool:
"""
说明:
说明:
添加群信息
参数:
参数:
:param group_id: 群号
:param group_name: 群名称
:param max_member_count: 群员最大数量
@@ -74,9 +74,9 @@ class GroupInfo(db.Model):
@classmethod
async def delete_group_info(cls, group_id: int):
"""
说明:
说明:
删除群信息
参数:
参数:
:param group_id: 群号
"""
await cls.delete.where(cls.group_id == group_id).gino.status()
@@ -84,7 +84,7 @@ class GroupInfo(db.Model):
@classmethod
async def get_all_group(cls) -> List["GroupInfo"]:
"""
说明:
说明:
获取所有群对象
"""
query = await cls.query.gino.all()
Regular → Executable
+59 -41
View File
@@ -1,5 +1,5 @@
from datetime import datetime
from configs.config import Config
from services.db_context import db
from typing import List, Optional
@@ -10,41 +10,41 @@ class GroupInfoUser(db.Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
user_name = db.Column(db.Unicode(), nullable=False)
belonging_group = db.Column(db.BigInteger(), nullable=False)
group_id = 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)
_idx1 = db.Index("info_group_users_idx1", "user_qq", "group_id", unique=True)
@classmethod
async def add_member_info(
cls,
user_qq: int,
belonging_group: int,
group_id: int,
user_name: str,
user_join_time: datetime,
uid: Optional[int] = None,
) -> bool:
"""
说明:
说明:
添加群内用户信息
参数:
参数:
:param user_qq: qq号
:param belonging_group: 群号
:param group_id: 群号
:param user_name: 用户名称
:param user_join_time: 入群时间
:param uid: 用户唯一 id(自动生成)
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
try:
if not await query.gino.first():
await cls.create(
user_qq=user_qq,
user_name=user_name,
belonging_group=belonging_group,
group_id=group_id,
user_join_time=user_join_time,
uid=uid
)
@@ -54,31 +54,31 @@ class GroupInfoUser(db.Model):
@classmethod
async def get_member_info(
cls, user_qq: int, belonging_group: int
cls, user_qq: int, group_id: int
) -> "GroupInfoUser":
"""
说明:
说明:
查询群员信息
参数:
参数:
:param user_qq: qq号
:param belonging_group: 群号
:param group_id: 群号
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
return await query.gino.first()
@classmethod
async def delete_member_info(cls, user_qq: int, belonging_group: int) -> bool:
async def delete_member_info(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
说明:
删除群员信息
参数:
参数:
:param user_qq: qq号
:param belonging_group: 群号
:param group_id: 群号
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
query = query.with_for_update()
user = await query.gino.first()
@@ -87,40 +87,40 @@ class GroupInfoUser(db.Model):
return True
else:
await cls.delete.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
(cls.user_qq == user_qq) & (cls.group_id == group_id)
).gino.status()
return True
except Exception:
return False
@classmethod
async def get_group_member_id_list(cls, belonging_group: int) -> List[int]:
async def get_group_member_id_list(cls, group_id: int) -> List[int]:
"""
说明:
说明:
获取该群所有用户qq
参数:
:param belonging_group: 群号
参数:
:param group_id: 群号
"""
member_list = []
query = cls.query.where((cls.belonging_group == belonging_group))
query = cls.query.where((cls.group_id == group_id))
for user in await query.gino.all():
member_list.append(user.user_qq)
return member_list
@classmethod
async def set_group_member_nickname(
cls, user_qq: int, belonging_group: int, nickname: str
cls, user_qq: int, group_id: int, nickname: str
) -> bool:
"""
说明:
说明:
设置群员在该群内的昵称
参数:
参数:
:param user_qq: qq号
:param belonging_group: 群号
:param group_id: 群号
:param nickname: 昵称
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
user = await query.with_for_update().gino.first()
if user:
@@ -129,30 +129,48 @@ class GroupInfoUser(db.Model):
return False
@classmethod
async def get_group_member_nickname(cls, user_qq: int, belonging_group: int) -> str:
async def get_user_all_group(cls, user_qq: int) -> List[int]:
"""
说明:
说明:
获取该用户所在的所有群聊
参数:
:param user_qq: 用户qq
"""
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
if query:
query = [x.group_id for x in query]
return query
@classmethod
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
"""
说明:
获取用户在该群的昵称
参数:
参数:
:param user_qq: qq号
:param belonging_group: 群号
:param group_id: 群号
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
user = await query.gino.first()
if user:
if user.nickname:
return user.nickname
_tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
for x in user.nickname:
_tmp += "*" if x in black_word else x
return _tmp
return ""
@classmethod
async def get_group_member_uid(cls, user_qq: int, belonging_group: int) -> Optional[str]:
async def get_group_member_uid(cls, user_qq: int, group_id: int) -> Optional[str]:
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
user = await query.gino.first()
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.belonging_group == 114514)).with_for_update()
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.group_id == 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:
@@ -162,9 +180,9 @@ class GroupInfoUser(db.Model):
return x.uid
else:
if not user:
await GroupInfoUser.add_member_info(user_qq, belonging_group, '', datetime.min)
await GroupInfoUser.add_member_info(user_qq, group_id, '', datetime.min)
user = await cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
(cls.user_qq == user_qq) & (cls.group_id == group_id)
).gino.first()
await user.update(
uid=_max_uid + 1,
Regular → Executable
+25 -20
View File
@@ -1,3 +1,5 @@
from asyncpg import UniqueViolationError
from services.db_context import db
@@ -15,9 +17,9 @@ class LevelUser(db.Model):
@classmethod
async def get_user_level(cls, user_qq: int, group_id: int) -> int:
"""
说明:
说明:
获取用户在群内的等级
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
@@ -33,9 +35,9 @@ class LevelUser(db.Model):
cls, user_qq: int, group_id: int, level: int, group_flag: int = 0
) -> bool:
"""
说明:
说明:
设置用户在群内的权限
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param level: 权限等级
@@ -44,24 +46,27 @@ class LevelUser(db.Model):
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
if user is None:
await cls.create(
user_qq=user_qq,
group_id=group_id,
user_level=level,
group_flag=group_flag,
)
return True
else:
await user.update(user_level=level, group_flag=group_flag).apply()
try:
if not user:
await cls.create(
user_qq=user_qq,
group_id=group_id,
user_level=level,
group_flag=group_flag,
)
return True
else:
await user.update(user_level=level, group_flag=group_flag).apply()
return False
except UniqueViolationError:
return False
@classmethod
async def delete_level(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
说明:
删除用户权限
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
@@ -77,9 +82,9 @@ class LevelUser(db.Model):
@classmethod
async def check_level(cls, user_qq: int, group_id: int, level: int) -> bool:
"""
说明:
说明:
检查用户权限等级是否大于 level
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param level: 权限等级
@@ -107,9 +112,9 @@ class LevelUser(db.Model):
@classmethod
async def is_group_flag(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
说明:
检测是否会被自动更新刷新权限
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
Regular → Executable
+41 -14
View File
@@ -1,5 +1,5 @@
from datetime import datetime
from typing import List
from services.db_context import db
@@ -8,8 +8,7 @@ class SignGroupUser(db.Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
belonging_group = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
checkin_count = db.Column(db.Integer(), nullable=False)
checkin_time_last = db.Column(db.DateTime(timezone=True), nullable=False)
impression = db.Column(db.Numeric(scale=3, asdecimal=False), nullable=False)
@@ -20,28 +19,56 @@ class SignGroupUser(db.Model):
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
)
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "belonging_group", unique=True)
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "group_id", unique=True)
@classmethod
async def ensure(
cls, user_qq: int, belonging_group: int, for_update: bool = False
cls, user_qq: int, group_id: int, for_update: bool = False
) -> "SignGroupUser":
"""
说明:
获取签到用户
参数:
:param user_qq: 用户qq
:param group_id: 所在群聊
:param for_update: 是否存在修改数据
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
if for_update:
query = query.with_for_update()
user = await query.gino.first()
return user or await cls.create(
user_qq=user_qq,
belonging_group=belonging_group,
group_id=group_id,
checkin_count=0,
checkin_time_last=datetime.min, # 从未签到过
impression=0,
)
@classmethod
async def get_user_all_data(cls, user_qq: int) -> List["SignGroupUser"]:
"""
说明:
获取某用户所有数据
参数:
:param user_qq: 用户qq
"""
query = cls.query.where(cls.user_qq == user_qq)
query = query.with_for_update()
return await query.gino.all()
@classmethod
async def sign(cls, user: "SignGroupUser", impression: float, checkin_time_last: datetime):
"""
说明:
签到
说明:
:param user: 用户
:param impression: 增加的好感度
:param checkin_time_last: 签到时间
"""
await user.update(
checkin_count=user.checkin_count + 1,
checkin_time_last=checkin_time_last,
@@ -51,22 +78,22 @@ class SignGroupUser(db.Model):
).apply()
@classmethod
async def get_all_impression(cls, belonging_group: int) -> "list, list, list":
async def get_all_impression(cls, group_id: int) -> "list, list, list":
"""
说明:
说明:
获取该群所有用户 id 及对应 好感度
参数:
:param belonging_group: 群号
参数:
:param group_id: 群号
"""
impression_list = []
user_qq_list = []
user_group = []
if belonging_group:
query = cls.query.where(cls.belonging_group == belonging_group)
if group_id:
query = cls.query.where(cls.group_id == group_id)
else:
query = cls.query
for user in await query.gino.all():
impression_list.append(user.impression)
user_qq_list.append(user.user_qq)
user_group.append(user.belonging_group)
user_group.append(user.group_id)
return user_qq_list, impression_list, user_group
+59
View File
@@ -0,0 +1,59 @@
from datetime import datetime
from services.db_context import db
class UserShopGoldLog(db.Model):
__tablename__ = "user_shop_gold_log"
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
type = db.Column(db.Integer(), nullable=False) # 0: 购买,1: 使用,2: 插件
name = db.Column(db.String())
spend_gold = db.Column(db.Integer(), nullable=False)
num = db.Column(db.Integer(), nullable=False)
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
@classmethod
async def add_shop_log(
cls,
user_qq: int,
group_id: int,
type_: int,
name: str,
num: int,
spend_gold: int = 0,
):
"""
说明:
添加商店购买或使用日志
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param type_: 类型
:param name: 商品名称
:param num: 数量
:param spend_gold: 花费金币
"""
await cls.create(
user_qq=user_qq,
group_id=group_id,
type=type_,
name=name,
num=num,
spend_gold=spend_gold,
create_time=datetime.now(),
)
@classmethod
async def get_user_log(cls, user_qq: int, group_id: int) -> "UserShopGoldLog":
"""
说明:
获取用户日志
参数:
:param user_qq: qq号
:param group_id: 所在群号
"""
return await cls.query.where(
(cls.user_qq == user_qq) & (cls.group_qq == group_id)
).first()
View File

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