Compare commits

...
646 Commits
Author SHA1 Message Date
HibiKier 30bcef32e4 Update README.md 2023-03-12 21:56:57 +08:00
HibiKier 33d5cd6b5c fix bug 2023-03-12 21:53:15 +08:00
HibiKier c574459485 UPDATE README.MD 2023-03-12 19:56:37 +08:00
HibiKier ca9933a489 Merge pull request #1301 from YuS1aN/main
色图bug修复、增加指令
2023-03-12 19:55:21 +08:00
HibiKier 429b7e38b5 Update data_source.py 2023-03-12 19:54:11 +08:00
HibiKier 8c7110ae85 UPDATE README.MD 2023-03-12 19:50:24 +08:00
HibiKier a43a7b5f75 更新开箱指令 2023-03-12 19:50:08 +08:00
HibiKier 5b9218251e Merge pull request #1299 from LambdaYH/patch-7
签到卡片中今日增加的好感度被显示成总好感度了
2023-03-09 19:42:05 +08:00
HibiKier 461ca0af32 Merge pull request #1302 from LambdaYH/patch-8
更正sql语句
2023-03-09 19:38:49 +08:00
Cinte 97443a11e2 Update bag_user.py 2023-03-08 10:13:16 +08:00
sean 5aff21aab2 1. 修复某些情况下会发出两张图片的问题
2. 限制色图连发图片数量
3. 连发正则新增指令
2023-03-07 22:50:04 +08:00
HibiKier 1cbe807b05 fix bug 2023-03-06 22:52:15 +08:00
Cinte d8ea0c6baf Update utils.py 2023-03-06 13:00:11 +08:00
HibiKier d6ef64c70a fix bug 2023-03-05 23:19:54 +08:00
HibiKier b31fbf5810 修复开箱BUG 2023-03-05 23:11:04 +08:00
HibiKier f2ab119397 modified: README.md 2023-03-05 21:00:28 +08:00
HibiKier 33e42be32d 更新开箱会记录箱子数据以及开箱时箱子价格加入花费 2023-03-05 21:00:05 +08:00
HibiKier 8c92756493 fix bug 2023-03-04 22:53:36 +08:00
HibiKier c2ca09867a fix bug 2023-03-04 21:12:21 +08:00
HibiKier a1eb981fd4 UPDATE README.MD 2023-03-04 20:38:05 +08:00
HibiKier e32f086b8a 新增开箱日志以及自动更新武器箱 2023-03-04 20:32:03 +08:00
HibiKier bdfdbbcaeb 重写翻译,使用百度翻译API 2023-03-04 17:51:18 +08:00
HibiKier 3cdabb7d81 修复词条单图片/表情/at无法添加 2023-03-02 22:45:37 +08:00
HibiKier 422ed2ff51 fix bug 2023-03-02 21:59:07 +08:00
HibiKier 6e76ffb60f 修复词云 2023-03-02 21:01:11 +08:00
HibiKier eaa809931c 修复我的签到签到图片 2023-03-02 20:47:23 +08:00
HibiKier 4163435c84 更正BuffSkin添加语句 2023-03-02 19:33:08 +08:00
HibiKier 99263ab36a Merge pull request #1287 from yajiwa/main
修复签到
2023-03-02 19:30:33 +08:00
HibiKier 0d76fa8560 Merge pull request #1288 from LambdaYH/patch-6
修复config.yaml中把False也当成None的问题
2023-03-02 19:29:41 +08:00
Cinte c3644576b8 顺便把写错的type改回来 2023-03-02 18:31:36 +08:00
Cinte 325e345b4e Update __init__.py 2023-03-02 18:17:07 +08:00
yajiwa 3b7972454d no message 2023-03-02 11:31:42 +08:00
yajiwa 6af5e42bf0 fix sign_in bug 2023-03-02 11:29:54 +08:00
HibiKier edc68921c9 修复消息统计 2023-03-01 23:24:56 +08:00
HibiKier 83c3f44ae7 重写开箱更新箱子,允许更新目前所有箱子的皮肤 2023-03-01 22:54:03 +08:00
HibiKier 6d7e79e9de Merge pull request #1282 from MobiusT/main
修复同意群聊请求以及添加群认证 更新变成查询的问题
2023-02-28 20:08:40 +08:00
HibiKier 401029bd27 Merge pull request #1283 from LambdaYH/main
把Config的type字段默认类型由str改为None
2023-02-28 20:07:03 +08:00
LambdaYH 33a0477fab 把Config的type字段默认类型由str改为None 2023-02-27 21:39:13 +08:00
HibiKier 6826c10a09 fix bug 2023-02-27 19:44:47 +08:00
HibiKier 8133b61ebd Config提供type字段确定配置项类型 2023-02-26 22:17:26 +08:00
MobiusT 898d7b40b3 补充群认证同样问题 2023-02-26 20:42:50 +08:00
MobiusT 5a9beb2e5c 修复同意群聊请求出错 2023-02-26 20:28:10 +08:00
HibiKier a63fda8a0d UPDATE README.MD 2023-02-25 17:42:08 +08:00
HibiKier 0baf043f74 Merge pull request #1275 from unknownsno/main
修复ys查询,尘歌壶背景尺寸与内容不匹配的问题
2023-02-25 16:59:41 +08:00
HibiKier cbc32a79d2 Merge pull request #1274 from yajiwa/main
update coser
2023-02-25 16:51:28 +08:00
HibiKier df5a68bcec fix bug 2023-02-25 16:42:09 +08:00
HibiKier 1ca6a67a24 Update __init__.py 2023-02-23 21:01:12 +08:00
unknownsno f27a537f70 修复ys查询,尘歌壶背景尺寸与内容不匹配的问题 2023-02-22 22:48:24 +08:00
yajiwa aa76fae386 update coser 2023-02-22 17:51:51 +08:00
HibiKier d35d53825c Merge branch 'main' of https://github.com/HibiKier/zhenxun_bot 2023-02-21 20:41:38 +08:00
HibiKier 7f743141fb modified: models/level_user.py 2023-02-21 20:40:51 +08:00
HibiKier fa88a08d8e UPDATE pypoetry.toml 2023-02-21 20:38:19 +08:00
HibiKier 06d0bb1ab2 Update level_user.py 2023-02-21 20:34:45 +08:00
HibiKier 3c0f35b3b7 UPDATE pyproject.toml 2023-02-21 20:32:38 +08:00
HibiKier 396d9c1a65 Merge branch 'main' of https://github.com/HibiKier/zhenxun_bot 2023-02-20 22:14:54 +08:00
HibiKier e41f3a4ce7 char_history新增_run_script 2023-02-20 22:14:40 +08:00
HibiKier 8f9e4d6e4f Merge pull request #1270 from MobiusT/main
chat_history部分字段调整为可null
2023-02-20 22:09:25 +08:00
HibiKier d0764f0865 Update chat_history.py 2023-02-20 22:08:01 +08:00
MobiusT ab32eedbb9 chat_history部分字段调整为可null
字段group_id、text、plain_text修改为可空
使新建表结构与旧版基本一致
并且修复以下报错
CMD[定时任务] 定时批量添加聊天记录 || 错误 <class 'ValueError'>: group_id is non nullable field, but null was passed
2023-02-20 21:09:19 +08:00
HibiKier 73f858e071 Merge pull request #1266 from yajiwa/main
修复b站订阅添加失败的问题
2023-02-20 19:11:02 +08:00
yajiwa 73b4a1254c fix bilibili_sub bug 2023-02-20 00:04:05 +08:00
HibiKier fbf82d999f 修改BUG 2023-02-19 17:17:55 +08:00
HibiKier 1f68481256 modified: README.md
modified:   basic_plugins/super_cmd/reload_setting.py
2023-02-19 12:33:22 +08:00
HibiKier 876cfb421a 执行_run_script添加try 2023-02-19 12:29:51 +08:00
HibiKier c97f1bd750 Merge branch 'main' of https://github.com/HibiKier/zhenxun_bot 2023-02-19 00:08:45 +08:00
HibiKier e4dec9f0de word_bank执行添加to_me字段 2023-02-19 00:08:26 +08:00
HibiKier 282b4c102f Update README.md 2023-02-18 23:03:39 +08:00
HibiKier 37e0003810 Update config.py 2023-02-18 23:03:30 +08:00
HibiKier 42683e4f09 Merge branch 'main' of https://github.com/HibiKier/zhenxun_bot 2023-02-18 22:58:56 +08:00
HibiKier 6352ea7c6f update README.md 2023-02-18 22:57:40 +08:00
HibiKier 40c10e672c Merge pull request #1258 from McElaga/main
细节优化,原神今日素材重写
2023-02-18 22:56:43 +08:00
HibiKier fef85190c5 Merge branch 'main' into main 2023-02-18 22:56:25 +08:00
HibiKier eea1be0fc1 Merge pull request #1257 from yajiwa/main
解决开红包经常误触的问题
2023-02-18 22:53:13 +08:00
HibiKier 633862d121 Merge pull request #1263 from CRAZYShimakaze/main
修复插件帮助命令不生效的问题
2023-02-18 22:05:58 +08:00
HibiKier 86ac770971 modified: README.md 2023-02-18 18:48:36 +08:00
HibiKier 7685b95031 modified: basic_plugins/admin_bot_manage/_data_source.py
modified:   basic_plugins/admin_bot_manage/admin_config.py
	modified:   basic_plugins/admin_bot_manage/custom_welcome_message.py
	modified:   basic_plugins/admin_bot_manage/timing_task.py
	modified:   basic_plugins/apscheduler/__init__.py
	modified:   basic_plugins/ban/__init__.py
	modified:   basic_plugins/ban/data_source.py
	modified:   basic_plugins/chat_history/chat_message.py
	modified:   basic_plugins/chat_history/chat_message_handle.py
	modified:   basic_plugins/group_handle/__init__.py
	modified:   basic_plugins/hooks/_utils.py
	modified:   basic_plugins/hooks/ban_hook.py
	modified:   basic_plugins/hooks/chkdsk_hook.py
	modified:   basic_plugins/init_plugin_config/__init__.py
	deleted:    basic_plugins/init_plugin_config/init_group_manager.py
	modified:   basic_plugins/invite_manager/__init__.py
	new file:   basic_plugins/invite_manager/utils.py
	modified:   basic_plugins/nickname.py
	modified:   basic_plugins/plugin_shop/__init__.py
	modified:   basic_plugins/plugin_shop/data_source.py
	modified:   basic_plugins/scripts.py
	modified:   basic_plugins/shop/__init__.py
	modified:   basic_plugins/shop/buy.py
	modified:   basic_plugins/shop/gold.py
	modified:   basic_plugins/shop/my_props/__init__.py
	deleted:    basic_plugins/shop/reset_today_gold.py
	modified:   basic_plugins/shop/shop_handle/__init__.py
	modified:   basic_plugins/shop/shop_handle/data_source.py
	modified:   basic_plugins/shop/use/__init__.py
	modified:   basic_plugins/shop/use/data_source.py
	modified:   basic_plugins/super_cmd/__init__.py
	modified:   basic_plugins/super_cmd/bot_friend_group.py
	modified:   basic_plugins/super_cmd/clear_data.py
	modified:   basic_plugins/super_cmd/exec_sql.py
	modified:   basic_plugins/super_cmd/manager_group.py
	modified:   basic_plugins/super_cmd/reload_setting.py
	modified:   basic_plugins/super_cmd/set_admin_permissions.py
	deleted:    basic_plugins/super_cmd/super_task_switch.py
	modified:   basic_plugins/super_cmd/update_friend_group_info.py
	modified:   basic_plugins/super_help/__init__.py
	modified:   basic_plugins/update_info.py
	modified:   configs/config.py
	modified:   configs/utils/__init__.py
	modified:   models/bag_user.py
	modified:   models/ban_user.py
	modified:   models/chat_history.py
	modified:   models/friend_user.py
	modified:   models/goods_info.py
	modified:   models/group_info.py
	modified:   models/group_member_info.py
	modified:   models/level_user.py
	modified:   models/sign_group_user.py
	modified:   models/user_shop_gold_log.py
	modified:   plugins/aconfig/__init__.py
	modified:   plugins/ai/__init__.py
	modified:   plugins/ai/data_source.py
	modified:   plugins/bilibili_sub/__init__.py
	modified:   plugins/bilibili_sub/data_source.py
	modified:   plugins/bilibili_sub/model.py
	modified:   plugins/black_word/__init__.py
	modified:   plugins/black_word/model.py
	modified:   plugins/black_word/utils.py
	modified:   plugins/bt/data_source.py
	modified:   plugins/genshin/almanac/__init__.py
	modified:   plugins/genshin/material_remind/__init__.py
	modified:   plugins/genshin/query_user/_models/__init__.py
	modified:   plugins/genshin/query_user/_utils/__init__.py
	modified:   plugins/genshin/query_user/bind/__init__.py
	modified:   plugins/genshin/query_user/genshin_sign/__init__.py
	modified:   plugins/genshin/query_user/genshin_sign/data_source.py
	modified:   plugins/genshin/query_user/genshin_sign/init_task.py
	modified:   plugins/genshin/query_user/mihoyobbs_sign/__init__.py
	modified:   plugins/genshin/query_user/query_memo/__init__.py
	modified:   plugins/genshin/query_user/query_memo/data_source.py
	modified:   plugins/genshin/query_user/query_role/__init__.py
	modified:   plugins/genshin/query_user/query_role/data_source.py
	modified:   plugins/genshin/query_user/reset_today_query_user_data/__init__.py
	modified:   plugins/genshin/query_user/resin_remind/__init__.py
	modified:   plugins/genshin/query_user/resin_remind/init_task.py
	modified:   plugins/gold_redbag/model.py
	modified:   plugins/image_management/send_image/__init__.py
	modified:   plugins/my_info/__init__.py
	modified:   plugins/open_cases/models/buff_prices.py
	modified:   plugins/open_cases/models/open_cases_user.py
	modified:   plugins/open_cases/open_cases_c.py
	modified:   plugins/open_cases/utils.py
	modified:   plugins/parse_bilibili_json.py
	modified:   plugins/pid_search.py
	modified:   plugins/pix_gallery/__init__.py
	modified:   plugins/pix_gallery/_data_source.py
	modified:   plugins/pix_gallery/_model/omega_pixiv_illusts.py
	modified:   plugins/pix_gallery/_model/pixiv.py
	modified:   plugins/pix_gallery/_model/pixiv_keyword_user.py
	modified:   plugins/pix_gallery/pix_add_keyword.py
	modified:   plugins/pix_gallery/pix_pass_del_keyword.py
	modified:   plugins/pix_gallery/pix_show_info.py
	modified:   plugins/pix_gallery/pix_update.py
	modified:   plugins/pixiv_rank_search/data_source.py
	modified:   plugins/poke/__init__.py
	modified:   plugins/russian/__init__.py
	modified:   plugins/russian/data_source.py
	modified:   plugins/russian/model.py
	modified:   plugins/send_dinggong_voice/__init__.py
	modified:   plugins/send_setu_/_model.py
	modified:   plugins/send_setu_/send_setu/__init__.py
	modified:   plugins/send_setu_/send_setu/data_source.py
	modified:   plugins/send_setu_/update_setu/data_source.py
	modified:   plugins/sign_in/goods_register.py
	modified:   plugins/sign_in/group_user_checkin.py
	modified:   plugins/sign_in/random_event.py
	modified:   plugins/sign_in/utils.py
	modified:   plugins/statistics/_model.py
	modified:   plugins/statistics/statistics_handle.py
	modified:   plugins/statistics/statistics_hook.py
	modified:   plugins/update_picture.py
	modified:   plugins/web_ui/api/request.py
	modified:   plugins/word_bank/_model.py
	deleted:    plugins/word_bank/_old_model.py
	modified:   plugins/word_bank/_rule.py
	modified:   plugins/word_bank/word_handle.py
	modified:   plugins/word_clouds/data_source.py
	modified:   resources/image/sign/sign_res/bar.png
	modified:   resources/image/sign/sign_res/bar_white.png
	modified:   services/db_context.py
	modified:   services/log.py
	modified:   utils/browser.py
	modified:   utils/data_utils.py
	modified:   utils/depends/__init__.py
	modified:   utils/http_utils.py
	modified:   utils/image_utils.py
	modified:   utils/manager/admin_manager.py
	modified:   utils/message_builder.py
	modified:   utils/utils.py
2023-02-18 18:46:54 +08:00
HibiKier a6105e8a1b modified: .gitignore 2023-02-18 17:51:22 +08:00
CRAZYShimakaze 9feea3ba1d 修复插件帮助命令不生效的问题 2023-02-16 22:59:53 +08:00
McElaga 22f415abfa 重新原神素材 2023-02-09 22:11:28 +08:00
McElaga c99292d327 重写原神今日素材 2023-02-09 22:07:08 +08:00
McElaga 362ef519b7 细节优化 2023-02-09 21:59:40 +08:00
yajiwa a053c120c4 update gold_redbag 2023-02-06 02:06:36 +08:00
HibiKier 4d133ed2df Merge pull request #1249 from noahzark/patch-3
修复B站转发卡片BUG
2023-02-05 17:28:20 +08:00
HibiKier d2cf18e11d Merge pull request #1244 from AkashiCoin/patch-1
替换pixiv反向代理地址
2023-02-05 16:37:57 +08:00
Feliciano Long 5ddfd2b5b9 修复B站转发卡片BUG
1. 最新URL `https://b23.tv/nz4tMtX`
返回
```
HTTP/2 301 
date: Tue, 31 Jan 2023 09:43:07 GMT
content-type: text/html; charset=utf-8
content-length: 781
set-cookie: ******; path=/; expires=Mon, 27 Oct 2025 09:43:07 GMT; domain=.bilibili.com
set-cookie: b_nut=1675158187; path=/; expires=Wed, 31 Jan 2024 09:43:07 GMT; domain=.bilibili.com
location: /video/BV1CM4y197A4/?buvid=******
vary: Origin,Accept-Encoding
idc: shjd
x-cache-webcdn: BYPASS from blzone07
```

这时候 url 会变成 `/video/BV1CM4y197A4/` 需要去除末尾的/来提取BVID

2. 某些转发(比如ios客户端)目前QQ小程序的desc为空,需要在prompt里检测
```json
[CQ:json,data={"app":"com.tencent.miniapp_01"&#44;"appID":"100951776"&#44;"bthirdappforward":true&#44;"bthirdappforwardforbackendswitch":true&#44;"config":{"autoSize":0&#44;"ctime":1675159871&#44;"forward":1&#44;"height":0&#44;"token":"d1dda06f69b12d511972e87ec49b2a19"&#44;"type":"normal"&#44;"width":0}&#44;"desc":""&#44;"extra":{"app_type":1&#44;"appid":100951776&#44;"uin":28696786}&#44;"meta":{"detail_1":{"appType":0&#44;"appid":"1109937557"&#44;"desc":"网络中挖到国防光缆vs现实"&#44;"gamePoints":""&#44;"gamePointsUrl":""&#44;"host":{"nick":"Noahzark"&#44;"uin":28696786}&#44;"icon":"http://miniapp.gtimg.cn/public/appicon/432b76be3a548fc128acaa6c1ec90131_200.jpg"&#44;"preview":"https://pic.ugcimg.cn/07cc5adddb5e6ef3cc27326a12b2df17/jpg1"&#44;"qqdocurl":"https://b23.tv/******"&#44;"scene":1036&#44;"shareTemplateData":{}&#44;"shareTemplateId":"8C8E89B49BE609866298ADDFF2DBABA4"&#44;"showLittleTail":""&#44;"title":"哔哩哔哩"&#44;"url":"m.q.qq.com/a/s/f6362a996fd107b3d4dbedce09c17d92"}}&#44;"prompt":"&#91;QQ小程序&#93;哔哩哔哩"&#44;"ver":"1.0.1.42"&#44;"view":"view_8C8E89B49BE609866298ADDFF2DBABA4"}]
```
2023-01-31 18:13:52 +08:00
AkashiCoin 71264bffa1 替换pixiv反向代理地址 2023-01-27 22:45:01 +08:00
HibiKier f39005f5e1 Update README.md 2023-01-06 17:31:31 +08:00
HibiKier 9454308ba7 允许真寻自身触发命令,提供配置项 self_message:STATUS 2022-12-31 18:54:17 +08:00
HibiKier 51dd622e20 Merge remote-tracking branch 'origin/main' 2022-12-31 18:10:58 +08:00
HibiKier 05de55cc6b 原神黄历改为PIL 2022-12-31 18:10:48 +08:00
HibiKier db441c8406 Add files via upload 2022-12-31 17:16:54 +08:00
HibiKier 295c535002 Add files via upload 2022-12-31 17:16:28 +08:00
HibiKier b0606feff3 原神黄历改为PIL 2022-12-31 17:15:14 +08:00
HibiKier 2070014021 修复词条在某些回答下出错 2022-12-31 14:59:56 +08:00
HibiKier def53aa22e Merge pull request #1226 from newton-miku/main
修复epic报错,优化简介
2022-12-31 14:15:05 +08:00
newton_miku a3d10385a0 修复epic报错,优化简介
1.修复了因报错UnboundLocalError: local variable 'game_desp' referenced before assignment而导致的发送失败
2.修复因简介过长导致的win版QQ在群聊中无法查看发送的合并转发消息的问题(疑似因为单条消息过长?测试时安卓QQ无此异常)(当存在简短介绍时,使用简短介绍)
2022-12-31 03:30:43 +08:00
HibiKier cb7527a44b UPDATE UPDATE_INFO 2022-12-27 12:39:36 +08:00
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
修复[滴滴滴]会被转义成&#91;滴滴滴&#93;导致无法触发的问题
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 修复[滴滴滴]会被转义成&#91;滴滴滴&#93;导致无法触发的问题 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
607 changed files with 27331 additions and 13272 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错误...
+23 -1
View File
@@ -138,10 +138,32 @@ dmypy.json
# Cython debug symbols
cython_debug/
demo.py
test.py
server_ip.py
member_activity_handle.py
Yu-Gi-Oh/
black_word/
csgo/
fantasy_card/
data/
log/
backup/
extensive_plugin/
test/
bot.py
data/
.env
.env.dev
/resources/text/
/resources/image/
/resources/temp/
!/resources/template/
/configs/config.py
configs/config.yaml
./.env
./.env.dev
plugins/csgo_server/
plugins/activity/
!/resources/image/genshin/alc/back.png
!/data/genshin_alc/
.vscode/launch.json
+496 -289
View File
@@ -5,37 +5,53 @@
![maven](https://img.shields.io/badge/go--cqhttp-1.0.0-red)
# 绪山真寻Bot
****
此项目基于 Nonebot2 和 go-cqhttp 开发,以 postgresql 作为数据库的QQ群娱乐机器人
## 关于
用爱发电,某些功能学习借鉴了大佬们的代码,因为绪山真寻实在太可爱了因此开发了
绪山真寻bot,实现了一些对群友的娱乐功能和实用功能(大概)。
如果该项目的图片等等侵犯猫豆腐老师权益请联系我删除!
如果希望有个地方讨论绪山真寻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>])
## 声明
此项目仅用于学习交流,请勿用于非法用途
## Gitee
# Nonebot2
# [Gitee](https://gitee.com/two_Dimension/zhenxun_bot)
<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/)
## 真寻的帮助
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
## 普通帮助图片
![x](https://github.com/HibiKier/zhenxun_bot/blob/0.0.8.2/docs_image/3238573864-836268675-E2FFBB2AC143EAF4DDDF150438508721.png)
![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)
## 提供符合真寻标准的插件仓库
@@ -44,152 +60,164 @@
## 来点优点?
* 实现了许多功能,且提供了大量功能管理命令
* 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改
* 方便增删插件,原生nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
* 提供了cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`__plugin_cd_limit__`
* __..... 更多详细请通过`传送门`查看文档!__
* 实现了许多功能,且提供了大量功能管理命令
* 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改
* 方便增删插件,原生nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
* 提供了cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`__plugin_cd_limit__`
* __..... 更多详细请通过`传送门`查看文档!__
## 功能列表
<details>
<summary>已实现的功能</summary>
### 已实现的常用功能
- [x] 昵称系统(群与群与私聊分开.)
- [x] 图灵AI(会把'你'等关键字替换为你的昵称),且带有 [AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus),够味
- [x] 签到/我的签到/好感度排行/好感度总排行(影响色图概率和开箱次数,支持配置)
- [x] 发送某文件夹下的随机图片(支持自定义,默认:美图,萝莉,壁纸)
- [x] 色图(这不是基础功能嘛喂)
- [x] coser
- [x] 黑白草图生成器
- [x] 鸡汤/语录
- [x] 骂我(钉宫语音)
- [x] 戳一戳(概率发送美图,钉宫语音或者戳回去)
- [x] 模拟开箱/我的开箱/群开箱统计/我的金色/设置cookie(csgo,内置爬虫脚本,需要提前抓取数据和图片,需要session,可能需要代理,阿里云服务器等ip也许已经被ban了(我无代理访问失败),如果访问太多账号API调用可能被禁止访问api!)
- [x] 鲁迅说过
- [x] 构造假消息(自定义的分享链接)
- [x] 商店/我的金币/购买道具/使用道具
- [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
- [x] 我有一个朋友想问问..(借鉴pcrbot插件)
- [x] 原神黄历
- [x] 原神今日素材
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 原神便笺查询
- [x] 原神玩家查询
- [x] 原神树脂提醒
- [x] 原神签到/自动签到
- [x] 金币红包
- [x] 微博热搜
- [x] B站主播/UP/番剧订阅
- [x] pil对图片的一些操作
- [x] BUFF饰品底价查询(需要session)
- [x] 天气查询
- [x] 疫情查询
- [x] bt磁力搜索(咳咳,这功能我想dddd)
- [x] reimu搜索(上车) (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
- [x] 靠图识番 (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
- [x] 以图搜图 (使用[nonebot_plugin_picsearcher](https://github.com/synodriver/nonebot_plugin_picsearcher)插件)
- [x] 搜番
- [x] 点歌 [nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)插件(删除了选歌和评论)
- [x] epic免费游戏
- [x] p站排行榜
- [x] p站搜图
- [x] 翻译(日英韩)
- [x] pix图库(一个自己的图库,含有增删查改,黑名单等命令)
* [x] 昵称系统(群与群与私聊分开.)
- [x] 查看当前群欢迎消息
- [x] 查看该群自己的权限
- [x] 我的信息(只是为了看看什么时候入群)
- [x] 更新信息(如果继续更新的话)
- [x] go-cqhttp最新版下载和上传(不需要请删除)
- [x] 撤回
- [x] 滴滴滴-(用户对超级用户发送消息)
- [x] 金币红包/金币排行
- [x] 俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
- [x] 网易云热评
- [x] 念首古诗
- [x] 获取b站视频封面
- [x] 通过PID获取图片
- [x] 功能统计可视化
* [x] 图灵AI(会把'你'等关键字替换为你的昵称),且带有 [AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus),够味
* [x] 签到/我的签到/好感度排行/好感度总排行(影响色图概率和开箱次数,支持配置)
* [x] 发送某文件夹下的随机图片(支持自定义,默认:美图,萝莉,壁纸)
* [x] 色图(这不是基础功能嘛喂)
* [x] coser
* [x] 黑白草图生成器
* [x] 鸡汤/语录
* [x] 骂我(钉宫语音)
* [x] 戳一戳(概率发送美图,钉宫语音或者戳回去)
* [x] 模拟开箱/我的开箱/群开箱统计/我的金色/设置cookie(csgo,内置爬虫脚本,需要提前抓取数据和图片,需要session,可能需要代理,阿里云服务器等ip也许已经被ban了(我无代理访问失败),如果访问太多账号API调用可能被禁止访问api!)
* [x] 鲁迅说过
* [x] 构造假消息(自定义的分享链接)
* [x] 商店/我的金币/购买道具/使用道具
* [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
* [x] 我有一个朋友想问问..(借鉴pcrbot插件)
* [x] 原神黄历
* [x] 原神今日素材
* [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
* [x] 原神便笺查询
* [x] 原神玩家查询
* [x] 原神树脂提醒
* [x] 原神签到/自动签到
* [x] 金币红包
* [x] 微博热搜
* [x] B站主播/UP/番剧订阅
- [x] 关于
* [x] pil对图片的一些操作
* [x] BUFF饰品底价查询(需要session)
* [x] 天气查询
* [x] 疫情查询
* [x] bt磁力搜索(咳咳,这功能我想dddd)
* [x] reimu搜索(上车) (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
* [x] 靠图识番 (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
* [x] 以图搜图 (使用[nonebot_plugin_picsearcher](https://github.com/synodriver/nonebot_plugin_picsearcher)插件)
* [x] 搜番
* [x] 点歌 [nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)插件(删除了选歌和评论)
* [x] epic免费游戏
* [x] p站排行榜
* [x] p站搜图
* [x] 翻译(日英韩)
* [x] pix图库(一个自己的图库,含有增删查改,黑名单等命令)
* [x] 查看当前群欢迎消息
* [x] 查看该群自己的权限
* [x] 我的信息(只是为了看看什么时候入群)
* [x] 更新信息(如果继续更新的话)
* [x] go-cqhttp最新版下载和上传(不需要请删除)
* [x] 撤回
* [x] 滴滴滴-(用户对超级用户发送消息)
* [x] 金币红包/金币排行
* [x] 俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
* [x] 网易云热评
* [x] 念首古诗
* [x] 获取b站视频封面
* [x] 通过PID获取图片
* [x] 功能统计可视化
* [x] 词云
* [x] 关于
### 已实现的管理员功能
- [x] 更新群组成员信息
- [x] 95%的群功能开关
- [x] 查看群内被动技能状态
- [x] 自定义群欢迎消息(是真寻的不是管家的!)
- [x] .ban/.unban(支持设置ban时长)= 黑白名单
- [x] 刷屏禁言相关:刷屏检测设置/设置禁言时长/设置检测次数
- [x] 上传图片/连续上传图片 (上传图片至指定图库)
- [x] 移动图片 (同上)
- [x] 删除图片 (同上)
- [x] 群内B站订阅
- [x] 群词条
- [x] 休息吧/醒来
* [x] 更新群组成员信息
* [x] 95%的群功能开关
* [x] 查看群内被动技能状态
* [x] 自定义群欢迎消息(是真寻的不是管家的!)
* [x] .ban/.unban(支持设置ban时长)= 黑白名单
* [x] 刷屏禁言相关:刷屏检测设置/设置禁言时长/设置检测次数
* [x] 上传图片/连续上传图片 (上传图片至指定图库)
* [x] 移动图片 (同上)
* [x] 删除图片 (同上)
* [x] 群内B站订阅
* [x] 词条设置
* [x] 休息吧/醒来
### 已实现的超级用户功能
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
- [x] 开启/关闭指定群的广播通知
- [x] 广播
- [x] 自检(检查系统状态)
- [x] 所有群组/所有好友
- [x] 退出指定群
- [x] 更新好友信息/更新群信息
- [x] /t(对用户进行回复或发送消息)
- [x] 上传/删除/修改商品(需要编写对应的商品功能)
- [x] 节日红包发送
- [x] 修改群权限
- [x] ban
- [x] 更新色图
- [x] 更新价格/更加图片(csgo开箱)
- [x] 重载原神/方舟/赛马娘/坎公骑冠剑卡池
- [x] 更新原神今日素材/更新原神资源信息
- [x] PIX相关操作
- [x] 检查更新真寻
- [x] 重启
- [x] 添加/删除/查看群白名单
- [x] 功能开关(更多设置)
- [x] 功能状态
- [x] b了
- [x] 执行sql
- [x] 重载配置
- [x] 清理临时数据
- [x] 增删群认证
- [x] 同意/拒绝好友/群聊请求
- [x] 配置重载
* [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
* [x] 开启/关闭指定群的广播通知
* [x] 广播
* [x] 自检(检查系统状态)
* [x] 所有群组/所有好友
* [x] 退出指定群
* [x] 更新好友信息/更新群信息
* [x] /t(对用户进行回复或发送消息)
* [x] 上传/删除/修改商品(需要编写对应的商品功能)
* [x] 节日红包发送
* [x] 修改群权限
* [x] ban
* [x] 更新色图
* [x] 更新价格/更加图片(csgo开箱)
* [x] 重载原神/方舟/赛马娘/坎公骑冠剑卡池
* [x] 更新原神今日素材/更新原神资源信息
* [x] PIX相关操作
* [x] 检查更新真寻
* [x] 重启
* [x] 添加/删除/查看群白名单
* [x] 功能开关(更多设置)
* [x] 功能状态
* [x] b了
* [x] 执行sql
* [x] 重载配置
* [x] 清理临时数据
* [x] 增删群认证
* [x] 同意/拒绝好友/群聊请求
* [x] 配置重载
#### 超级用户的被动技能
- [x] 邀请入群提醒(别人邀请真寻入群)
- [x] 添加好友提醒(别人添加真寻好友)
* [x] 邀请入群提醒(别人邀请真寻入群)
* [x] 添加好友提醒(别人添加真寻好友)
### 已实现的被动技能
- [x] 进群欢迎消息
- [x] 群早晚安
- [x] 每日开箱重置提醒
- [x] b站转发解析(解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv),且5分钟内不解析相同url
- [x] 丢人爬(爬表情包)
- [x] epic通知(每日发送epic免费游戏链接)
- [x] 原神黄历提醒
- [x] 复读
### 已实现的看不见的技能!
- [x] 刷屏禁言检测
- [x] 功能调用统计
- [x] 检测恶意触发命令(将被最高权限ban掉30分钟,只有最高权限(9级)可以进行unban)
- [x] 自动同意好友请求,加群请求将会提醒管理员,退群提示,加群欢迎等等
- [x] 群聊时间检测(当群聊最后一人发言时间大于当前36小时后将关闭该群所有通知(即被动技能))
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
- [x] 群权限系统
- [x] 定时更新权限
- [x] 自动配置重载
* [x] 进群欢迎消息
* [x] 群早晚安
* [x] 每日开箱重置提醒
* [x] b站转发解析(解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv),且5分钟内不解析相同url
* [x] 丢人爬(爬表情包)
* [x] epic通知(每日发送epic免费游戏链接)
* [x] 原神黄历提醒
* [x] 复读
### 已实现的看不见的技能
* [x] 刷屏禁言检测
* [x] 功能调用统计
* [x] 检测恶意触发命令(将被最高权限ban掉30分钟,只有最高权限(9级)可以进行unban)
* [x] 自动同意好友请求,加群请求将会提醒管理员,退群提示,加群欢迎等等
* [x] 群聊时间检测(当群聊最后一人发言时间大于当前36小时后将关闭该群所有通知(即被动技能))
* [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
* [x] 群权限系统
* [x] 定时更新权限
* [x] 自动配置重载
</details>
## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
## 简单部署
```
@@ -232,239 +260,418 @@ python bot.py
```
## 使用Docker
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
#### GitHub:[Sakuracio/zxenv](https://github.com/Sakuracio/zxenv)
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
**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|)
[shenqi](https://afdian.net/u/fa923a8cfe3d11eba61752540025c377)
[A_Kyuu](https://afdian.net/u/b83954fc2c1211eba9eb52540025c377)
[疯狂混沌](https://afdian.net/u/789a2f9200cd11edb38352540025c377)
[投冥](https://afdian.net/a/144514mm)
[茶喵](https://afdian.net/u/fd22382eac4d11ecbfc652540025c377)
[AemokpaTNR](https://afdian.net/u/1169bb8c8a9611edb0c152540025c377)
[爱发电用户_wrxn](https://afdian.net/u/4aa03d20db4311ecb1e752540025c377)
[qqw](https://afdian.net/u/b71db4e2cc3e11ebb76652540025c377)
[溫一壺月光下酒](https://afdian.net/u/ad667a5c650c11ed89bf52540025c377)
[伝木](https://afdian.net/u/246b80683f9511edba7552540025c377)
[阿奎](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>
## 更新
### 2022/4/26
### 2023/3/12 \[v0.1.6.7]
* 修复了群白名单无法正确添加
* 优化了管理员帮助图片,背景图层将位于最下层
* 修复了树脂140时不断提醒(未测试
* 新增了消息记录的消息排行
* WebUI新增CPU,内存,磁盘监控
* WebUI新增资源文件夹统计可视化
* 新增`更新武器箱ALL`命令来更新所有武器箱
* 新增`查看武器箱`命令
* 色图bug修复、增加指令 [@pull/1301](https://github.com/HibiKier/zhenxun_bot/pull/1301)
### 2022/4/12
### 2023/3/9
* 修复b了命令私聊出错
* 更正sql语句 [@pull/1302](https://github.com/HibiKier/zhenxun_bot/pull/1302)
* 修改签到卡片中签到增加好感度显示错误 [@pull/1299](https://github.com/HibiKier/zhenxun_bot/pull/1299)
### 2022/4/10 \[v0.1.4.7]
### 2023/3/5
* 新增消息记录模块
* 丰富处理请求操作提示
* web ui新增配置项修改
* 更新开箱会记录箱子数据以及开箱时箱子价格加入花费
* 修复开箱BUG
### 2022/4/9
### 2023/3/4
* fix: 更新问题,戳一戳图片路径问题 [@pull/144](https://github.com/HibiKier/zhenxun_bot/pull/144)
* 重写翻译,使用百度翻译API
* 新增开箱日志以及自动更新武器箱
### 2022/4/8
### 2023/3/2
* 修复原神玩家查询
* 修复config.yaml中把False也当成None的问题 [@pull/1288](https://github.com/HibiKier/zhenxun_bot/pull/1288)
* 删除道具表无用字段(props) [@pull/1287](https://github.com/HibiKier/zhenxun_bot/pull/1287)
* 修复词云
* 修复我的签到签到图片
* 更正BuffSkin添加语句
* 修复词条单图片/表情/at无法添加
### 2022/4/6
### 2022/3/1
* update search_type [@pull/143](https://github.com/HibiKier/zhenxun_bot/pull/143)
* 重写开箱更新箱子,允许更新目前所有箱子的皮肤
* 修复消息统计
### 2022/4/5 \[v0.1.4.6]
### 2023/2/28
* 修复web修改插件后帮助图片生成错误
* 把Config的type字段默认类型由str改为None [@pull/1283](https://github.com/HibiKier/zhenxun_bot/pull/1283)
* 修复同意群聊请求以及添加群认证 更新变成查询的问题 [@pull/1282](https://github.com/HibiKier/zhenxun_bot/pull/1282)
### 2022/4/4 \[v0.1.4.5]
### 2023/2/26
* 替换了bt搜索URL
* 优化使用playwright的相关代码
* 原神玩家查询新增层岩巨渊探索
* 修复原神便笺角色头像黑框
* 修复同意群聊请求错误
* 提供webui方面的api
* 新增web-ui(前端简易管理页面插件)插件
* Config提供`type`字段确定配置项类型
* 重写开箱功能
### 2022/3/21
### 2023/2/25
* 修复statistics_handle.py乱码
* 修复ys查询,尘歌壶背景尺寸与内容不匹配的问题 [@pull/1270](https://github.com/HibiKier/zhenxun_bot/pull/1275)
* 更换cos url [@pull/1270](https://github.com/HibiKier/zhenxun_bot/pull/1274)
### 2022/3/18 \[v0.1.4.4]
### 2023/2/20
* 修复戳一戳无法功能关闭与ban禁用
* 新增图片搜索 search_image
* chat_history部分字段调整为可null [@pull/1270](https://github.com/HibiKier/zhenxun_bot/pull/1270)
### 2022/3/7
### 2023/2/19
* 优化增删权限插件
* 修正了`重载插件`的帮助提示
* 修改BUG
### 2022/3/6
### 2023/2/18
* 修复树脂提醒无法开启
* 修复p搜图片路径错误
* 数据库舍弃`gino`使用`tortoise`
* 昵称提供命令`全局昵称设置`
* `manager_group`群管理操作中`退群`,`修改群权限`,`添加/删除群白名单`,`添加/删除群认证`在群聊中使用命令时且未指定群聊时,默认指定当前群聊
* 修复插件帮助命令不生效的问题 [@pull/1263](https://github.com/HibiKier/zhenxun_bot/pull/1263)
* 解决开红包经常误触的问题,有红包和未领取的时候才会触发“开”命令 [@pull/1257](https://github.com/HibiKier/zhenxun_bot/pull/1257)
* 细节优化,原神今日素材重写 [@pull/1258](https://github.com/HibiKier/zhenxun_bot/pull/1258)
### 2022/3/3 \[v0.1.4.3]
### 2023/1/31
* 修复手动同意群聊请求依旧退出
* 修复B站转发卡片BUG [@pull/1249](https://github.com/HibiKier/zhenxun_bot/pull/1249)
### 2022/3/1 \[v0.1.4.2]
### 2023/1/27
* 0.1.4内容
* 替换pixiv反向代理地址 [@pull/1244](https://github.com/HibiKier/zhenxun_bot/pull/1244)
### 2022/2/27 \[v0.1.4.1]
### 2022/12/31
* 优化抽卡
* 修复epic报错,优化简介 [@pull/1226](https://github.com/HibiKier/zhenxun_bot/pull/1226)
* 修复词条在某些回答下出错
* 原神黄历改为PIL
* 允许真寻自身触发命令,提供配置项 `self_message:STATUS`
### 2022/2/25 \[v0.1.4]
### 2022/12/27 \[v0.1.6.6]
* PIX提供配置MAX_ONCE_NUM2FORWARD:当单次发送图片超过指定张数且在群聊时,将转为合并消息
* 修复点歌无法正确发送
* 修复我有一个朋友有时文本会包含CQ码
* 修复群欢消息被动控制文本未删除 [@pull/124](https://github.com/HibiKier/zhenxun_bot/pull/124)
* message_builder.image不再提供参数:abspath
* 添加权限检查依赖注入
### 2022/2/23
### 2022/12/26
* 插件状态将从已加载插件模块中读取
* 修复b站订阅插件订阅失败问题
* 修复重启命令无法使用
* 优化`gamedraw`插件
* 提供全局被动控制
* 群被动状态改为图片
* 修复epic获取到的简介不是中文的bug [@pull/1221](https://github.com/HibiKier/zhenxun_bot/pull/1221)
### 2022/2/21 \[v0.1.3.2]
## 2022/12/24
* 群权限为-1时,超级用户发送的命令依旧生效
* 当群权限为-1时,被动技能也将不会发送
* 修复功能开关,b站转发解析,复读 ignore无法使用
* 修复色图下载文件名与路径错误
* 修复被动技能提醒有时无法删除控制文本
* 修复群管理员权限检测会阻挡超级用户权限
### 2022/12/23
### 2022/2/20 \[v0.1.3.1]
* 优化`管理员帮助`,`超级用户帮助`图片
* 重新移植`gamedraw`
* 修复pil帮助私聊时无法生成
* 修复pix下载临时文件目录错误
* 修复AI,天气,发送图片ignore导致无法使用
* 修复纯文本被动技能提醒有时无法删除控制文本
### 2022/12/17
### 2022/2/19 \[v0.1.3] (nonebot beta2!)
* 修复查看插件仓库当已安装插件版本不一致时出错
* 由于nonebot升级版本,提供更新建议(__该次升级将会导致nonebot.beta1以下的插件无法使用__
* 保证services,utils,configs,plugins,basic_plugins,文件夹均为最新
* 根目录有pyproject.toml与poetry.lock
* 执行命令:
* pip3 install poetry
* poetry install
* poetry shell
* playwright install chromium
* python3 bot.py
### 2022/12/15
* 修复自定义群欢迎消息无法使用
* 适配nonebot.beta2
* 删除图片搜索 nonebot_plugin_picsearcher
* 替换cos api
* 原神签到树脂提醒新增绑定群里,在某群绑定uid就会在某群发送提醒信息(有好友则私聊,需要重新绑定uid
* 修改update_info.json
* 修复原神资源查询下载数据失败时导致报错
* 优化BuildImage.circle()锯齿问题 [@pull/109](https://github.com/HibiKier/zhenxun_bot/pull/109)
* epic restful 替换 [@pull/119](https://github.com/HibiKier/zhenxun_bot/pull/119)
* fix: 修复远古时期残留的epic推送问题 [@pull/122](https://github.com/HibiKier/zhenxun_bot/pull/122)
### 2022/12/13
### 2022/2/11
* 修复.unban
* 修复pix不使用反代无法下载图片
### 2022/12/12
### 2022/2/10 \[v0.1.1]
* 修改HTML帮助禁用提示文本错误
* 修复HTML帮助私聊无法生成
* 修复购买道具出错
### 2022/12/11
### 2022/2/9 \[v0.1]
* 词条问题支持真寻的昵称开头与at真寻开头并优化回复
* 帮助新增HTML生成(新布局),添加配置`TYPE`切换
* 更正私聊时功能管理回复错误
* 修复加入新群聊时初始化功能开关错误
* 添加单例注解
* 添加统计表
* 新增原神自动签到和手动签到
* 新增原神树脂提醒
* 新增手动重载Config.yaml命令以及重载配置定时任务(极少部分帮助或配置可能需要重启
* 修改了发送本地图库的matcher,改为on_message
* register_use可以通过返回值发送消息
* 修复修改商品时限制时间出错
* 修复超时商品依旧可以被购买
### 2022/12/10
### 2022/1/16 \[v0.0.9.0]
* 重写帮助,删除 `详细帮助` 命令
* Ai提供文本敏感词过滤器
* 疫情插件适配新版腾讯API
* 修复/t回复带空格切分
* 修复原神玩家查询缺少渊下宫和稻妻家园以及角色不完全
* 修复方法 text2image 中 padding 和 font 无法对纯文本生效
* 修复签到图片中信息并未使用配置文件中的色图概率
* 修改原神大地图合成方式,改为先压缩再合成
* bag_user弃用字段props(该字段会在下次更新删除),使用新字段property
* 数据库中所有belonging_group统一修改为group_id
* 商店将registered_use和register_goods更名为register_use何register_goods
* 商品注册提供了kwargs参数提供:
* bot
* event
* 特殊字段
* “send_success_msg”(发送成功的交互信息->即:使用道具 {name} {num} 次成功)
* “_max_num_limit”(该道具单次使用的最多个数,默认1)
### 2022/12/4
### 2022/1/5 \[v0.0.8.2]
* 优化管理代码
* 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币
* 商店插件将作为内置插件移动至basic_plugins
* 商店插件通过export提供了方法,不需要修改商店插件代码添加商品数据和生效方法
* 修改了hook插件顺序,主要以auth_hook为主
* 修改商店图片样式
* 取消每次启动更新城市列表(首次除外),采用定时更新,加快bot启动速度
* 取消每次启动时截取今日素材,采用调用时截取保存,加快bot启动速度
* 更新色图时当图片404时会删除并替换
* 疫情消息回复改为图片
* 修复商店折扣和限时时间无法生效
* 修复原神玩家查询尘歌壶缺少图片
### 2022/11/28
### 2021/12/26
* 修复web_ui群组无法获取
* 修复web_ui修改插件数据时cmd格式错误
* 修复群词条问题 空格 会被录入导致不断回复
* 修复米游社app替换api导致无法正常查询
### 2022/11/28
### 2021/12/24
* :bug: Fix a bug in open_cases to get vanilla knives' prices [@pull/1188](https://github.com/HibiKier/zhenxun_bot/pull/1188)
* 支持国际疫情数据查询 [@pull/99](https://github.com/HibiKier/zhenxun_bot/pull/99)
### 2022/11/24
### 2021/12/20
* 修复管理员插件加载路径错误
* 只有发布小于存储时间的新动态/视频的时候才获取并推送 [@pull/96](https://github.com/HibiKier/zhenxun_bot/pull/96)
### 2022/11/23
### 2021/12/16 \[v0.0.7.0]
* 修复webui插件无法获取修改
* 提供了真寻群聊功能总开关和对应默认配置项,命令:休息吧 醒来
* 新增原神玩家查询,原神便笺查询
* 群功能管理提供全部开启/关闭命令:开启/关闭全部功能
* 提供主要数据自动备份,且提供自定义配置项
* 提供命令:关于,用于介绍Bot之类的
* 新增命令exec,用于执行sql语句
* 签到提供参数 "all",用于签到所有群聊
* Ban提醒提供cd
* 本地图库提供配置项SHOW_ID,用于设置发送图片时是否显示id
* 色图和PIX提供配置项SHOW_INFO,用于设置发送图片时是否显示图片信息
* 所有被动技能提供了进群默认状态配置项
* 修复添加权限第二种添加形式无法正确添加正确的权限
* 修复签到获取好感度卡时金币不会增加
* 修复当红包数量不合法时依旧扣除金币
* 修复金币红包再次使用塞红包时无法正确退回上次未开完的金币
* 修复 滴滴滴- 只包含图片时不会发送至管理员
* 修复添加权限等级错误
* 修复群词条以bot名称为开头时无法正确触发
* 修改了权限插件加载顺序防止小概率优先加载权限插件引起报错
* 本地图库新图库会统一建立在resource/img/image_management文件夹下,如果该文件夹内未找到图库,会从上级目录查找(即:resource/img/)
### 2022/11/22
* fix switch_rule [@pull/1185](https://github.com/HibiKier/zhenxun_bot/pull/1185)
### 2022/11/21 \[v0.1.6.5]
* 优化manager, hook代码
* 修复pid搜图 [@pull/1180](https://github.com/HibiKier/zhenxun_bot/pull/1180)
### 2022/11/19
* 修改优化帮助图片生成逻辑
### 2022/11/18
* poetry添加适配器依赖,更新支持py3.10 [@pull/1176](https://github.com/HibiKier/zhenxun_bot/pull/1176)
### 2022/11/13
* 更新天气api
* 使用道具可以附带额外信息供函数使用
* 限制帮助图片最小宽度
### 2022/11/12
* 更新yiqing插件数据显示 [@pull/1168](https://github.com/HibiKier/zhenxun_bot/pull/1168)
### 2022/11/11
* fix: B站直播订阅的相关问题 [@pull/1158](https://github.com/HibiKier/zhenxun_bot/pull/1158)
### 2022/10/30
* 商店简介动态行数,根据文字长度自动换行
### 2022/10/28
* 为exec指令进行了SELECT语句适配,添加了查看所有表指令 [@pull/1155](https://github.com/HibiKier/zhenxun_bot/pull/1155)
* 修复复读 [@pull/1154](https://github.com/HibiKier/zhenxun_bot/pull/1154)
### 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
- [ ] web管理
* [x] web管理
## 感谢
[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异步机器人框架
@@ -477,4 +684,4 @@ __..... 更多更新信息请查看文档__
[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查询插件
[KimigaiiWuyi / GenshinUID](https://github.com/KimigaiiWuyi/GenshinUID) :一个基于HoshinoBot/NoneBot2的原神UID查询插件
+1 -1
View File
@@ -1 +1 @@
__version__: v0.1.5.0
__version__: v0.1.6.7
+8 -3
View File
@@ -1,6 +1,8 @@
from configs.config import Config
from pathlib import Path
import nonebot
from configs.config import Config
Config.add_plugin_config(
"admin_bot_manage:custom_welcome_message",
@@ -9,6 +11,7 @@ Config.add_plugin_config(
name="群管理员操作",
help_="设置群欢迎消息权限",
default_value=2,
type=int,
)
Config.add_plugin_config(
@@ -17,6 +20,7 @@ Config.add_plugin_config(
2,
help_="开关群功能权限",
default_value=2,
type=int,
)
Config.add_plugin_config(
@@ -24,7 +28,8 @@ Config.add_plugin_config(
"ADMIN_DEFAULT_AUTH",
5,
help_="默认群管理员权限",
default_value=5
default_value=5,
type=int,
)
nonebot.load_plugins("basic_plugins/admin_bot_manage")
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
+189 -125
View File
@@ -1,68 +1,95 @@
import asyncio
import os
import time
from datetime import datetime
from pathlib import Path
from typing import List
import ujson as json
from nonebot.adapters.onebot.v11.message import MessageSegment
from configs.config import Config
from configs.path_config import DATA_PATH, IMAGE_PATH
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from services.log import logger
from configs.path_config import DATA_PATH
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
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
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"
)
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, imgs: List[str], user_id: int, group_id: int
msg: str, img_list: List[str], user_id: int, group_id: int
) -> str:
"""
替换群欢迎消息
:param msg: 欢迎消息文本
:param imgs: 欢迎消息图片,只取第一张
:param user_id: 用户id,用于log记录
:param group_id: 群号
说明:
替换群欢迎消息
参数:
:param msg: 欢迎消息文本
:param img_list: 欢迎消息图片,只取第一张
:param user_id: 用户id,用于log记录
:param group_id: 群号
"""
img_result = ""
img = imgs[0] if imgs else ""
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)
data = {}
else:
try:
data = json.load(open(custom_welcome_msg_json, "r"))
except FileNotFoundError:
data = {}
pass
try:
if msg:
data[str(group_id)] = str(msg)
@@ -86,14 +113,48 @@ async def custom_group_welcome(
task_data = None
async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
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: 是否位超级用户,超级用户用于私聊开关功能状态
说明:
修改群功能状态
参数:
: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"
@@ -104,41 +165,44 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
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)
if not group_manager.check_group_task_status(group_id, task):
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)
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)
group_manager.unblock_plugin(f, group_id, False)
else:
group_manager.block_plugin(f, group_id)
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 in [task_data[x] for x in task_data.keys()]:
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] == cmd]
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 await group_manager.check_group_task_status(group_id, module):
if group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
await group_manager.open_group_task(group_id, 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 await group_manager.check_group_task_status(group_id, module):
if not group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
await group_manager.close_group_task(group_id, module)
group_manager.close_group_task(group_id, module)
else:
if not group_manager.get_plugin_status(module, group_id):
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
@@ -158,9 +222,11 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
def set_plugin_status(cmd: str, block_type: str = "all"):
"""
设置插件功能状态(超级用户使用)
:param cmd: 功能名称
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
说明:
设置插件功能状态(超级用户使用)
参数:
:param cmd: 功能名称
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
"""
status = cmd[:2]
cmd = cmd[2:]
@@ -176,14 +242,16 @@ def set_plugin_status(cmd: str, block_type: str = "all"):
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"
@@ -195,7 +263,7 @@ def _get_plugin_status() -> MessageSegment:
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"]
plugin_name = plugins_manager.get(module).plugin_name
if (
"[Hidden]" in plugin_name
or "[Admin]" in plugin_name
@@ -205,7 +273,7 @@ def _get_plugin_status() -> MessageSegment:
rst += f"{plugin_name}"
except KeyError:
rst += f"{module}"
if plugins_manager.get(module)["error"]:
if plugins_manager.get(module).error:
rst += "[ERROR]"
rst += "\n"
flag_str += f"{flag}\n"
@@ -222,9 +290,11 @@ def _get_plugin_status() -> MessageSegment:
async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool:
"""
更新群成员信息
:param group_id: 群号
:param remind_superuser: 失败信息提醒超级用户
说明:
更新群成员信息
参数:
:param group_id: 群号
:param remind_superuser: 失败信息提醒超级用户
"""
bot = get_bot()
_group_user_list = await bot.get_group_member_list(group_id=group_id)
@@ -232,58 +302,54 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
_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(
nickname = user_info["card"] or user_info["nickname"]
# 更新权限
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"],
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"
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_or_none(
user_qq=user_info["user_id"], group_id=user_info["group_id"]
)
if user:
if user.user_name != nickname:
user.user_name = nickname
await user.save(update_fields=["user_name"])
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",
)
user, _ = await GroupInfoUser.get_or_create(
user_qq=user_info["user_id"],
group_id=user_info["group_id"],
defaults={
"user_name": nickname,
},
)
# await GroupInfoUser.update_or_create(
# user_qq=user_info["user_id"],
# group_id=user_info["group_id"],
# defaults={
# "user_name": nickname,
# # "user_join_time": datetime.now().replace(tzinfo=None),
# },
# )
user.user_join_time = join_time
await user.save()
_exist_member_list.append(int(user_info["user_id"]))
logger.info("更新成功", "更新成员信息", user_info["user_id"], user_info["group_id"])
_del_member_list = list(
set(_exist_member_list).difference(
set(await GroupInfoUser.get_group_member_id_list(group_id))
@@ -291,10 +357,8 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
)
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} 删除失败")
await GroupInfoUser.filter(user_qq=del_user, group_id=group_id).delete()
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
if _error_member_list and remind_superuser:
result = ""
for error_user in _error_member_list:
@@ -307,9 +371,11 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
def set_group_bot_status(group_id: int, status: bool) -> str:
"""
设置群聊bot开关状态
:param group_id: 群号
:param status: 状态
说明:
设置群聊bot开关状态
参数:
:param group_id: 群号
:param status: 状态
"""
if status:
if group_manager.check_group_bot_status(group_id):
@@ -318,6 +384,4 @@ def set_group_bot_status(group_id: int, status: bool) -> str:
return "呜..醒来了..."
else:
group_manager.shutdown_group_bot_status(group_id)
# for x in group_manager.get_task_data():
# group_manager.close_group_task(group_id, x)
return "那我先睡觉了..."
@@ -1,10 +1,10 @@
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
from configs.config import Config
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from services.log import logger
__zx_plugin_name__ = "群管理员变动监测 [Hidden]"
__plugin_version__ = 0.1
@@ -16,11 +16,11 @@ 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:
if user := await GroupInfoUser.filter(
user_qq=event.user_id, group_id=event.group_id
).first():
nickname = user.nickname
else:
nickname = event.user_id
if event.sub_type == "set":
await LevelUser.set_level(
@@ -1,12 +1,14 @@
from nonebot import on_command
from utils.utils import get_message_img
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 typing import List
from configs.config import Config
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.params import CommandArg
from services.log import logger
from utils.depends import ImageList
from ._data_source import custom_group_welcome
__zx_plugin_name__ = "自定义进群欢迎消息 [Admin]"
__plugin_usage__ = """
@@ -17,12 +19,14 @@ usage:
Note:可以通过[at]来确认是否艾特新成员
示例:自定义进群欢迎消息 欢迎你[at]
""".strip()
__plugin_des__ = '简易的自定义群欢迎消息'
__plugin_cmd__ = ['自定义群欢迎消息 ?[文本] ?[图片]']
__plugin_des__ = "简易的自定义群欢迎消息"
__plugin_cmd__ = ["自定义群欢迎消息 ?[文本] ?[图片]"]
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"admin_level": Config.get_config("admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"),
"admin_level": Config.get_config(
"admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"
),
}
custom_welcome = on_command(
@@ -35,12 +39,13 @@ custom_welcome = on_command(
@custom_welcome.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
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:
msg = arg.extract_plain_text().strip()
img = get_message_img(event.json())
if not msg and not img:
await custom_welcome.finish(__plugin_usage__)
await custom_welcome.send(
await custom_group_welcome(msg, img, event.user_id, event.group_id),
at_sender=True,
+15 -7
View File
@@ -2,30 +2,37 @@ 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(event: Event) -> bool:
"""
检测文本是否是关闭功能命令
:param event: pass
说明:
检测文本是否是关闭功能命令
参数:
:param event: pass
"""
global cmd
global cmd, v
try:
if not cmd:
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:
if isinstance(_data[key]["cmd"], list):
for x in _data[key]["cmd"]:
if isinstance(_data[key].cmd, list):
for x in _data[key].cmd:
cmd.append(f"开启{x}")
cmd.append(f"关闭{x}")
cmd.append(f"开启 {x}")
@@ -37,6 +44,7 @@ def switch_rule(event: Event) -> bool:
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
+11 -6
View File
@@ -1,12 +1,14 @@
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent, GROUP
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
set_group_bot_status, change_global_task_status
)
from services.log import logger
from configs.config import NICKNAME, Config
@@ -31,11 +33,12 @@ usage:
""".strip()
__plugin_superuser_usage__ = """
usage:
功能总开关与指定群禁用
(私聊)功能总开关与指定群禁用
指令:
功能状态
开启/关闭[功能] [group]
开启/关闭[功能] ['private'/'group']
开启被动/关闭被动[被动名称] # 全局被动控制
""".strip()
__plugin_des__ = "群内功能开关"
__plugin_cmd__ = [
@@ -74,7 +77,9 @@ async def _(bot: Bot, event: MessageEvent):
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 ("关闭被动" 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()
@@ -85,7 +90,7 @@ async def _(bot: Bot, event: MessageEvent):
"group_name"
]
await switch_rule_matcher.send(
f"已禁用群聊 {group_name}({block_type}) 的 {_cmd[2:]} 功能"
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
@@ -110,7 +115,7 @@ async def _():
@group_task_status.handle()
async def _(event: GroupMessageEvent):
await group_task_status.send(await group_current_status(event.group_id))
await group_task_status.send(image(b64=await group_current_status(event.group_id)))
@group_status.handle()
+10 -9
View File
@@ -1,15 +1,16 @@
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
from models.group_info import GroupInfo
from services.log import logger
from utils.utils import get_bot, scheduler
__zx_plugin_name__ = '管理方面定时任务 [Hidden]'
__plugin_usage__ = '无'
__plugin_des__ = '成员信息和管理权限的定时更新'
from ._data_source import update_member_info
__zx_plugin_name__ = "管理方面定时任务 [Hidden]"
__plugin_usage__ = "无"
__plugin_des__ = "成员信息和管理权限的定时更新"
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_author__ = "HibiKier"
# 自动更新群员信息
@@ -42,7 +43,7 @@ async def _():
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()]
all_group = [x.group_id for x in await GroupInfo.all()]
for g in gl:
if g not in all_group:
await update_member_info(g, False)
@@ -2,6 +2,7 @@ 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:
+5 -5
View File
@@ -3,7 +3,7 @@ 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
from .data_source import create_help_image, ADMIN_HELP_IMAGE
__zx_plugin_name__ = '管理帮助 [Admin]'
@@ -16,12 +16,12 @@ __plugin_settings__ = {
admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True)
if admin_help_image.exists():
admin_help_image.unlink()
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():
if not ADMIN_HELP_IMAGE.exists():
await create_help_image()
await admin_help.send(image('admin_help_img.png'))
await admin_help.send(image(ADMIN_HELP_IMAGE))
+63 -66
View File
@@ -1,25 +1,25 @@
from utils.image_utils import BuildImage
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.onebot.v11 import Bot
from nonebot import Driver
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'
ADMIN_HELP_IMAGE = IMAGE_PATH / "admin_help_img.png"
@driver.on_bot_connect
async def init_task(bot: Bot = None):
async def init_task():
if not group_manager.get_task_data():
await group_manager.init_group_task()
logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.')
group_manager.load_task()
logger.info(f"已成功加载 {len(group_manager.get_task_data())} 个被动技能.")
async def create_help_image():
@@ -33,58 +33,55 @@ async def _create_help_image():
"""
创建管理员帮助图片
"""
_matchers = get_matchers()
_plugin_name_list = []
width = 0
_plugin_level = {}
for matcher in _matchers:
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
_module = _plugin.module
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:
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.plugin_name}: {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 = BuildImage(width, height, font_size=24)
_background = BuildImage(width, height, background=background)
await A.apaste(_background, alpha=True)
await A.atext((150, 110), help_str)
await A.asave(admin_help_image)
logger.info(f'已成功加载 {len(_plugin_name_list)} 条管理员命令')
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)} 条管理员命令")
+65 -72
View File
@@ -1,48 +1,52 @@
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.exception import ActionFailed
from configs.config import NICKNAME, Config
from utils.manager import group_manager
from pathlib import Path
import shutil
from pathlib import Path
from typing import List
import nonebot
from nonebot import on_message
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import NICKNAME, Config
from configs.path_config import IMAGE_PATH
from models.friend_user import FriendUser
from models.group_info import GroupInfo
from services.log import logger
from utils.message_builder import image
from utils.utils import broadcast_group, get_bot, scheduler
__zx_plugin_name__ = "定时任务相关 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {'zwa': '早晚安'}
__plugin_task__ = {"zwa": "早晚安"}
Config.add_plugin_config(
"_task",
"DEFAULT_ZWA",
True,
help_="被动 早晚安 进群默认开关状态",
default_value=True,
"_task", "DEFAULT_ZWA", True, help_="被动 早晚安 进群默认开关状态", default_value=True, type=bool
)
Config.add_plugin_config(
"_backup",
"BACKUP_FLAG",
True,
help_="是否开启文件备份",
default_value=True
"_backup", "BACKUP_FLAG", True, help_="是否开启文件备份", default_value=True, type=bool
)
Config.add_plugin_config(
"_backup",
"BACKUP_DIR_OR_FILE",
['data/black_word', 'data/configs', 'data/statistics', 'data/word_bank', 'data/manager', 'configs'],
[
"data/black_word",
"data/configs",
"data/statistics",
"data/word_bank",
"data/manager",
"configs",
],
name="文件备份",
help_="备份的文件夹或文件",
default_value=[]
default_value=[],
type=List[str],
)
cx = on_message(priority=9, block=False)
cx = on_message(priority=9999, block=False, rule=lambda: False)
# 早上好
@@ -52,18 +56,9 @@ cx = on_message(priority=9, block=False)
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}")
img = image(IMAGE_PATH / "zhenxun" / "zao.jpg")
await broadcast_group("[[_task|zwa]]早上好" + img, log_cmd="被动早晚安")
logger.info("每日早安发送")
# 睡觉了
@@ -73,20 +68,11 @@ async def _():
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}")
img = image(IMAGE_PATH / "zhenxun" / "sleep.jpg")
await broadcast_group(
f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + img, log_cmd="被动早晚安"
)
logger.info("每日晚安发送")
# 自动更新群组信息
@@ -96,21 +82,27 @@ async def _():
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}")
bots = nonebot.get_bots()
_used_group = []
for bot in bots.values():
try:
group_list = await bot.get_group_list()
gl = [g["group_id"] for g in group_list if g["group_id"] not in _used_group]
for g in gl:
_used_group.append(g)
group_info = await bot.get_group_info(group_id=g)
await GroupInfo.update_or_create(
group_id=group_info["group_id"],
defaults={
"group_name": group_info["group_name"],
"max_member_count": group_info["max_member_count"],
"member_count": group_info["member_count"],
"group_flag": 1,
},
)
logger.info(f"自动更新群组信息成功", group_id=g)
except Exception as e:
logger.error(f"Bot: {bot.self_id} 自动更新群组信息", e=e)
# 自动更新好友信息
@@ -124,10 +116,10 @@ async def _():
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"]} 信息失败')
await FriendUser.create(user_id=f["user_id"], user_name=f["nickname"])
logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
# else:
# logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
except Exception as e:
logger.error(f"自动更新群组信息错误 e:{e}")
@@ -140,7 +132,7 @@ async def _():
)
async def _():
if Config.get_config("_backup", "BACKUP_FLAG"):
_backup_path = Path() / 'backup'
_backup_path = Path() / "backup"
_backup_path.mkdir(exist_ok=True, parents=True)
for x in Config.get_config("_backup", "BACKUP_DIR_OR_FILE"):
try:
@@ -155,12 +147,13 @@ async def _():
if _p.exists():
_p.unlink()
shutil.copy(x, _p)
logger.info(f'已完成自动备份:{x}')
logger.info(f"已完成自动备份:{x}")
except Exception as e:
logger.error(f"自动备份文件 {x} 发生错误 {type(e)}:{e}")
# 一次性任务
# 固定时间触发,仅触发一次:
#
# from datetime import datetime
+72 -63
View File
@@ -1,15 +1,22 @@
from typing import Tuple
from typing import List
from nonebot import on_command
from nonebot.adapters.onebot.v11 import (
Bot,
GroupMessageEvent,
Message,
MessageEvent,
PrivateMessageEvent,
)
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
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.utils import get_message_at, is_number
from utils.depends import AtList, OneCommand
from utils.utils import is_number
from .data_source import a_ban, parse_ban_time
@@ -49,6 +56,7 @@ __plugin_configs__ = {
"value": 5,
"help": "ban/unban所需要的管理员权限等级",
"default_value": 5,
"type": int
}
}
@@ -67,46 +75,38 @@ super_ban = on_command("b了", permission=SUPERUSER, priority=5, block=True)
async def _(
bot: Bot,
event: GroupMessageEvent,
cmd: Tuple[str, ...] = Command(),
cmd: str = OneCommand(),
arg: Message = CommandArg(),
at_list: List[int] = AtList(),
):
cmd = cmd[0]
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"] or user_name["nickname"]
if at_list:
qq = at_list[0]
user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
user_name = user["card"] or user["nickname"]
msg = arg.extract_plain_text().strip()
time = parse_ban_time(msg)
if isinstance(time, str):
await ban.finish(time, at_sender=True)
user_level = await LevelUser.get_user_level(event.user_id, event.group_id)
is_not_superuser = str(event.user_id) not in bot.config.superusers
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
):
at_user_level = await LevelUser.get_user_level(qq, event.group_id)
if user_level <= at_user_level and is_not_superuser:
await ban.finish(
f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!",
at_sender=True,
)
logger.info(f"用户封禁 时长: {time}", cmd, event.user_id, event.group_id, qq)
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
):
if await BanUser.check_ban_level(qq, user_level) and is_not_superuser:
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} 从黑名单中删除了!"
logger.info(f"解除用户封禁", cmd, event.user_id, event.group_id, qq)
result = f"已经将 {user_name} 从黑名单中删除了!"
else:
result = f"{user_name} 不在黑名单!"
else:
@@ -118,53 +118,62 @@ async def _(
async def _(
bot: Bot,
event: PrivateMessageEvent,
cmd: Tuple[str, ...] = Command(),
cmd: str = OneCommand(),
arg: Message = CommandArg(),
):
cmd = cmd[0]
msg = arg.extract_plain_text().strip()
if msg:
if str(event.user_id) in bot.config.superusers:
if is_number(arg.extract_plain_text().strip().split()[0]):
qq = int(msg[0])
msg = msg[1:]
if cmd in [".ban", "/ban"]:
time = parse_ban_time(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)
if msg and str(event.user_id) in bot.config.superusers:
msg_split = msg.split()
if msg_split and is_number(msg_split[0]):
qq = int(msg_split[0])
param = msg_split[1:]
if cmd in [".ban", "/ban"]:
time = parse_ban_time(" ".join(param))
if isinstance(time, str):
logger.info(time, cmd, event.user_id, target=qq)
await ban.finish(time)
result = await a_ban(qq, time, str(qq), event, 9)
else:
await ban.finish(
"qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?", at_sender=True
)
if await BanUser.unban(qq):
result = f"已经把 {qq} 从黑名单中删除了!"
else:
result = f"{qq} 不在黑名单!"
await ban.send(result)
logger.info(result, cmd, event.user_id, target=qq)
else:
await ban.send("参数不正确!\n格式:.ban [qq] [hour]? [minute]?", at_sender=True)
@super_ban.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
async def _(
bot: Bot,
event: MessageEvent,
cmd: str = OneCommand(),
arg: Message = CommandArg(),
at_list: List[int] = AtList(),
):
user_name = ""
qq = None
if isinstance(event, GroupMessageEvent):
qq = get_message_at(event.json())
if qq:
qq = qq[0]
if at_list:
qq = at_list[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):
msg = arg.extract_plain_text().strip()
if not is_number(msg):
await super_ban.finish("对象qq必须为纯数字...")
qq = int(qq)
user_name = qq
qq = int(msg)
user_name = msg
if qq:
if not await BanUser.ban(qq, 10, 99999999):
await BanUser.unban(qq)
await BanUser.ban(qq, 10, 99999999)
await BanUser.ban(qq, 10, 99999999)
await ban.send(f"已将 {user_name} 拉入黑名单!")
logger.info(
f"已将 {user_name} 拉入黑名单!",
cmd,
event.user_id,
event.group_id if isinstance(event, GroupMessageEvent) else None,
qq,
)
else:
await super_ban.send("需要添加被super ban的对象,可以使用at或者指定qq..")
await super_ban.send("需要提供被super ban的对象,可以使用at或者指定qq...")
+43 -35
View File
@@ -1,10 +1,12 @@
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from typing import Optional, Union
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from configs.config import NICKNAME
from models.level_user import LevelUser
from utils.utils import is_number
from models.ban_user import BanUser
from models.level_user import LevelUser
from services.log import logger
from typing import Union
from utils.utils import is_number
def parse_ban_time(msg: str) -> Union[int, str]:
@@ -12,20 +14,32 @@ 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
try:
if not msg:
return -1
msg_split = msg.split()
if len(msg_split) == 1:
if not is_number(msg_split[0].strip()):
return "参数必须是数字!"
return int(msg_split[0]) * 60 * 60
else:
if not is_number(msg_split[0].strip()) or not is_number(
msg_split[1].strip()
):
return "参数必须是数字!"
return int(msg_split[0]) * 60 * 60 + int(msg_split[1]) * 60
except ValueError as e:
logger.error("解析ban时长错误", ".ban", e=e)
return "时长不可以带小数点!"
async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None) -> str:
async def a_ban(
qq: int,
time: int,
user_name: str,
event: MessageEvent,
ban_level: Optional[int] = None,
) -> str:
"""
ban
:param qq: qq
@@ -34,11 +48,15 @@ async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_lev
:param event: event
:param ban_level: ban级别
"""
group_id = None
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
ban_level = await LevelUser.get_user_level(event.user_id, event.group_id)
if not ban_level:
return "未查询到ban级用户权限"
if await BanUser.ban(qq, ban_level, time):
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time / 60} 分钟"
f"将 [Target]({qq})封禁 时长 {time / 60} 分钟", ".ban", event.user_id, group_id
)
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
if time != -1:
@@ -46,24 +64,14 @@ async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_lev
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) + " 秒"
ban_time = await BanUser.check_ban_time(qq)
if isinstance(ban_time, int):
ban_time = abs(float(ban_time))
if ban_time < 60:
ban_time = str(ban_time) + " 秒"
else:
time = str(int(time / 60)) + " 分钟"
ban_time = str(int(ban_time / 60)) + " 分钟"
else:
time += " 分钟"
result = f"{user_name} 已在黑名单!预计 {time}后解封"
ban_time += " 分钟"
result = f"{user_name} 已在黑名单!预计 {ban_time}后解封"
return result
+13 -12
View File
@@ -1,14 +1,15 @@
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
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
from configs.config import Config
from services.log import logger
from utils.manager import group_manager
from utils.message_builder import image
from utils.utils import get_message_img
__zx_plugin_name__ = "广播 [Superuser]"
__plugin_usage__ = """
@@ -28,6 +29,7 @@ Config.add_plugin_config(
True,
help_="被动 广播 进群默认开关状态",
default_value=True,
type=bool,
)
broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
@@ -40,11 +42,10 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
rst = ""
for img in img_list:
rst += image(img)
gl = await bot.get_group_list()
gl = [
g["group_id"]
for g in gl
if await group_manager.check_group_task_status(g["group_id"], "broadcast")
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
+2 -1
View File
@@ -1,3 +1,4 @@
import nonebot
from pathlib import Path
nonebot.load_plugins("basic_plugins/chat_history")
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
+43 -9
View File
@@ -1,8 +1,12 @@
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 configs.config import Config
from models.chat_history import ChatHistory
from services.log import logger
from utils.depends import PlaintText
from utils.utils import scheduler
from ._rule import rule
__zx_plugin_name__ = "消息存储 [Hidden]"
@@ -11,21 +15,51 @@ __plugin_author__ = "HibiKier"
Config.add_plugin_config(
"chat_history", "FLAG", True, help_="是否开启消息自从存储", name="消息存储", default_value=True
"chat_history",
"FLAG",
True,
help_="是否开启消息自从存储",
name="消息存储",
default_value=True,
type=bool,
)
chat_history = on_message(rule=rule, priority=1, block=False)
TEMP_LIST = []
@chat_history.handle()
async def _(event: MessageEvent):
async def _(event: MessageEvent, msg: str = PlaintText()):
group_id = None
if isinstance(event, GroupMessageEvent):
await ChatHistory.add_chat_msg(
event.user_id, event.group_id, str(event.get_message())
)
else:
await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message()))
group_id = event.group_id
TEMP_LIST.append(
{
"user_qq": event.user_id,
"group_id": group_id,
"text": str(event.get_message()),
"plain_text": msg,
}
)
@scheduler.scheduled_job(
"interval",
minutes=1,
)
async def _():
try:
message_list = TEMP_LIST.copy()
TEMP_LIST.clear()
if message_list:
model_list = [ChatHistory(**x) for x in message_list]
await ChatHistory.bulk_create(model_list)
logger.debug(f"批量添加聊天记录 {len(message_list)} 条", "定时任务")
except Exception as e:
logger.error(f"定时批量添加聊天记录", "定时任务", e=e)
# @test.handle()
@@ -1,26 +1,27 @@
from datetime import datetime, timedelta
from typing import Any, Tuple
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
from models.chat_history import ChatHistory
from models.group_member_info import GroupInfoUser
from utils.image_utils import BuildImage, text2image
from utils.message_builder import image
from utils.utils import is_number
__zx_plugin_name__ = "消息统计"
__plugin_usage__ = """
usage:
发言记录统计
regex:(周|月)?消息排行(des|DES)?(n=[0-9]{1,2})?
regex:(周|月|日)?消息排行(des|DES)?(n=[0-9]{1,2})?
指令:
消息统计?(des)?(n=?)
周消息统计?(des)?(n=?)
月消息统计?(des)?(n=?)
日消息统计?(des)?(n=?)
示例:
消息统计
消息统计des
@@ -28,11 +29,7 @@ usage:
消息统计n=15
""".strip()
__plugin_des__ = "发言消息排行"
__plugin_cmd__ = [
"消息统计",
"周消息统计",
"月消息统计"
]
__plugin_cmd__ = ["消息统计", "周消息统计", "月消息统计", "日消息统计"]
__plugin_type__ = ("数据统计", 1)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
@@ -42,7 +39,9 @@ __plugin_settings__ = {
}
msg_handler = on_regex(r"(周|月)?消息统计(des|DES)?(n=[0-9]{1,2})?", priority=5, block=True)
msg_handler = on_regex(
r"^(周|月|日)?消息统计(des|DES)?(n=[0-9]{1,2})?$", priority=5, block=True
)
@msg_handler.handle()
@@ -53,10 +52,16 @@ async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup())
num = num.split("=")[-1] if num else 10
if num and is_number(num) and 10 < int(num) < 50:
num = int(num)
if date in ["周"]:
date_scope = (datetime.now() - timedelta(days=7), datetime.now())
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 = (datetime.now() - timedelta(days=30), datetime.now())
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
):
@@ -64,9 +69,9 @@ async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup())
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:
if user := await GroupInfoUser.filter(user_qq=uid, group_id=gid).first():
user_name = user.user_name
else:
user_name = uid
name += f"\t{idx}.{user_name} \n\n"
num_str += f"\t{num}\n\n"
@@ -79,7 +84,7 @@ async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup())
pytz.timezone("Asia/Shanghai")
).replace(microsecond=0)
else:
date_scope = datetime.now().replace(microsecond=0)
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)}"
+85 -57
View File
@@ -1,29 +1,27 @@
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.onebot.v11 import (
Bot,
GroupIncreaseNoticeEvent,
GroupDecreaseNoticeEvent,
)
from nonebot.adapters.onebot.v11.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
import random
from datetime import datetime
from pathlib import Path
try:
import ujson as json
except ModuleNotFoundError:
import json
import ujson as json
from nonebot import on_notice, on_request
from nonebot.adapters.onebot.v11 import (
ActionFailed,
Bot,
GroupDecreaseNoticeEvent,
GroupIncreaseNoticeEvent,
)
from configs.config import NICKNAME, Config
from configs.path_config import DATA_PATH, IMAGE_PATH
from models.group_info import GroupInfo
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from services.log import logger
from utils.depends import GetConfig
from utils.manager import group_manager, plugins2settings_manager, requests_manager
from utils.message_builder import image
from utils.utils import FreqLimiter
__zx_plugin_name__ = "群事件处理 [Hidden]"
__plugin_version__ = 0.1
@@ -33,10 +31,10 @@ Config.add_plugin_config(
"invite_manager", "message", f"请不要未经同意就拉{NICKNAME}入群!告辞!", help_="强制拉群后进群回复的内容.."
)
Config.add_plugin_config(
"invite_manager", "flag", True, help_="被强制拉群后是否直接退出", default_value=True
"invite_manager", "flag", True, help_="被强制拉群后是否直接退出", default_value=True, type=bool
)
Config.add_plugin_config(
"invite_manager", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
"invite_manager", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5, type=int
)
Config.add_plugin_config(
"_task",
@@ -44,6 +42,7 @@ Config.add_plugin_config(
True,
help_="被动 进群欢迎 进群默认开关状态",
default_value=True,
type=bool,
)
Config.add_plugin_config(
"_task",
@@ -51,10 +50,11 @@ Config.add_plugin_config(
True,
help_="被动 退群提醒 进群默认开关状态",
default_value=True,
type=bool,
)
_flmt = FreqLimiter(Config.get_config("invite_manager", "welcome_msg_cd"))
_flmt = FreqLimiter(Config.get_config("invite_manager", "welcome_msg_cd") or 5)
# 群员增加处理
@@ -68,7 +68,7 @@ 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)
group = await GroupInfo.filter(group_id=event.group_id).first()
# 群聊不存在或被强制拉群,退出该群
if (not group or group.group_flag == 0) and Config.get_config(
"invite_manager", "flag"
@@ -91,25 +91,48 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
message=f"触发强制入群保护,退出群聊 {event.group_id} 失败..",
)
# 默认群功能开关
elif event.group_id not in group_manager["group_manager"].keys():
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"]:
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']} 更新失败")
user, _ = await GroupInfoUser.get_or_create(
user_qq=user_info["user_id"],
group_id=user_info["group_id"],
defaults={
"user_name": user_info["nickname"],
},
)
user.user_join_time = join_time
await user.save()
# await GroupInfoUser.update_or_create(
# user_qq=user_info["user_id"],
# group_id=user_info["group_id"],
# defaults={"user_name": user_info["nickname"], "user_join_time": join_time},
# )
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
# 群欢迎消息
if _flmt.check(event.group_id):
@@ -128,9 +151,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
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"
)
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
@@ -140,7 +161,11 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
else:
await group_increase_handle.send(
"[[_task|group_welcome]]新人快跑啊!!本群现状↓(快使用自定义!)"
+ image(random.choice(os.listdir(IMAGE_PATH / "qxz")), "qxz")
+ image(
IMAGE_PATH
/ "qxz"
/ random.choice(os.listdir(IMAGE_PATH / "qxz"))
)
)
@@ -150,13 +175,13 @@ 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:
if user := await GroupInfoUser.get_or_none(
user_qq=event.operator_id, group_id=event.group_id
):
operator_name = user.user_name
else:
operator_name = "None"
group = await GroupInfo.get_group_info(group_id)
group = await GroupInfo.filter(group_id=group_id).first()
group_name = group.group_name if group else ""
coffee = int(list(bot.config.superusers)[0])
await bot.send_private_msg(
@@ -170,16 +195,19 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent):
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} 删除成功")
if user := await GroupInfoUser.get_or_none(
user_qq=event.user_id, group_id=event.group_id
):
user_name = user.user_name
else:
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败")
user_name = f"{event.user_id}"
await GroupInfoUser.filter(user_qq=event.user_id, group_id=event.group_id).delete()
logger.info(
f"名称: {user_name} 退出群聊",
"group_decrease_handle",
event.user_id,
event.group_id,
)
rst = ""
if event.sub_type == "leave":
rst = f"{user_name}离开了我们..."
+14 -31
View File
@@ -6,45 +6,30 @@ from nonebot.adapters.onebot.v11 import (
Message
)
from nonebot.params import CommandArg
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 ._data_source import create_help_img, get_plugin_help
from ._utils import GROUP_HELP_PATH
import os
__zx_plugin_name__ = "帮助"
group_help_path = DATA_PATH / "group_help"
help_image = IMAGE_PATH / "help.png"
__plugin_configs__ = {
"TYPE": {"value": "normal", "help": "帮助图片样式 ['normal', 'HTML']", "default_value": "normal"}
}
simple_help_image = 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, arg: Message = CommandArg()):
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
is_super = False
if msg:
@@ -54,20 +39,18 @@ async def _(bot: Bot, event: MessageEvent, state: T_State, arg: Message = Comman
msg = msg.replace('-super', '').strip()
msg = get_plugin_help(msg, is_super)
if msg:
await _help.send(image(b64=msg))
await simple_help.send(image(b64=msg))
else:
await _help.send("没有此功能的帮助信息...")
await simple_help.send("没有此功能的帮助信息...")
else:
if isinstance(event, GroupMessageEvent):
_image_path = group_help_path / f"{event.group_id}.png"
_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 create_help_img(event.group_id)
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"))
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
+255
View File
@@ -0,0 +1,255 @@
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 BuildImage
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 = IMAGE_PATH / "background" / "help" / "simple_help"
background = 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 = BuildImage(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.plugin_name)
_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.plugin_name
) and plugins2settings_manager[matcher.plugin_name].get("plugin_type"):
plugin_type = tuple(
plugins2settings_manager.get_plugin_data(matcher.plugin_name)[
"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] = {
"modules": matcher.plugin_name,
"des": plugin_des,
"cmd": plugin_cmd,
"text_type": text_type,
}
try:
if text_type == 0:
x = tmp_img.getsize(
f'{plugin_name}: {matchers_data[plugin_type][plugin_name]["des"]} ->'
+ " / ".join(matchers_data[plugin_type][plugin_name]["cmd"])
)[0]
width = width if width > x else x
except KeyError:
pass
if plugin_des not in _des_tmp:
_des_tmp[plugin_des] = plugin_name
except AttributeError as e:
if plugin_name not in _plugin_name_tmp:
logger.warning(f"获取功能 {matcher.plugin_name}: {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]["modules"], "all"
):
flag = False
if group_id:
flag = flag and plugins_manager.get_plugin_status(
matchers_data[type_][k]["modules"], "group"
)
simple_help_str += (
f"{i+1}.{k}<|_|~|>"
f"{group_manager.get_plugin_status(matchers_data[type_][k]['modules'], 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 = BuildImage(
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 = BuildImage(simple_width + 20, simple_height, font_size=24, color="#6495ED")
B = BuildImage(
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 = BuildImage(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 = BuildImage(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 = BuildImage(
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 = BuildImage(
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(
BuildImage(
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: BuildImage = None, is_paste: bool = False
) -> "int, BuildImage":
"""
获取最大宽度,或直接贴图
: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 = 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
+7 -10
View File
@@ -1,13 +1,13 @@
from configs.config import Config
Config.add_plugin_config(
"hook",
"CHECK_NOTICE_INFO_CD",
300,
name="基础hook配置",
help_="群检测,个人权限检测等各种检测提示信息cd",
default_value=300
default_value=300,
type=int,
)
Config.add_plugin_config(
@@ -15,7 +15,8 @@ Config.add_plugin_config(
"MALICIOUS_BAN_TIME",
30,
help_="恶意命令触发检测触发后ban的时长(分钟)",
default_value=30
default_value=30,
type=int,
)
Config.add_plugin_config(
@@ -23,14 +24,10 @@ Config.add_plugin_config(
"MALICIOUS_CHECK_TIME",
5,
help_="恶意命令触发检测规定时间内(秒)",
default_value=5
default_value=5,
type=int,
)
Config.add_plugin_config(
"hook",
"MALICIOUS_BAN_COUNT",
6,
help_="恶意命令触发检测最大触发次数",
default_value=6
"hook", "MALICIOUS_BAN_COUNT", 6, help_="恶意命令触发检测最大触发次数", default_value=6, type=int
)
+478 -5
View File
@@ -1,6 +1,40 @@
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent
from utils.manager import plugins2block_manager, StaticData
import time
from typing import Optional
import nonebot
from nonebot.adapters.onebot.v11 import (
Bot,
Event,
GroupMessageEvent,
Message,
MessageEvent,
PokeNotifyEvent,
PrivateMessageEvent,
)
from nonebot.exception import ActionFailed, IgnoredException
from nonebot.internal.matcher import Matcher
from configs.config import Config
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 services.log import logger
from utils.decorator import Singleton
from utils.manager import (
StaticData,
admin_manager,
group_manager,
plugins2block_manager,
plugins2cd_manager,
plugins2count_manager,
plugins2settings_manager,
plugins_manager,
)
from utils.message_builder import at
from utils.utils import FreqLimiter
ignore_rst_module = ["ai", "poke", "dialogue"]
@@ -8,7 +42,6 @@ other_limit_plugins = ["poke"]
class StatusMessageManager(StaticData):
def __init__(self):
super().__init__(None)
@@ -39,8 +72,8 @@ def set_block_limit_false(event, 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"]
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")
@@ -50,3 +83,443 @@ def set_block_limit_false(event, module):
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_user_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_user_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:
if plugin_name := matcher.plugin_name:
cost_gold = await self.auth_cost(plugin_name, bot, event)
user_id = getattr(event, "user_id", None)
if user_id and str(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)
logger.info(f"{event.user_id} ||XXXXXX: {matcher.module}")
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.create(
user_qq=event.user_id,
group_id=event.group_id,
type=2,
name=plugin_name,
num=1,
spend_gold=psm.cost_gold,
)
cost_gold = psm.cost_gold
return cost_gold
+16 -366
View File
@@ -1,386 +1,36 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
from nonebot.adapters.onebot.v11.exception import ActionFailed
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from models.bag_user import BagUser
from utils.manager import (
plugins2settings_manager,
admin_manager,
group_manager,
plugins_manager,
plugins2cd_manager,
plugins2block_manager,
plugins2count_manager,
)
from ._utils import (
set_block_limit_false,
status_message_manager,
ignore_rst_module,
other_limit_plugins,
)
from nonebot.typing import T_State
from typing import Optional
from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent,
GroupMessageEvent,
PokeNotifyEvent,
PrivateMessageEvent,
Message,
Event,
)
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
import nonebot
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, run_postprocessor
from nonebot.typing import T_State
_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"))
from ._utils import (
set_block_limit_false,
AuthChecker,
)
# 权限检测
# # 权限检测
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
module = matcher.plugin_name
plugins2info_dict = plugins2settings_manager.get_data()
# 功能的金币检测 #######################################
# 功能的金币检测 #######################################
# 功能的金币检测 #######################################
cost_gold = 0
if isinstance(
event, GroupMessageEvent
) and plugins2settings_manager.get_plugin_data(module).get("cost_gold"):
cost_gold = plugins2settings_manager.get_plugin_data(module).get("cost_gold")
if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
raise IgnoredException(f"{module} 金币限制...")
# 当插件不阻塞超级用户时,超级用户提前扣除金币
if (
str(event.user_id) in bot.config.superusers
and not plugins2info_dict[module]["limit_superuser"]
):
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
try:
if (
(not isinstance(event, MessageEvent) and module 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 plugins2info_dict.get(module)
and not plugins2info_dict[module]["limit_superuser"]
):
return
except AttributeError:
pass
# 超级用户命令
try:
_plugin = nonebot.plugin.get_plugin(module)
_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
):
return
except AttributeError:
pass
# 群黑名单检测 群总开关检测
if isinstance(event, GroupMessageEvent) or matcher.plugin_name == 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
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) 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 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("此功能正在维护...")
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 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)
# 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_)
# 功能花费的金币 #######################################
# 功能花费的金币 #######################################
if cost_gold:
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
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
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,
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)
async def init_rst(rst: str, event: MessageEvent):
if "[uname]" in rst:
uname = event.sender.card or 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
+18 -14
View File
@@ -1,20 +1,21 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
ActionFailed,
Bot,
Event,
GroupMessageEvent,
MessageEvent,
PokeNotifyEvent,
GroupMessageEvent,
)
from nonebot.matcher import Matcher
from nonebot.message import IgnoredException, run_preprocessor
from nonebot.typing import T_State
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
from utils.utils import FreqLimiter, is_number, static_flmt
from ._utils import ignore_rst_module, other_limit_plugins
Config.add_plugin_config(
"hook",
@@ -29,10 +30,13 @@ _flmt = FreqLimiter(300)
# 检查是否被ban
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if (
(isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent))
and matcher.priority not in [1, 9]
) or matcher.plugin_name in other_limit_plugins:
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)
@@ -46,7 +50,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
and str(event.user_id) not in bot.config.superusers
):
time = await BanUser.check_ban_time(event.user_id)
if is_number(time):
if isinstance(time, int):
time = abs(int(time))
if time < 60:
time = str(time) + " 秒"
@@ -58,7 +62,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id)
if matcher.priority != 9:
if matcher.priority != 999:
try:
ban_result = Config.get_config("hook", "BAN_RESULT")
if (
@@ -79,7 +83,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id)
if matcher.priority != 9:
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:
+5 -5
View File
@@ -1,9 +1,9 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
MessageEvent,
GroupMessageEvent,
)
@@ -25,15 +25,15 @@ _blmt = BanCheckLimiter(
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 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(
await BanUser.ban(
event.user_id,
9,
Config.get_config("hook", "MALICIOUS_BAN_TIME") * 60,
):
logger.info(f"USER {event.user_id} 触发了恶意触发检测")
)
logger.info(f"USER {event.user_id} 触发了恶意触发检测")
if isinstance(event, GroupMessageEvent):
try:
await bot.send_group_msg(
-8
View File
@@ -2,15 +2,12 @@ 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 utils.image_utils import text2image
from typing import Dict, Any
from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent,
PrivateMessageEvent,
GroupMessageEvent,
)
import re
# 为什么AI会自己和自己聊天
@@ -41,11 +38,6 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
status_message_manager.delete(event.user_id)
raise IgnoredException("有命令就别说话了")
# @Bot.on_calling_api
# async def handle_api_call(bot: Bot, api: str, data: Dict[str, Any]):
# if api in ["send_msg", "send_group_msg", "send_private_msg"]:
# msg = str(data["message"])
# if (r := re.search("\[\[To_Img\|?(.*?)]]", msg)) or (r := re.search("&#91;&#91;To_Img\|?(.*?)&#91;&#91;")):
+43 -34
View File
@@ -1,47 +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 handle_api_call(bot: Bot, api: str, data: Dict[str, Any]):
async def _(bot: Bot, api: str, data: Dict[str, Any]):
r = None
if (
(
(api == "send_msg" and data.get("message_type") == "group")
or api == "send_group_msg"
)
and (
task = None
group_id = None
try:
if (
(
r := re.search(
"^\[\[_task\|(.*)]]",
data["message"].strip()
if isinstance(data["message"], str)
else str(data["message"]["text"]).strip(),
(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(),
)
)
)
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}]]", ""
)
)
)
and r.group(1) in group_manager.get_task_data().keys()
):
task = r.group(1)
group_id = data["group_id"]
if group_manager.get_group_level(
group_id
) < 0 or not await group_manager.check_group_task_status(group_id, task):
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)
data["message"] = Message(msg)
+26 -31
View File
@@ -1,23 +1,23 @@
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_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
import nonebot
from nonebot import Driver
from nonebot.adapters.onebot.v11 import Bot
from configs.path_config import DATA_PATH
from services.log import logger
from pathlib import Path
from nonebot import Driver
import nonebot
from .check_plugin_status import check_plugin_status
from .init import init
from .init_none_plugin_count_manager import init_none_plugin_count_manager
from .init_plugin_info import init_plugin_info
from .init_plugins_config import init_plugins_config
from .init_plugins_data import init_plugins_data, plugins_manager
from .init_plugins_limit import (
init_plugins_block_limit,
init_plugins_cd_limit,
init_plugins_count_limit,
)
from .init_plugins_resources import init_plugins_resources
from .init_plugins_settings import init_plugins_settings
__zx_plugin_name__ = "初始化插件数据 [Hidden]"
__plugin_version__ = 0.1
@@ -28,27 +28,22 @@ driver: Driver = nonebot.get_driver()
@driver.on_startup
def _():
async def _():
"""
初始化数据
"""
_flag = False
config_file = DATA_PATH / "configs" / "plugins2config.yaml"
if not config_file.exists():
_flag = True
_flag = not config_file.exists()
init()
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)
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])
if _flag:
raise Exception("首次运行,已在configs目录下生成配置文件config.yaml,修改后重启即可...")
logger.info("初始化数据完成...")
@@ -56,5 +51,5 @@ def _():
@driver.on_bot_connect
async def _(bot: Bot):
await init_group_manager()
# await init_group_manager()
await check_plugin_status(bot)
@@ -6,13 +6,13 @@ async def check_plugin_status(bot: Bot):
"""
遍历查看插件加载情况
"""
rst = ""
msg = ""
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
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=rst[:-1]
user_id=int(list(bot.config.superusers)[0]), message=msg.strip()
)
@@ -1,73 +0,0 @@
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()
@@ -5,7 +5,6 @@ from utils.manager import (
plugins2settings_manager,
plugins2block_manager,
plugins_manager,
resources_manager
)
from services.log import logger
from utils.utils import get_matchers
@@ -20,26 +19,44 @@ 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}"
)
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,147 @@
import random
from types import ModuleType
from typing import Any, Dict
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, None) or default
def init_plugin_info():
for matcher in [x for x in get_matchers(True)]:
try:
if (plugin := matcher.plugin) and matcher.plugin_name:
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):
if plugin_configs:
for config_name in plugin_configs:
config: Dict[str, Any] = plugin_configs[config_name] # type: ignore
Config.add_plugin_config(
plugin_model,
config_name,
config.get("value"),
help_=config.get("help"),
default_value=config.get("default_value"),
type=config.get("type"),
)
plugin_configs = plugin_cfg.configs
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, # type: ignore
plugin_status=plugin_status,
)
plugin_data_manager.add_plugin_info(plugin_data)
except Exception as e:
logger.error(f"构造插件数据失败 {matcher.plugin_name}", e=e)
@@ -1,79 +1,86 @@
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
from ruamel import yaml
from ruamel.yaml import YAML, round_trip_dump, round_trip_load
from configs.config import Config
from configs.path_config import DATA_PATH
from services.log import logger
from utils.manager import admin_manager, plugin_data_manager, plugins_manager
from utils.text_utils import prompt2cn
from utils.utils import get_matchers
_yaml = YAML(typ="safe")
def init_plugins_config(data_path):
def init_plugins_config():
"""
初始化插件数据配置
"""
plugins2config_file = 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.plugin_name)
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.plugin_name)
and _data[matcher.plugin_name].keys() != plugin_configs.keys()
)
or plugin_version > plugins_manager.get(matcher.plugin_name)["version"]
or matcher.plugin_name not in _data.keys()
):
for key in plugin_configs:
if isinstance(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,
plugins2config_file = DATA_PATH / "configs" / "plugins2config.yaml"
_data = Config.get_data()
# 优先使用 metadata 数据
for matcher in get_matchers(True):
if matcher.plugin_name:
if plugin_data := plugin_data_manager.get(matcher.plugin_name):
# 插件配置版本更新或为Version为None或不在存储配置内,当使用metadata时,必定更新
version = plugin_data.plugin_status.version
config = _data.get(matcher.plugin_name)
plugin = plugins_manager.get(matcher.plugin_name)
if plugin_data.plugin_configs and (
isinstance(version, str)
or (
version is None
or (
config
and config.configs.keys()
!= plugin_data.plugin_configs.keys()
)
or version > int(plugin.version or 0)
or matcher.plugin_name not in _data.keys()
)
else:
Config.add_plugin_config(matcher.plugin_name, key, plugin_configs[key])
else:
plugin_configs = _data[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,
)
):
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,
type=plugin_configs[key].get("type"),
)
else:
config = plugin_configs[key]
Config.add_plugin_config(
matcher.plugin_name,
key,
config.value,
name=config.name,
help_=config.help,
default_value=config.default_value,
_override=True,
type=config.type,
)
elif plugin_configs := _data.get(matcher.plugin_name):
for key in plugin_configs.configs:
Config.add_plugin_config(
matcher.plugin_name,
key,
plugin_configs.configs[key].value,
help_=plugin_configs.configs[key].help,
default_value=plugin_configs.configs[key].default_value,
_override=True,
type=plugin_configs.configs[key].type,
)
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"]
plugin_name = plugins_manager.get(plugin).plugin_name
except (AttributeError, TypeError):
plugin_name = plugin
_data[plugin].yaml_set_start_comment(plugin_name, indent=2)
@@ -85,69 +92,82 @@ def init_plugins_config(data_path):
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():
_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].configs.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])
admin_manager.set_admin_level(
level2module, _data[plugin][k]
)
except KeyError:
logger.warning(f"{level2module} 设置权限等级失败:{_data[plugin][k]}")
logger.warning(
f"{level2module} 设置权限等级失败:{_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
except AttributeError as e:
raise AttributeError(
f"{e}\n" + prompt2cn("可能为config.yaml配置文件填写不规范", 46)
)
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()):
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:
if config_group := Config.get(plugin):
for key in list(config_group.configs.keys()):
try:
_x = plugin_data[x].get("name")
if _x:
plugin_name = _x
if config := config_group.configs[key]:
if config.name:
plugin_name = config.name
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()
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].configs[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()
@@ -1,8 +1,8 @@
from pathlib import Path
from ruamel.yaml import YAML
from utils.manager import plugins_manager
from utils.manager import plugins_manager, plugin_data_manager
from utils.utils import get_matchers
import nonebot
from services.log import logger
try:
import ujson as json
@@ -13,70 +13,45 @@ except ModuleNotFoundError:
_yaml = YAML(typ="safe")
def init_plugins_data(data_path):
def init_plugins_data():
"""
初始化插件数据信息
"""
plugin2data_file = 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.plugin_name)
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 _data.keys():
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.set_module_data(matcher.plugin_name, "error", True)
plugin_data = plugins_manager.get(matcher.plugin_name)
if plugin_data:
plugins_manager.set_module_data(
matcher.plugin_name, "version", plugin_data.get("version")
)
plugins_manager[matcher.plugin_name].error = True
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.plugin_name
try:
plugin_author = _module.__getattribute__("__plugin_author__")
except AttributeError:
plugin_author = None
if matcher.plugin_name in plugins_manager.keys():
plugins_manager.set_module_data(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 plugins_manager[matcher.plugin_name]["version"] is None or (
plugin_version is not None
and plugin_version > plugins_manager[matcher.plugin_name]["version"]
):
plugins_manager.set_module_data(
matcher.plugin_name, "plugin_name", plugin_name
)
plugins_manager.set_module_data(matcher.plugin_name, "author", plugin_author)
plugins_manager.set_module_data(
matcher.plugin_name, "version", plugin_version
)
if matcher.plugin_name in _data.keys():
plugins_manager.set_module_data(
matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
)
plugins_manager.set_module_data(
matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
)
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()
@@ -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,
plugin_data_manager,
)
from utils.utils import get_matchers
from ruamel import yaml
import nonebot
from configs.path_config import DATA_PATH
_yaml = YAML(typ="safe")
def init_plugins_cd_limit(data_path):
def init_plugins_cd_limit():
"""
加载 cd 限制
"""
plugins2cd_file = data_path / "configs" / "plugins2cd.yaml"
plugins2cd_file = 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.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try:
_module = _plugin.module
plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
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, data_dict=plugin_cd_limit
matcher.plugin_name, plugin_data.plugin_cd
)
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.add_cd_limit("这是一个示例")
plugins2cd_manager.save()
plugins2cd_manager.reload_cd_limit()
def init_plugins_block_limit(data_path):
def init_plugins_block_limit():
"""
加载阻塞限制
"""
plugins2block_file = 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.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try:
_module = _plugin.module
plugin_block_limit = _module.__getattribute__("__plugin_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, data_dict=plugin_block_limit
matcher.plugin_name, plugin_data.plugin_block
)
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.add_block_limit("这是一个示例")
plugins2block_manager.save()
plugins2block_manager.reload_block_limit()
def init_plugins_count_limit(data_path):
def init_plugins_count_limit():
"""
加载次数限制
"""
plugins2count_file = 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.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try:
_module = _plugin.module
plugin_count_limit = _module.__getattribute__("__plugin_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, data_dict=plugin_count_limit
matcher.plugin_name, plugin_data.plugin_count
)
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.add_count_limit("这是一个示例")
plugins2count_manager.save()
plugins2count_manager.reload_count_limit()
@@ -1,43 +1,25 @@
from utils.manager import resources_manager
from utils.manager import resources_manager, plugin_data_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.plugin_name not in _tmp:
_tmp.append(matcher.plugin_name)
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
for matcher in get_matchers(True):
if plugin_data := plugin_data_manager.get(matcher.plugin_name):
try:
_module = _plugin.module
_module = matcher.plugin.module
except AttributeError:
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,资源控制未加载...")
else:
try:
resources = _module.__getattribute__("__plugin_resources__")
except AttributeError:
pass
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.add_resource(
matcher.plugin_name, path / resource, resources[resource]
)
resources_manager.save()
resources_manager.start_move()
@@ -1,128 +1,44 @@
from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import plugins2settings_manager, admin_manager
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
from ruamel import yaml
import nonebot
_yaml = YAML(typ="safe")
def init_plugins_settings(data_path: str):
def init_plugins_settings():
"""
初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
"""
plugins2settings_file = data_path / "configs" / "plugins2settings.yaml"
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
_matchers = get_matchers()
_tmp_module = {}
_tmp = []
for x in plugins2settings_manager.keys():
# 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:
_plugin = nonebot.plugin.get_plugin(x)
_module = _plugin.module
plugin_name = _module.__getattribute__("__zx_plugin_name__")
_tmp_module[x] = plugin_name
except (KeyError, AttributeError) as e:
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
_tmp_module[x] = ""
for matcher in _matchers:
if matcher.plugin_name not in plugins2settings_manager.keys():
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try:
_module = _plugin.module
except AttributeError:
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
else:
if matcher.plugin_name not in plugins2settings_manager.keys():
_plugin = matcher.plugin
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 level is None:
level = 5
admin_manager.add_admin_plugin_settings(
matcher.plugin_name, cmd, level
)
if (
"[hidden]" in plugin_name.lower()
or "[admin]" in plugin_name.lower()
or "[superuser]" in plugin_name.lower()
or matcher.plugin_name in plugins2settings_manager.keys()
):
continue
_module = _plugin.module
except AttributeError:
if matcher.plugin_name not in _tmp:
logger.warning(
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
)
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
else:
try:
_tmp_module[matcher.plugin_name] = plugin_name
plugin_settings = _module.__getattribute__(
"__plugin_settings__"
)
if plugin_settings.get('cost_gold') is None:
plugin_settings['cost_gold'] = 0
if (
plugin_settings.get("cmd") is not None
and plugin_name not in plugin_settings["cmd"]
):
plugin_settings["cmd"].append(plugin_name)
if plugins2settings_manager.get(
matcher.plugin_name
) and plugins2settings_manager[matcher.plugin_name].get(
"plugin_type"
):
plugin_type = tuple(
plugins2settings_manager.get_plugin_data(
matcher.plugin_name
)["plugin_type"]
)
else:
try:
plugin_type = _module.__getattribute__(
"__plugin_type__"
if plugin_data := plugin_data_manager.get(matcher.plugin_name):
if plugin_settings := plugin_data.plugin_setting:
if (name := _module.__getattribute__("__zx_plugin_name__")) not in plugin_settings.cmd:
plugin_settings.cmd.append(name)
# 管理员命令
if plugin_data.plugin_type == PluginType.ADMIN:
admin_manager.add_admin_plugin_settings(
matcher.plugin_name, plugin_settings.cmd, plugin_settings.level
)
except AttributeError:
plugin_type = ("normal",)
if plugin_settings and matcher.plugin_name:
plugins2settings_manager.add_plugin_settings(
matcher.plugin_name,
plugin_type=plugin_type,
**plugin_settings,
)
except AttributeError:
pass
_tmp.append(matcher.plugin_name)
_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)
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())} 个非限制插件.")
+109 -92
View File
@@ -1,127 +1,145 @@
from nonebot import on_request, on_message
import asyncio
import re
import time
from datetime import datetime
from nonebot import on_message, on_request
from nonebot.adapters.onebot.v11 import (
ActionFailed,
Bot,
FriendRequestEvent,
GroupRequestEvent,
MessageEvent,
)
from models.friend_user import FriendUser
from datetime import datetime
from configs.config import NICKNAME, Config
from nonebot.adapters.onebot.v11.exception import ActionFailed
from utils.manager import requests_manager
from models.friend_user import FriendUser
from models.group_info import GroupInfo
from services.log import logger
from utils.manager import requests_manager
from utils.utils import scheduler
import asyncio
import time
import re
from .utils import time_manager
__zx_plugin_name__ = "好友群聊处理请求 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_configs__ = {
"AUTO_ADD_FRIEND": {"value": False, "help": "是否自动同意好友添加", "default_value": False}
"AUTO_ADD_FRIEND": {
"value": False,
"help": "是否自动同意好友添加",
"default_value": False,
"type": bool,
}
}
friend_req = on_request(priority=5, block=True)
group_req = on_request(priority=5, block=True)
x = on_message(priority=9, block=False)
exists_data = {"private": {}, "group": {}}
x = on_message(priority=999, block=False, rule=lambda: False)
@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,
if time_manager.add_user_request(event.user_id):
logger.debug(f"收录 用户[{event.user_id}] 好友请求", "好友请求")
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"):
logger.debug(f"已开启好友请求自动同意,成功通过该请求", "好友请求", target=event.user_id)
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.create(user_id=user["user_id"], user_name=user["nickname"])
else:
requests_manager.add_request(
event.user_id,
"private",
event.flag,
nickname=nickname,
sex=sex,
age=age,
comment=comment,
)
else:
logger.debug(f"好友请求五分钟内重复, 已忽略", "好友请求", target=event.user_id)
@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,
)
logger.debug(
f"超级用户自动同意加入群聊", "群聊请求", event.user_id, target=event.group_id
)
await bot.set_group_add_request(
flag=event.flag, sub_type="invite", approve=True
)
except ActionFailed:
pass
group_info = await bot.get_group_info(group_id=event.group_id)
await GroupInfo.update_or_create(
group_id=group_info["group_id"],
defaults={
"group_name": group_info["group_name"],
"max_member_count": group_info["max_member_count"],
"member_count": group_info["member_count"],
"group_flag": 1,
},
)
except ActionFailed as e:
logger.error(
"超级用户自动同意加入群聊发生错误",
"群聊请求",
event.user_id,
target=event.group_id,
e=e,
)
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,
)
if time_manager.add_group_request(event.user_id, event.group_id):
logger.debug(
f"收录 用户[{event.user_id}] 群聊[{event.group_id}] 群聊请求", "群聊请求"
)
user = await bot.get_stranger_info(user_id=event.user_id)
sex = user["sex"]
age = str(user["age"])
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"邀请日期:{datetime.now().replace(microsecond=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,
)
else:
logger.debug(
f"群聊请求五分钟内重复, 已忽略",
"群聊请求",
target=f"{event.user_id}:{event.group_id}",
)
@x.handle()
@@ -145,5 +163,4 @@ async def _(event: MessageEvent):
minutes=5,
)
async def _():
global exists_data
exists_data = {"private": {}, "group": {}}
time_manager.clear()
+87
View File
@@ -0,0 +1,87 @@
import time
from dataclasses import dataclass
from typing import Dict
@dataclass
class PrivateRequest:
"""
好友请求
"""
user_id: int
time: float = time.time()
@dataclass
class GroupRequest:
"""
群聊请求
"""
user_id: int
group_id: int
time: float = time.time()
class RequestTimeManage:
"""
过滤五分钟以内的重复请求
"""
def __init__(self):
self._group: Dict[str, GroupRequest] = {}
self._user: Dict[int, PrivateRequest] = {}
def add_user_request(self, user_id: int) -> bool:
"""
添加请求时间
Args:
user_id (int): 用户id
Returns:
bool: 是否满足时间
"""
if user := self._user.get(user_id):
if time.time() - user.time < 60 * 5:
return False
self._user[user_id] = PrivateRequest(user_id)
return True
def add_group_request(self, user_id: int, group_id: int) -> bool:
"""
添加请求时间
Args:
user_id (int): 用户id
group_id (int): 邀请群聊
Returns:
bool: 是否满足时间
"""
key = f"{user_id}:{group_id}"
if group := self._group.get(key):
if time.time() - group.time < 60 * 5:
return False
self._group[key] = GroupRequest(user_id=user_id, group_id=group_id)
return True
def clear(self):
"""
清理过期五分钟请求
"""
now = time.time()
for user_id in self._user:
if now - self._user[user_id].time < 60 * 5:
del self._user[user_id]
for key in self._group:
if now - self._group[key].time < 60 * 5:
del self._group[key]
time_manager = RequestTimeManage()
+136 -129
View File
@@ -1,114 +1,163 @@
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message
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
from typing import Any, List, Tuple
from nonebot import on_command, on_regex
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.internal.matcher import Matcher
from nonebot.internal.params import Depends
from nonebot.params import CommandArg, RegexGroup
from nonebot.rule import to_me
from configs.config import NICKNAME
from models.ban_user import BanUser
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.depends import GetConfig
__zx_plugin_name__ = "昵称系统"
__plugin_usage__ = f"""
usage:
个人昵称系统,群聊 与 私聊 昵称相互独立
个人昵称,将替换真寻称呼你的名称,群聊 与 私聊 昵称相互独立,全局昵称设置将更改您目前所有群聊中及私聊的昵称
指令:
以后叫我 [昵称]
以后叫我 [昵称]: 设置当前群聊/私聊的昵称
全局昵称设置 [昵称]: 设置当前所有群聊和私聊的昵称
{NICKNAME}我是谁
""".strip()
__plugin_des__ = "区区昵称,才不想叫呢!"
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
__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
"value": ["爸", "爹", "爷", "父"],
"help": "昵称所屏蔽的关键词,已设置的昵称会被替换为 *,未设置的昵称会在设置时提示",
"default_value": None,
"type": List[str],
}
}
nickname = on_command(
"nickname",
aliases={"以后叫我", "以后请叫我", "称呼我", "以后请称呼我", "以后称呼我", "叫我", "请叫我"},
nickname = on_regex(
"(?:以后)?(?:叫我|请叫我|称呼我)(.*)",
rule=to_me(),
priority=5,
block=True,
)
my_nickname = on_command(
"my_name", aliases={"我叫什么", "我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
"我叫什么", aliases={"我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
)
global_nickname = on_regex("设置全局昵称(.*)", 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, 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")
for x in msg:
_tmp += "*" if x in black_word else x
msg = _tmp
def CheckNickname():
"""
说明:
检查名称是否合法
"""
async def dependency(
bot: Bot,
matcher: Matcher,
event: MessageEvent,
reg_group: Tuple[Any, ...] = RegexGroup(),
black_word: Any = GetConfig(config="BLACK_WORD"),
):
(msg,) = reg_group
logger.debug(f"昵称检查: {msg}", "昵称设置", event.user_id)
if not msg:
await matcher.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
if str(event.user_id) in bot.config.superusers:
logger.debug(f"超级用户设置昵称, 跳过合法检测: {msg}", "昵称设置", event.user_id)
return
if len(msg) > 20:
await nickname.finish("昵称可不能超过20个字!", at_sender=True)
if msg in bot.config.nickname:
await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True)
if black_word:
for x in msg:
if x in black_word:
logger.debug("昵称设置禁止字符: [{x}]", "昵称设置", event.user_id)
await nickname.finish(f"字符 [{x}] 为禁止字符!", at_sender=True)
for word in black_word:
if word in msg:
logger.debug("昵称设置禁止字符: [{word}]", "昵称设置", event.user_id)
await nickname.finish(f"字符 [{word}] 为禁止字符!", at_sender=True)
return Depends(dependency)
@global_nickname.handle(parameterless=[CheckNickname()])
async def _(
event: MessageEvent,
reg_group: Tuple[Any, ...] = RegexGroup(),
):
(msg,) = reg_group
await FriendUser.set_user_nickname(event.user_id, msg)
await GroupInfoUser.filter(user_qq=event.user_id).update(nickname=msg)
logger.info(f"设置全局昵称成功: {msg}", "设置全局昵称", event.user_id)
await global_nickname.send(f"设置全局昵称成功!亲爱的{msg}")
@nickname.handle(parameterless=[CheckNickname()])
async def _(
event: MessageEvent,
reg_group: Tuple[Any, ...] = RegexGroup(),
):
(msg,) = reg_group
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}了.",
]
)
await GroupInfoUser.set_user_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} 失败")
)
logger.info(f"设置群昵称成功: {msg}", "昵称设置", event.user_id, event.group_id)
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}了.",
]
)
await FriendUser.set_user_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} 失败")
)
logger.info(f"设置私聊昵称成功: {msg}", "昵称设置", event.user_id)
@my_nickname.handle()
async def _(event: GroupMessageEvent):
try:
nickname_ = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
except AttributeError:
nickname_ = ""
async def _(event: MessageEvent):
nickname_ = None
card = None
if isinstance(event, GroupMessageEvent):
nickname_ = await GroupInfoUser.get_user_nickname(event.user_id, event.group_id)
card = event.sender.card or event.sender.nickname
else:
nickname_ = await FriendUser.get_user_nickname(event.user_id)
card = event.sender.nickname
if nickname_:
await my_nickname.send(
random.choice(
@@ -123,44 +172,20 @@ async def _(event: GroupMessageEvent):
)
)
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_)
).format(card)
)
@cancel_nickname.handle()
async def _(event: GroupMessageEvent):
nickname_ = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
async def _(event: MessageEvent):
nickname_ = None
if isinstance(event, GroupMessageEvent):
nickname_ = await GroupInfoUser.get_user_nickname(event.user_id, event.group_id)
else:
nickname_ = await FriendUser.get_user_nickname(event.user_id)
if nickname_:
await cancel_nickname.send(
random.choice(
@@ -173,28 +198,10 @@ async def _(event: GroupMessageEvent):
]
)
)
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)
if isinstance(event, GroupMessageEvent):
await GroupInfoUser.set_user_nickname(event.user_id, event.group_id, "")
else:
await FriendUser.set_user_nickname(event.user_id, "")
await BanUser.ban(event.user_id, 9, 60)
else:
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
+75
View File
@@ -0,0 +1,75 @@
from nonebot import on_command, on_regex
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
from services.log import logger
from utils.message_builder import image
from .data_source import (
download_json,
install_plugin,
show_plugin_repo,
uninstall_plugin,
)
__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()):
name = arg.extract_plain_text().strip()
msg = await install_plugin(name)
await install_plugin_matcher.send(msg)
logger.info(f"安装插件: {name}", "安装插件", event.user_id)
@uninstall_plugin_matcher.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
name = arg.extract_plain_text().strip()
msg = await uninstall_plugin(name)
await install_plugin_matcher.send(msg)
logger.info(f"卸载插件: {name}", "卸载插件", event.user_id)
@update_repo.handle()
async def _(bot: Bot, event: MessageEvent):
code = await download_json()
if code == 200:
await update_repo.finish("更新插件仓库信息成功!")
await update_repo.send("更新插件仓库信息失败!")
logger.info("更新插件仓库信息", "更新插件仓库信息", event.user_id)
@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(msg))
logger.info("查看插件仓库", "查看插件仓库", event.user_id)
+201
View File
@@ -0,0 +1,201 @@
import os
import shutil
import zipfile
from pathlib import Path
from typing import Tuple, Union
import ujson as json
from configs.path_config import DATA_PATH, TEMP_PATH
from services import logger
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage, text2image
from utils.manager import plugins_manager
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("开始解压插件压缩包...", "安装插件", target=name)
# 解压
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("解压插件压缩包完成...", "安装插件", target=name)
logger.debug("开始移动插件文件夹...", "安装插件", target=name)
if (extensive_plugin_path / f"{name}").exists():
logger.debug(
"extensive_plugin目录下文件夹已存在,删除该目录插件文件夹...", "安装插件", target=name
)
shutil.rmtree(
(extensive_plugin_path / f"{name}").absolute(), ignore_errors=True
)
extract_path.rename(extensive_plugin_path / f"{name}")
prompt = ""
if "pyproject.toml" in os.listdir(extensive_plugin_path / f"{name}"):
prompt = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
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}"):
prompt = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
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("移动插件文件夹完成...", "安装插件", target=name)
logger.info(f"成功安装插件 {name} 成功!\n{prompt}", "安装插件", target=name)
return f"成功安装插件 {name},请重启真寻!"
except Exception as e:
logger.error(f"安装插失败", "安装插件", target=name, 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
+139 -137
View File
@@ -1,20 +1,16 @@
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
import random
from asyncio.exceptions import TimeoutError
from typing import List
from utils.http_utils import AsyncHttpx
from utils.utils import scheduler
import nonebot
from nonebot.adapters.onebot.v11 import Bot
from nonebot.drivers import Driver
from configs.path_config import TEXT_PATH
from models.bag_user import BagUser
from models.group_info import GroupInfo
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.utils import GDict, scheduler
try:
import ujson as json
@@ -35,6 +31,7 @@ async def update_city():
data = {}
if not china_city.exists():
try:
logger.debug("开始更新城市列表...")
res = await AsyncHttpx.get(
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
)
@@ -53,99 +50,97 @@ async def update_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 TimeoutError as e:
logger.warning("自动更新城市列表超时...", e=e)
except ValueError as e:
logger.warning("自动城市列表失败.....", e=e)
except Exception as e:
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
logger.error(f"自动城市列表未知错误", 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"
), # 新增原神群号绑定字段
]
for sql in sql_str:
try:
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)
# 完成后
end_sql_str = [
# "ALTER TABLE bag_users DROP COLUMN props;" # 删除 bag_users 的 props 字段(还不到时候)
]
for sql in end_sql_str:
try:
query = db.text(sql)
await db.first(query)
logger.info(f"完成执行sql操作:{sql}")
except (DuplicateColumnError, UndefinedColumnError):
pass
except PostgresSyntaxError:
logger.error(f"语法错误:执行sql失败:{sql}")
# str2json_sql = ["alter table bag_users alter COLUMN props type json USING props::json;"] # 字段类型替换
# rename_sql = 'alter table {} rename {} to {};' # 字段更名
# for sql in str2json_sql:
# try:
# query = db.text(sql)
# await db.first(query)
# except DuplicateColumnError:
# pass
# @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
@@ -154,51 +149,58 @@ async def _(bot: Bot):
版本某些需要的变换
"""
# 清空不存在的群聊信息,并将已所有已存在的群聊group_flag设置为1(认证所有已存在的群)
if not await GroupInfo.get_group_info(114514):
if not await GroupInfo.get_or_none(group_id=114514):
# 标识符,该功能只需执行一次
await GroupInfo.add_group_info(114514, "114514", 114514, 114514, 1)
await GroupInfo.create(
group_id=114514,
group_name="114514",
max_member_count=114514,
member_count=114514,
group_flag=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()]
_gl = [x.group_id for x in await GroupInfo.all()]
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)
if group := await GroupInfo.get_or_none(group_id=group_id):
group.group_flag = 1
await group.save(update_fields=["group_flag"])
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,
await GroupInfo.create(
group_id=group_info["group_id"],
group_name=group_info["group_name"],
max_member_count=group_info["max_member_count"],
member_count=group_info["member_count"],
group_flag=1,
)
logger.info(f"已将群聊 {group_id} 添加认证...")
logger.info(f"已添加群认证...", group_id=group_id)
else:
await GroupInfo.delete_group_info(group_id)
logger.info(f"移除不存在的群聊信息:{group_id}")
await GroupInfo.filter(group_id=group_id).delete()
logger.info(f"移除不存在的群聊信息", group_id=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()
# 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()
# 自动更新城市列表
+15 -2
View File
@@ -1,5 +1,12 @@
from pathlib import Path
import nonebot
from nonebot.drivers import Driver
from configs.config import Config
from utils.decorator.shop import shop_register
driver: Driver = nonebot.get_driver()
Config.add_plugin_config(
@@ -7,8 +14,14 @@ Config.add_plugin_config(
"IMPORT_DEFAULT_SHOP_GOODS",
True,
help_="导入商店自带的三个商品",
default_value=True
default_value=True,
type=bool,
)
nonebot.load_plugins("basic_plugins/shop")
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
@driver.on_bot_connect
async def _():
await shop_register.load_register()
+48 -33
View File
@@ -1,14 +1,15 @@
from nonebot import on_command
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
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.params import CommandArg
from models.bag_user import BagUser
from models.goods_info import GoodsInfo
from models.user_shop_gold_log import UserShopGoldLog
from services.log import logger
from utils.utils import is_number
__zx_plugin_name__ = "商店 - 购买道具"
__plugin_usage__ = """
@@ -46,10 +47,7 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
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
]
goods_name_list = [x.goods_name for x in goods_list]
msg = arg.extract_plain_text().strip().split()
num = 1
if len(msg) > 1:
@@ -72,23 +70,40 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
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)
if await BagUser.buy_property(event.user_id, event.group_id, goods, 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} 成功!"
)
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} 失败!"
)
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)
spend_gold = int(goods.goods_discount * goods.goods_price * num)
await BagUser.spend_gold(event.user_id, event.group_id, spend_gold)
await BagUser.add_property(event.user_id, event.group_id, goods.goods_name, 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"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!",
"购买道具",
event.user_id,
event.group_id,
)
await UserShopGoldLog.create(
user_qq=event.user_id,
group_id=event.group_id,
type=0,
name=goods.goods_name,
num=num,
spend_gold=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} 失败!"
# )
+16 -6
View File
@@ -1,9 +1,11 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.params import CommandArg
from nonebot.adapters.onebot.v11 import ActionFailed, GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.data_utils import init_rank
from nonebot.params import CommandArg
from models.bag_user import BagUser
from utils.data_utils import init_rank
from utils.image_utils import text2image
from utils.message_builder import image
from utils.utils import is_number
@@ -34,7 +36,13 @@ gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP)
@my_gold.handle()
async def _(event: GroupMessageEvent):
await my_gold.finish(await BagUser.get_user_total_gold(event.user_id, event.group_id))
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()
@@ -44,9 +52,11 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
num = int(num)
else:
num = 10
all_users = await BagUser.get_all_users(event.group_id)
all_users = await BagUser.filter(group_id=event.group_id)
all_user_id = [user.user_qq for user in all_users]
all_user_data = [user.gold for user in all_users]
rank_image = await init_rank("金币排行", all_user_id, all_user_data, event.group_id, num)
rank_image = await init_rank(
"金币排行", all_user_id, all_user_data, event.group_id, num
)
if rank_image:
await gold_rank.finish(image(b64=rank_image.pic2bs4()))
@@ -1,9 +1,12 @@
from nonebot import on_command
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
from models.bag_user import BagUser
from services.log import logger
from utils.message_builder import image
from ._data_source import create_bag_image
__zx_plugin_name__ = "商店 - 我的道具"
__plugin_usage__ = """
@@ -14,7 +17,7 @@ usage:
""".strip()
__plugin_des__ = "商店 - 我的道具"
__plugin_cmd__ = ["我的道具"]
__plugin_type__ = ('商店',)
__plugin_type__ = ("商店",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
@@ -32,10 +35,7 @@ my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
async def _(event: GroupMessageEvent):
props = await BagUser.get_property(event.user_id, event.group_id)
if 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)
await my_props.send(image(b64=await create_bag_image(props)))
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
-26
View File
@@ -1,26 +0,0 @@
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}")
+55 -26
View File
@@ -1,15 +1,24 @@
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info
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
from nonebot.params import CommandArg
from nonebot.plugin import export
from services.log import logger
import os
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Message, MessageEvent
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
from configs.path_config import IMAGE_PATH
from models.bag_user import BagUser
from services.log import logger
from utils.message_builder import image
from utils.utils import is_number, scheduler
from .data_source import (
GoodsInfo,
create_shop_help,
delete_goods,
parse_goods_info,
register_goods,
update_goods,
)
__zx_plugin_name__ = "商店"
__plugin_usage__ = """
@@ -38,7 +47,7 @@ __plugin_cmd__ = [
"删除商品 [名称或序号] [_superuser]",
"修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时] [_superuser]",
]
__plugin_type__ = ('商店',)
__plugin_type__ = ("商店",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
@@ -47,15 +56,8 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["商店"],
}
__plugin_block_limit__ = {
"limit_type": "group"
}
__plugin_block_limit__ = {"limit_type": "group"}
# 导出方法供其他插件使用
export = export()
export.register_goods = register_goods
export.delete_goods = delete_goods
export.update_goods = update_goods
shop_help = on_command("商店", priority=5, block=True)
@@ -81,12 +83,15 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
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)
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)
@@ -128,6 +133,30 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
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(f"修改商品 {name} 失败了...", at_sender=True)
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.all().update(daily_purchase_limit={})
logger.info("商品每日限购次数重置成功...")
except Exception as e:
logger.error(f"商品每日限购次数重置出错 {type(e)}:{e}")
@scheduler.scheduled_job(
"cron",
hour=0,
minute=1,
)
async def _():
try:
await BagUser.all().update(get_today_gold=0, spend_today_gold=0)
except Exception as e:
logger.error(f"重置每日金币", "定时任务", e=e)
+259 -107
View File
@@ -1,43 +1,18 @@
from models.goods_info import GoodsInfo
from utils.image_utils import BuildImage
from models.sign_group_user import SignGroupUser
from utils.utils import is_number
from configs.path_config import IMAGE_PATH
from typing import Optional, Union
from configs.config import Config
from nonebot import Driver
from nonebot.plugin import require
import nonebot
import time
from typing import Optional, Tuple, Union
driver: Driver = nonebot.get_driver()
from PIL import Image
use = require("use")
from configs.path_config import IMAGE_PATH
from models.goods_info import GoodsInfo
from utils.image_utils import BuildImage, text2image
from utils.utils import GDict, is_number
icon_path = IMAGE_PATH / "shop_icon"
@driver.on_startup
async def init_default_shop_goods():
"""
导入内置的三个商品
"""
async def sign_card(**kwargs):
user_id = kwargs['user_id']
group_id = kwargs['group_id']
prob = kwargs["prob"]
user = await SignGroupUser.ensure(user_id, group_id)
await user.update(add_probability=prob).apply()
if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
await register_goods(
"好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"
)
use.register_use("好感度双倍加持卡Ⅰ", sign_card, **{"prob": 0.1})
await register_goods("好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)")
use.register_use("好感度双倍加持卡Ⅱ", sign_card, **{"prob": 0.2})
await register_goods(
"好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"
)
use.register_use("好感度双倍加持卡Ⅲ", sign_card, **{"prob": 0.3})
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);")
# 创建商店界面
@@ -47,91 +22,230 @@ async def create_shop_help() -> str:
:return: 图片base64
"""
goods_lst = await GoodsInfo.get_all_goods()
idx = 1
_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:
h += len(goods.goods_description.strip().split("\n")) * font_h + 80
_list.append(goods)
A = BuildImage(1000, h, color="#f9f6f2")
current_h = 0
for goods in _list:
bk = BuildImage(
700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf"
)
goods_image = BuildImage(
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
)
# 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}.{goods.goods_name}", center_type="by_height"
(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")
await name_image.atext(
(440, 0), str(goods.goods_price), (255, 255, 255), 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.atext((15, 50), f"简介:{goods.goods_description}")
await goods_image.acircle_corner(20)
await bk.apaste(goods_image, alpha=True)
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:
_limit_time_logo = BuildImage(40, 40, background=f"{IMAGE_PATH}/other/time.png")
await bk.apaste(_limit_time_logo, (600, 0), True)
await bk.apaste(BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"), (640, 10), True)
limit_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)).split()
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((605, 38), str(y_m_d))
await bk.atext((615, 57), str(h_m))
await bk.aline((550, -1, 710, -1), "#a29ad6", 5)
await bk.aline((550, 80, 710, 80), "#a29ad6", 5)
idx += 1
await A.apaste(bk, (0, current_h), True)
current_h += 90
w = 1000
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")
shop.paste(A, (20, 230))
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan.png")
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, (780, 100))
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, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
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,
**kwargs,
):
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:
"""
添加商品
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
@@ -142,25 +256,35 @@ async def register_goods(
:param des: 商品简介
:param discount: 商品折扣
:param limit_time: 商品限时销售时间,单位为小时
:param kwargs: kwargs
:param daily_limit: 每日购买次数限制
:param is_passive: 是否为被动
:param icon: 图标
:return: 是否添加成功
"""
if kwargs:
name = kwargs.get("name")
price = kwargs.get("price")
des = kwargs.get("des")
discount = kwargs.get("discount")
limit_time = kwargs.get("time_limit")
limit_time = float(limit_time) if limit_time else limit_time
discount = discount if discount is 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
)
if not await GoodsInfo.get_or_none(goods_name=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
)
await GoodsInfo.create(
goods_name=name,
goods_price=int(price),
goods_description=des,
goods_discount=float(discount),
goods_limit_time=limit_time_,
daily_limit=daily_limit,
is_passive=is_passive,
icon=icon,
)
return True
return False
# 删除商品
async def delete_goods(name: str, id_: int) -> "str, str, int":
async def delete_goods(name: str, id_: int) -> Tuple[str, str, int]:
"""
删除商品
:param name: 商品名称
@@ -181,10 +305,11 @@ async def delete_goods(name: str, id_: int) -> "str, str, int":
return f"删除商品 {name} 成功!", name, 200
else:
return f"删除商品 {name} 失败!", name, 999
return "获取商品失败", "", 999
# 更新商品信息
async def update_goods(**kwargs) -> "str, str, int":
async def update_goods(**kwargs) -> Tuple[bool, str, str]:
"""
更新商品信息
:param kwargs: kwargs
@@ -194,17 +319,19 @@ async def update_goods(**kwargs) -> "str, str, int":
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 "序号错误,没有该序号的商品...", "", 999
return False, "序号错误,没有该序号的商品...", ""
goods = goods_lst[int(kwargs["name"]) - 1]
else:
goods = await GoodsInfo.get_goods_info(kwargs["name"])
goods = await GoodsInfo.filter(goods_name=kwargs["name"]).first()
if not goods:
return "名称错误,没有该名称的商品...", "", 999
name = goods.goods_name
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"):
@@ -218,20 +345,41 @@ async def update_goods(**kwargs) -> "str, str, int":
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),
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"
tmp += f"限时至: {new_time}\n" if new_time else "取消了限时\n"
limit_time = kwargs["limit_time"]
return (
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),
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],
)
@@ -264,6 +412,10 @@ def parse_goods_info(msg: str) -> Union[dict, str]:
data["discount"] = sp[1]
elif sp[0] == "limit_time":
if not is_number(sp[1]) or float(sp[1]) < 0:
return "limit_time参数不合法,必须大于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
+76 -40
View File
@@ -1,26 +1,33 @@
from nonebot import on_command
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
from nonebot.params import CommandArg
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 nonebot.plugin import export
from .data_source import effect, register_use, func_manager
from typing import Any, Tuple
from nonebot import on_command, on_regex
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.params import CommandArg, RegexGroup
from models.bag_user import BagUser
from models.user_shop_gold_log import UserShopGoldLog
from services.log import logger
from utils.decorator.shop import NotMeetUseConditionsException
from utils.utils import is_number
from .data_source import build_params, effect, func_manager, register_use
__zx_plugin_name__ = "商店 - 使用道具"
__plugin_usage__ = """
usage:
普通的使用道具
指令:
使用道具 [序号或道具名称] ?[数量]=1
使用道具 [序号或道具名称] ?[数量]=1 ?[其他信息]
示例:使用道具好感度双倍加持卡 使用道具好感度双倍加持卡
示例:使用道具1 使用第一个道具
示例:使用道具1 10 使用10个第一个道具
示例:使用道具1 1 来点色图 使用第一个道具并附带信息
* 序号以 ”我的道具“ 为准 *
""".strip()
__plugin_des__ = "商店 - 使用道具"
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
__plugin_type__ = ('商店',)
__plugin_type__ = ("商店",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
@@ -30,52 +37,81 @@ __plugin_settings__ = {
"cmd": ["商店", "使用道具"],
}
# 导出方法供其他插件使用
export = export()
export.register_use = register_use
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
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().strip()
msg = arg.extract_plain_text()
num = 1
msg_sp = msg.split()
if len(msg_sp) > 1 and is_number(msg_sp[-1]) and int(msg_sp[-1]) > 0:
num = int(msg.split()[-1])
msg = " ".join(msg.split()[:-1])
property_ = await BagUser.get_property(event.user_id, event.group_id)
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_:
async with db.transaction():
if is_number(msg):
if 0 < int(msg) <= len(property_):
name = list(property_.keys())[int(msg) - 1]
else:
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
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:
if msg not in property_.keys():
await use_props.finish("道具名称错误!", at_sender=True)
name = msg
_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} 个!")
if await BagUser.delete_property(
event.user_id, event.group_id, name, num
):
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
if not name:
await use_props.finish("未获取到道具名称", at_sender=True)
_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} 个!")
try:
model, kwargs = build_params(bot, event, name, num, text)
except KeyError:
logger.warning(f"{name} 未注册使用函数")
await use_props.finish(f"{name} 未注册使用方法")
else:
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)
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):
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.create(
user_qq=event.user_id,
group_id=event.group_id,
type=1,
name=name,
num=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)
+149 -35
View File
@@ -1,7 +1,11 @@
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment, Message
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot
from typing import Optional, Union
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
@@ -9,6 +13,30 @@ 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):
"""
注册商品使用方法
@@ -30,24 +58,69 @@ class GoodsUseFuncManager:
:param goods_name: 商品名称
"""
if self.exists(goods_name):
return self._data[goods_name]["kwargs"]["_max_num_limit"]
return self._data[goods_name]["kwargs"]["max_num_limit"]
return 1
async def use(self, **kwargs) -> Optional[Union[str, MessageSegment]]:
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 = kwargs.get("goods_name")
goods_name = param.goods_name
if self.exists(goods_name):
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
return await self._data[goods_name]["func"](
**kwargs,
)
# 使用方法
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:
return self._data[goods_name]["func"](
**kwargs,
)
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.get(goods_name) and 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:
"""
@@ -67,12 +140,56 @@ class GoodsUseFuncManager:
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: 其他信息
"""
_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
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int, text: str, message: Message
) -> Optional[Union[str, MessageSegment]]:
"""
商品生效
@@ -80,29 +197,22 @@ async def effect(
: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)
return await func_manager.use(
**{
**_kwargs,
"_bot": bot,
"event": event,
"group_id": event.group_id,
"user_id": event.user_id,
"num": num,
"goods_name": goods_name,
}
)
except Exception as e:
logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
# 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, **kwargs):
def register_use(goods_name: str, func: Callable, **kwargs):
"""
注册商品使用方法
:param goods_name: 商品名称
@@ -112,10 +222,14 @@ def register_use(goods_name: str, func, **kwargs):
if func_manager.exists(goods_name):
raise ValueError("该商品使用函数已被注册!")
# 发送使用成功信息
if kwargs.get("send_success_msg") is None:
kwargs["send_success_msg"] = True
kwargs["_max_num_limit"] = (
kwargs.get("_max_num_limit") if kwargs.get("_max_num_limit") else 1
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,
},
)
func_manager.register_use(goods_name, **{"func": func, "kwargs": kwargs})
logger.info(f"register_use 成功注册商品:{goods_name} 的使用函数")
+3 -8
View File
@@ -1,10 +1,5 @@
from pathlib import Path
import nonebot
nonebot.load_plugins('basic_plugins/super_cmd')
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
+32 -27
View File
@@ -1,14 +1,17 @@
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 import on_command
from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.utils import is_number
from models.group_info import GroupInfo
from services.log import logger
from utils.depends import OneCommand
from utils.manager import requests_manager
from utils.message_builder import image
from models.group_info import GroupInfo
from utils.utils import is_number
__zx_plugin_name__ = "显示所有好友群组 [Superuser]"
__plugin_usage__ = """
@@ -76,8 +79,7 @@ async def _(bot: Bot):
@friend_handle.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(bot: Bot, cmd: str = OneCommand(), arg: Message = CommandArg()):
id_ = arg.extract_plain_text().strip()
if is_number(id_):
id_ = int(id_)
@@ -97,8 +99,9 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
@group_handle.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(
bot: Bot, event: MessageEvent, cmd: str = OneCommand(), arg: Message = CommandArg()
):
id_ = arg.extract_plain_text().strip()
flag = None
if is_number(id_):
@@ -106,31 +109,33 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
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)
if group := await GroupInfo.get_or_none(group_id=rid):
group.group_flag = 1
await group.save(update_fields=["group_flag"])
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
await GroupInfo.create(
group_id=rid,
group_name=group_info["group_name"],
max_member_count=group_info["max_member_count"],
member_count=group_info["member_count"],
group_flag=1,
)
flag = await requests_manager.approve(bot, id_, "group")
else:
await friend_handle.send("同意群聊请求失败,未找到此id的请求..")
await group_handle.send("同意群聊请求失败,未找到此id的请求..")
logger.info("同意群聊请求失败,未找到此id的请求..", cmd, event.user_id)
else:
flag = await requests_manager.refused(bot, id_, "group")
if flag == 1:
await friend_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..")
await group_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..")
requests_manager.delete_request(id_, "group")
elif flag == 2:
await friend_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..")
await group_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..")
else:
await friend_handle.send(f"{cmd[:2]}群聊请求成功!")
await group_handle.send(f"{cmd[:2]}群聊请求成功!")
else:
await friend_handle.send("id必须为纯数字!")
await group_handle.send("id必须为纯数字!")
@cls_request.handle()
@@ -139,15 +144,15 @@ async def _():
for type_ in ["private", "group"]:
msg = await requests_manager.show(type_)
if msg:
_str += image(b64=msg)
_str += image(msg)
else:
_str += "没有任何好友请求.." if type_ == "private" else "没有任何群聊请求.."
if type_ == "private":
_str += '\n--------------------\n'
_str += "\n--------------------\n"
await cls_request.send(Message(_str))
@clear_request.handle()
async def _():
requests_manager.clear()
await cls_request.send("已清空所有好友/群聊请求..")
await clear_request.send("已清空所有好友/群聊请求..")
+26 -17
View File
@@ -1,13 +1,15 @@
import asyncio
import os
import time
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 configs.path_config import TEMP_PATH
from services.log import logger
from utils.manager import resources_manager
import asyncio
import time
import os
from utils.utils import scheduler
__zx_plugin_name__ = "清理临时数据 [Superuser]"
__plugin_usage__ = """
@@ -37,22 +39,29 @@ 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))
logger.info("清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
def _clear_data() -> float:
logger.debug("开始清理临时文件...")
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}")
dir_list = [dir_ for dir_ in resources_manager.get_temp_data_dir() if dir_.exists()]
for dir_ in dir_list:
logger.debug(f"尝试清理文件夹: {dir_.absolute()}", "清理临时数据")
dir_size = 0
for file in os.listdir(dir_):
file = dir_ / file
if file.is_file():
try:
if time.time() - os.path.getatime(file) > 10:
file_size = os.path.getsize(file)
file.unlink()
size += file_size
dir_size += file_size
logger.debug(f"移除临时文件: {file.absolute()}", "清理临时数据")
except Exception as e:
logger.error(f"清理临时数据错误,临时文件夹: {dir_.absolute()}...", "清理临时数据", e=e)
logger.debug("清理临时文件夹大小: {:.2f}MB".format(size / 1024 / 1024), "清理临时数据")
return float(size)
+71 -16
View File
@@ -1,37 +1,92 @@
from nonebot.adapters.onebot.v11 import Message
import asyncio
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from services.db_context import db
from nonebot.params import CommandArg
from tortoise import Tortoise
from services.db_context import TestSQL
from services.log import logger
from utils.message_builder import custom_forward_msg
__zx_plugin_name__ = "执行sql [Superuser]"
__plugin_usage__ = """
usage:
执行一段sql语句
指令:
exec [sql语句]
exec [sql语句] ([查询页数,19条/页])
查看所有表
""".strip()
__plugin_des__ = "执行一段sql语句"
__plugin_cmd__ = [
"exec [sql语句]",
]
__plugin_version__ = 0.1
__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 _(arg: Message = CommandArg()):
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
sql = arg.extract_plain_text().strip()
async with db.transaction():
if not sql:
await exec_.finish("未接受到sql语句")
db = Tortoise.get_connection("default")
# try:
# 判断是否为SELECT语句
if sql.lower().startswith("select"):
pass
# # 分割语句
try:
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}")
page = int(sql.split(" ")[-1]) - 1
sql_list = sql.split(" ")[:-1]
except ValueError:
page = 0
sql_list = sql.split(" ")
# 拼接语句
sql = " ".join(sql_list)
res = await db.execute_query_dict(sql)
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)
# 检查是私聊还是群聊
if isinstance(event, GroupMessageEvent):
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
)
else:
for msg in msg_list:
await exec_.send(msg)
await asyncio.sleep(0.2)
return
else:
await TestSQL.raw(sql)
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):
# 获取所有表
db = Tortoise.get_connection("default")
query = await db.execute_query_dict(
"select tablename from pg_tables where schemaname = 'public'"
)
msg = "数据库中的所有表名:\n"
for tablename in query:
msg += str(tablename["tablename"]) + "\n"
await tables.finish(msg)
+129 -89
View File
@@ -1,29 +1,39 @@
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GROUP, GroupMessageEvent, Message
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.adapters.onebot.v11.exception import ActionFailed
from nonebot.params import Command, CommandArg
from typing import Tuple
from nonebot import on_command, on_regex
from nonebot.adapters.onebot.v11 import (
GROUP,
Bot,
GroupMessageEvent,
Message,
MessageEvent,
)
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from configs.config import NICKNAME
from models.group_info import GroupInfo
from services.log import logger
from utils.depends import OneCommand
from utils.image_utils import text2image
from utils.manager import group_manager, plugins2settings_manager
from utils.message_builder import image
from utils.utils import is_number
__zx_plugin_name__ = "管理群操作 [Superuser]"
__plugin_usage__ = """
usage:
群权限 | 群白名单 | 退出群 操作
指令:
退群 [group_id]
退群,添加/删除群白名单,添加/删除群认证,当在群聊中这五个命令且没有指定群号时,默认指定当前群聊
指令:
退群 ?[group_id]
修改群权限 [group_id] [等级]
添加群白名单 *[group_id]
删除群白名单 *[group_id]
添加群认证 *[group_id]
删除群认证 *[group_id]
修改群权限 [等级]: 该命令仅在群聊时生效,默认修改当前群聊
添加群白名单 ?*[group_id]
删除群白名单 ?*[group_id]
添加群认证 ?*[group_id]
删除群认证 ?*[group_id]
查看群白名单
""".strip()
__plugin_des__ = "管理群操作"
@@ -47,7 +57,7 @@ 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,
@@ -67,47 +77,57 @@ group_auth = on_command(
@del_group.handle()
async def _(bot: Bot, arg: Message = CommandArg()):
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
group_id = arg.extract_plain_text().strip()
if not group_id and isinstance(event, GroupMessageEvent):
group_id = event.group_id
if group_id:
if is_number(group_id):
group_list = [x["group_id"] for x in await bot.get_group_list()]
group_id = int(group_id)
if group_id not in group_list:
logger.debug("群聊不存在", "退群", event.user_id, target=group_id)
await del_group.finish(f"{NICKNAME}未在该群聊中...")
try:
await bot.set_group_leave(group_id=int(group_id))
logger.info(f"退出群聊 {group_id} 成功")
await bot.set_group_leave(group_id=group_id)
logger.info(f"{NICKNAME}退出群聊成功", "退群", event.user_id, target=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))
group_manager.delete_group(group_id)
await GroupInfo.filter(group_id=group_id).delete()
except Exception as e:
logger.info(f"退出群聊 {group_id} 失败 e:{e}")
logger.error(f"退出群聊失败", "退群", event.user_id, target=group_id, e=e)
await del_group.send(f"退出群聊 {group_id} 失败", at_sender=True)
else:
await del_group.finish(f"请输入正确的群号", at_sender=True)
await del_group.send(f"请输入正确的群号", at_sender=True)
else:
await del_group.finish(f"请输入群号", at_sender=True)
await del_group.send(f"请输入群号", at_sender=True)
@add_group_level.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
msg = msg.split()
group_id = 0
level = 0
if isinstance(event, GroupMessageEvent) and len(msg) == 1:
msg = [event.group_id, msg[0]]
if not msg:
await add_group_level.finish("用法:修改群权限 [group] [level]")
msg = msg.split(" ")
await add_group_level.finish("缺失参数...")
if len(msg) < 2:
await add_group_level.finish("参数不完全..[group] [level]")
await add_group_level.finish("缺失参数...")
if is_number(msg[0]) and is_number(msg[1]):
group_id = msg[0]
group_id = int(msg[0])
level = int(msg[1])
else:
await add_group_level.finish("参数错误...group和level必须是数字..")
await add_group_level.finish("参数错误...群号和等级必须是数字..")
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}"
group_id=group_id, message=f"管理员修改了此群权限:{old_level} -> {level}"
)
logger.info(f"{event.user_id} 修改了 {group_id} 的权限:{level}")
logger.info(f"修改群权限:{level}", "修改群权限", event.user_id, target=group_id)
@my_group_level.handle()
@@ -116,89 +136,109 @@ async def _(event: GroupMessageEvent):
tmp = ""
data = plugins2settings_manager.get_data()
for module in data:
if data[module]["level"] > level:
plugin_name = data[module]["cmd"][0]
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}")
if not tmp:
await my_group_level.finish(f"当前群权限:{level}")
await my_group_level.finish(
f"当前群权限:{level}\n目前无法使用的功能:\n"
+ image(await text2image(tmp, padding=10, color="#f9f6f2"))
)
@what_up_group_level.handle()
async def _():
await what_up_group_level.finish(
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限"
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.超级管理员修改权限"
)
@manager_group_whitelist.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(
bot: Bot, event: MessageEvent, cmd: str = OneCommand(), arg: Message = CommandArg()
):
msg = arg.extract_plain_text().strip().split()
all_group = [
g["group_id"] for g in await bot.get_group_list()
]
if not msg and isinstance(event, GroupMessageEvent):
msg = [event.group_id]
if not msg:
await manager_group_whitelist.finish("请输入群号")
all_group = [g["group_id"] for g in await bot.get_group_list()]
error_group = []
group_list = []
for group in msg:
if is_number(group) and int(group) in all_group:
group_list.append(int(group))
for group_id in msg:
if is_number(group_id) and int(group_id) in all_group:
group_list.append(int(group_id))
else:
logger.debug(f"群号不合法或不存在", cmd, target=group_id)
error_group.append(group_id)
if group_list:
for group in group_list:
for group_id in group_list:
if cmd in ["添加群白名单"]:
group_manager.add_group_white_list(group)
group_manager.add_group_white_list(group_id)
else:
group_manager.delete_group_white_list(group)
group_manager.delete_group_white_list(group_id)
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}是否已加入这些群聊或重复添加/删除群白单名")
await manager_group_whitelist.send("已成功将 " + "\n".join(group_list) + " " + cmd)
group_manager.save()
if error_group:
await manager_group_whitelist.send("以下群聊不合法或不存在:\n" + "\n".join(error_group))
@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 = [str(g) for g in group_manager.get_group_white_list()]
if not group:
await show_group_whitelist.finish("没有任何群在群白名单...")
await show_group_whitelist.send("目前的群白名单:\n" + "\n".join(group))
@group_auth.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(
bot: Bot, event: MessageEvent, cmd: str = OneCommand(), arg: Message = CommandArg()
):
msg = arg.extract_plain_text().strip().split()
if isinstance(event, GroupMessageEvent) and not msg:
msg = [event.group_id]
if not msg:
await manager_group_whitelist.finish("请输入群号")
error_group = []
all_group = [g["group_id"] for g in await bot.get_group_list()]
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:
if is_number(group_id) and group_id in all_group:
if cmd[:2] == "添加":
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,
)
await GroupInfo.update_or_create(
group_id=group_info["group_id"],
defaults={
"group_flag": 1,
"group_name": group_info["group_name"],
"max_member_count": group_info["max_member_count"],
"member_count": group_info["member_count"],
},
)
except Exception as e:
await group_auth.send(f"添加群认证 {group_id} 发生错误!")
logger.error(f"添加群认证发生错误", cmd, target=group_id, e=e)
else:
await group_auth.send(f"已为 {group_id} {cmd[:2]}群认证..")
logger.info(f"添加群认证成功", cmd, target=group_id)
else:
if group := await GroupInfo.filter(group_id=group_id).first():
await group.update_or_create(
group_id=group_id, defaults={"group_flag": 0}
)
await group_auth.send(f"已删除 {group_id} 群认证..")
logger.info(f"删除群认证成功", cmd, target=group_id)
else:
await group_auth.send(f"未查找到群聊: {group_id}")
logger.info(f"未找到群聊", cmd, target=group_id)
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]}群认证..'
)
logger.debug(f"群号不合法或不存在", cmd, target=group_id)
error_group.append(str(group_id))
if error_group:
await manager_group_whitelist.send("以下群聊不合法或不存在:\n" + "\n".join(error_group))
+16 -24
View File
@@ -1,45 +1,37 @@
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.manager import (
group_manager,
plugins2block_manager,
plugins2cd_manager,
plugins2settings_manager,
)
from utils.utils import scheduler
__zx_plugin_name__ = "重载插件配置 [Superuser]"
__zx_plugin_name__ = "重载配置 [Superuser]"
__plugin_usage__ = """
usage:
重载插件配置
重载配置
plugins2settings,
plugins2cd
plugins2block
group_manager
指令:
重载插件配置
重载配置
""".strip()
__plugin_des__ = "重载插件配置"
__plugin_des__ = "重载配置"
__plugin_cmd__ = [
"重载插件配置",
"重载配置",
]
__plugin_version__ = 0.1
__plugin_version__ = 0.2
__plugin_author__ = "HibiKier"
__plugin_configs__ = {
"AUTO_RELOAD": {
"value": False,
"help": "自动重载配置文件",
"default_value": False
},
"AUTO_RELOAD_TIME": {
"value": 180,
"help": "控制自动重载配置文件时长",
"default_value": 180
}
"AUTO_RELOAD": {"value": False, "help": "自动重载配置文件", "default_value": False, "type": bool},
"AUTO_RELOAD_TIME": {"value": 180, "help": "控制自动重载配置文件时长", "default_value": 180, "type": int},
}
@@ -59,7 +51,7 @@ async def _():
@scheduler.scheduled_job(
'interval',
"interval",
seconds=Config.get_config("reload_setting", "AUTO_RELOAD_TIME", 180),
)
async def _():
@@ -1,12 +1,16 @@
from typing import List, Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.exception import ActionFailed
from nonebot.params import CommandArg
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.depends import AtList, OneCommand
from utils.message_builder import at
from nonebot.params import Command, CommandArg
from typing import Tuple
from utils.utils import is_number
__zx_plugin_name__ = "用户权限管理 [Superuser]"
__plugin_usage__ = """
@@ -16,12 +20,14 @@ usage:
添加权限 [at] [权限]
添加权限 [qq] [group_id] [权限]
删除权限 [at]
删除权限 [qq] [group_id]
""".strip()
__plugin_des__ = "增删改用户的权限"
__plugin_cmd__ = [
"添加权限 [at] [权限]",
"添加权限 [qq] [group_id] [权限]",
"删除权限 [at]",
"删除权限 [qq] [group_id]",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
@@ -40,21 +46,22 @@ super_cmd = on_command(
async def _(
bot: Bot,
event: MessageEvent,
cmd: Tuple[str, ...] = Command(),
cmd: str = OneCommand(),
arg: Message = CommandArg(),
at_list: List[int] = AtList(),
):
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
qq = None
try:
if qq:
qq = qq[0]
if cmd[0][:2] == "添加" and args and is_number(args[0]):
if at_list:
qq = at_list[0]
if cmd[:2] == "添加" and args and is_number(args[0]):
level = int(args[0])
else:
if cmd[0][:2] == "添加":
if cmd[:2] == "添加":
if (
len(args) > 2
and is_number(args[0])
@@ -69,33 +76,39 @@ async def _(
qq = int(args[0])
group_id = int(args[1])
flag = 1
level = -1 if cmd[0][:2] == "删除" else level
level = -1 if cmd[:2] == "删除" else level
if group_id == -1 or not level or not qq:
raise IndexError()
except IndexError:
await super_cmd.finish(__plugin_usage__)
if not qq:
await super_cmd.finish("未指定对象...")
try:
if cmd[0][:2] == "添加":
if await LevelUser.set_level(qq, group_id, level, 1):
result = f"添加管理成功, 权限: {level}"
else:
result = f"管理已存在, 更新权限: {level}"
if cmd[:2] == "添加":
await LevelUser.set_level(qq, group_id, level, 1)
result = f"设置权限成功, 权限: {level}"
else:
if await LevelUser.delete_level(qq, event.group_id):
if await LevelUser.delete_level(qq, 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}"
),
)
try:
await bot.send_group_msg(
group_id=group_id,
message=Message(
f"{at(qq)}管理员修改了你的权限"
f"\n--------\n你当前的权限等级:{level if level != -1 else 0}"
),
)
except ActionFailed:
pass
await super_cmd.send("修改成功")
logger.info(
f"修改权限: {level if level != -1 else 0}", cmd, event.user_id, group_id, qq
)
except Exception as e:
await super_cmd.send("执行指令失败!")
logger.error(f"执行指令失败 e:{e}")
logger.error(f"执行指令失败", cmd, event.user_id, group_id, qq, e=e)
@@ -1,58 +0,0 @@
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)
@@ -1,11 +1,11 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
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
from models.friend_user import FriendUser
from models.group_info import GroupInfo
from services.log import logger
__zx_plugin_name__ = "更新群/好友信息 [Superuser]"
__plugin_usage__ = """
@@ -32,38 +32,46 @@ update_friend_info = on_command(
@update_group_info.handle()
async def _():
bot = get_bot()
async def _(bot: Bot, event: MessageEvent):
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"],
):
try:
group_info = await bot.get_group_info(group_id=g)
await GroupInfo.update_or_create(
group_id=group_info["group_id"],
defaults={
"group_name": group_info["group_name"],
"max_member_count": group_info["max_member_count"],
"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]}")
logger.debug(
"群聊信息更新成功", "更新群信息", event.user_id, target=group_info["group_id"]
)
except Exception as e:
logger.error(f"更新群聊信息失败", "更新群信息", event.user_id, target=g, e=e)
await update_group_info.send(f"成功更新了 {len(gl)} 个群的信息")
logger.info(f"更新群聊信息完成,共更新了 {len(gl)} 个群的信息", "更新群信息", event.user_id)
@update_friend_info.handle()
async def _():
async def _(bot: Bot, event: MessageEvent):
num = 0
rst = ""
fl = await get_bot().get_friend_list()
error_list = []
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"]} 信息成功')
try:
await FriendUser.update_or_create(
user_id=f["user_id"], defaults={"nickname": f["nickname"]}
)
logger.debug(f"更新好友信息成功", "更新好友信息", event.user_id, target=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]}")
except Exception as e:
logger.error(f"更新好友信息失败", "更新好友信息", event.user_id, target=f["user_id"], e=e)
await update_friend_info.send(f"成功更新了 {num} 个好友的信息")
if error_list:
await update_friend_info.send(f"以下好友更新失败:\n" + "\n".join(error_list))
logger.info(f"更新好友信息完成,共更新了 {num} 个群的信息", "更新好友信息", event.user_id)
+9 -12
View File
@@ -1,18 +1,16 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
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 .data_source import SUPERUSER_HELP_IMAGE, create_help_image
__zx_plugin_name__ = "超级用户帮助 [Superuser]"
__zx_plugin_name__ = '超级用户帮助 [Superuser]'
superuser_help_image = IMAGE_PATH / 'superuser_help.png'
if superuser_help_image.exists():
superuser_help_image.unlink()
if SUPERUSER_HELP_IMAGE.exists():
SUPERUSER_HELP_IMAGE.unlink()
super_help = on_command(
"超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True
@@ -21,7 +19,6 @@ super_help = on_command(
@super_help.handle()
async def _():
if not superuser_help_image.exists():
if not SUPERUSER_HELP_IMAGE.exists():
await create_help_image()
x = image(superuser_help_image)
await super_help.finish(x)
await super_help.finish(image(SUPERUSER_HELP_IMAGE))
+70 -65
View File
@@ -1,79 +1,84 @@
from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.utils import get_matchers
from nonebot.adapters.onebot.v11 import Bot
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 = IMAGE_PATH / "background" / "0.png"
superuser_help_image = 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 = BuildImage(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.plugin_name)
_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.plugin_name}: {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 = BuildImage(width, height, font_size=24)
_background = BuildImage(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)} 条超级用户命令")
+2 -3
View File
@@ -1,6 +1,6 @@
from nonebot import on_command
from utils.message_builder import image
from utils.message_builder import image
__zx_plugin_name__ = "更新信息"
__plugin_usage__ = """
@@ -26,8 +26,7 @@ update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, b
@update_info.handle()
async def _():
img = image("update_info.png")
if img:
if img := image("update_info.png"):
await update_info.finish(image("update_info.png"))
else:
await update_info.finish("目前没有更新信息哦")
+1
View File
@@ -12,6 +12,7 @@ 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")
+15 -3
View File
@@ -1,16 +1,27 @@
from typing import Optional
import platform
from pathlib import Path
from typing import Optional
from .utils import ConfigsManager
if platform.system() == "Linux":
import os
hostip = (
os.popen("cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }'")
.read()
.replace("\n", "")
)
# 回复消息名称
NICKNAME: str = "小真寻"
# 数据库(必要)
# 如果填写了bind就不需要再填写后面的字段了#)
# 示例:"bind": "postgresql://user:password@127.0.0.1:5432/database"
# 示例:"bind": "postgres://user:password@127.0.0.1:5432/database"
bind: str = "" # 数据库连接链接
sql_name: str = "postgresql"
sql_name: str = "postgres"
user: str = "" # 数据用户名
password: str = "" # 数据库密码
address: str = "" # 数据库地址
@@ -18,6 +29,7 @@ port: str = "" # 数据库端口
database: str = "" # 数据库名称
# 代理,例如 "http://127.0.0.1:7890"
# 如果是WLS 可以 f"http://{hostip}:7890" 使用寄主机的代理
SYSTEM_PROXY: Optional[str] = None # 全局代理
+2
View File
@@ -15,6 +15,8 @@ FONT_PATH = Path() / "resources" / "font"
DATA_PATH = Path() / "data"
# 临时数据路径
TEMP_PATH = Path() / "resources" / "temp"
# 网页模板路径
TEMPLATE_PATH = Path() / "resources" / "template"
def load_path():
+208 -90
View File
@@ -1,7 +1,52 @@
from typing import Optional, Any, Union
import copy
from pathlib import Path
from ruamel.yaml import YAML
from typing import Any, Callable, Dict, Optional, Type, Union
import cattrs
from pydantic import BaseModel
from ruamel import yaml
from ruamel.yaml import YAML
from ruamel.yaml.scanner import ScannerError
from services.log import logger
class Config(BaseModel):
"""
配置项
"""
value: Any
"""配置项值"""
name: Optional[str]
"""插件名称"""
help: Optional[str]
"""配置注解"""
default_value: Optional[Any] = None
"""默认值"""
level_module: Optional[str]
"""受权限模块"""
type: Any = None
"""参数类型"""
arg_parser: Optional[Callable] = None
"""参数解析"""
class ConfigGroup(BaseModel):
"""
配置组
"""
module: str
"""模块名"""
configs: Dict[str, Config] = {}
"""配置项列表"""
class NoSuchConfig(Exception):
pass
class ConfigsManager:
@@ -10,20 +55,25 @@ class ConfigsManager:
"""
def __init__(self, file: Path):
self._data: dict = {}
self._data: Dict[str, ConfigGroup] = {}
self._simple_data: dict = {}
self._admin_level_data = []
self._simple_file = Path() / "configs" / "config.yaml"
_yaml = YAML()
if file:
file.parent.mkdir(exist_ok=True, parents=True)
self.file = file
_yaml = YAML()
if file.exists():
with open(file, "r", encoding="utf8") as f:
self._data = _yaml.load(f)
if self._simple_file.exists():
self.load_data()
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,
@@ -33,7 +83,9 @@ class ConfigsManager:
*,
name: Optional[str] = None,
help_: Optional[str] = None,
default_value: Optional[str] = None,
default_value: Optional[Any] = None,
type: Optional[Type] = None,
arg_parser: Optional[Callable] = None,
_override: bool = False,
):
"""
@@ -44,115 +96,138 @@ class ConfigsManager:
:param name: 插件名称
:param help_: 配置注解
:param default_value: 默认值
:param _override: 覆盖前值
:param _override: 强制覆盖值
"""
if (
not (module in self._data.keys() and self._data[module].get(key))
or _override
):
if not module or not key:
raise ValueError("add_plugin_config: module和key不能为为空")
if module in self._data and (config := self._data[module].configs.get(key)):
config.help = help_
config.arg_parser = arg_parser
config.type = type
if _override:
config.value = value
config.name = name
config.default_value = default_value
else:
_module = None
if ":" in module:
module = module.split(":")
_module = module[-1]
module = module[0]
module_split = module.split(":")
if len(module_split) < 2:
raise ValueError(f"module: {module} 填写错误")
_module = module_split[-1]
module = module_split[0]
if "[LEVEL]" in key and _module:
key = key.replace("[LEVEL]", "").strip()
self._admin_level_data.append((_module, value))
if self._data.get(module) is None:
self._data[module] = {}
key = key.upper()
self._data[module][key] = {
"value": value,
"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,
}
if not self._data.get(module):
self._data[module] = ConfigGroup(module=module)
self._data[module].configs[key] = Config(
value=value,
name=name,
help=help_,
default_value=default_value,
level_module=_module,
type=type,
)
def remove_plugin_config(self, module: str):
"""
为插件删除一个配置
:param module: 模块名
"""
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 and self._data[module][key] != value:
self._data[module][key]["value"] = value
if module in self._data:
if (
self._data[module].configs.get(key)
and self._data[module].configs[key] != value
):
self._data[module].configs[key].value = value
self._simple_data[module][key] = value
self.save()
if auto_save:
self.save(save_simple_data=save_simple_data)
def set_help(self, module: str, key: str, help_: str):
"""
设置配置注释
:param module: 模块名
:param key: 配置名称
:param help_: 注释文本
"""
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):
"""
设置配置默认值
:param module: 模块名
:param key: 配置名称
:param value: 值
"""
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, default: Optional[Any] = None) -> Optional[Any]:
def get_config(
self, module: str, key: str, default: Optional[Any] = None
) -> Optional[Any]:
"""
获取指定配置值
:param module: 模块名
:param key: 配置名称
:param default: 没有key值内容的默认返回值
"""
logger.debug(
f"尝试获取配置 MODULE: [<u><y>{module}</y></u>] | KEY: [<u><y>{key}</y></u>]"
)
key = key.upper()
value = None
if module in self._data.keys():
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
config = self._data[module].configs.get(key)
if not config:
config = self._data[module].configs.get(f"{key} [LEVEL]")
if not config:
raise NoSuchConfig(f"未查询到配置项 MODULE: [ {module} ] | KEY: [ {key} ]")
if config.arg_parser:
value = config.arg_parser(value or config.default_value)
else:
try:
if config.value is not None:
value = (
cattrs.structure(config.value, config.type)
if config.type
else config.value
)
else:
if config.default_value is not None:
value = (
cattrs.structure(config.default_value, config.type)
if config.type
else config.default_value
)
except Exception as e:
logger.warning(
f"配置项类型转换 MODULE: [<u><y>{module}</y></u>] | KEY: [<u><y>{key}</y></u>]",
e=e,
)
value = config.value or config.default_value
if value is None:
value = default
logger.debug(
f"获取配置 MODULE: [<u><y>{module}</y></u>] | KEY: [<u><y>{key}</y></u>] -> [<u><c>{value}</c></u>]"
)
return value
def get_level2module(self, module: str, key: str) -> Optional[str]:
"""
获取指定key所绑定的module,一般为权限等级
获取指定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")
if config := self._data[module].configs.get(key):
return config.level_module
def get(self, key: str):
def get(self, key: str) -> Optional[ConfigGroup]:
"""
获取插件配置数据
:param key: 名称
"""
if key in self._data.keys():
return self._data[key]
return self._data.get(key)
def save(self, path: Union[str, Path] = None, save_simple_data: bool = False):
def save(
self, path: Optional[Union[str, Path]] = None, save_simple_data: bool = False
):
"""
保存数据
:param path: 路径
@@ -161,12 +236,23 @@ class ConfigsManager:
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
self._simple_data,
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
path = path if path else self.file
path = path or self.file
data = {}
for module in self._data:
data[module] = {}
for config in self._data[module].configs:
value = self._data[module].configs[config].dict()
del value["type"]
data[module][config] = value
with open(path, "w", encoding="utf8") as f:
yaml.dump(
self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def reload(self):
@@ -174,21 +260,53 @@ class ConfigsManager:
重新加载配置文件
"""
_yaml = YAML()
temp_file = Path() / "configs" / "config.yaml"
if temp_file.exists():
with open(temp_file, "r", encoding="utf8") as f:
temp = _yaml.load(f)
for key in temp.keys():
for k in temp[key].keys():
self._data[key][k]["value"] = temp[key][k]
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].configs[k].value = self._simple_data[key][k]
self.save()
def load_data(self):
"""
加载数据
Raises:
ValueError: _description_
"""
if self.file.exists():
_yaml = YAML()
with open(self.file, "r", encoding="utf8") as f:
temp_data = _yaml.load(f)
if not temp_data:
self.file.unlink()
raise ValueError(
"配置文件为空!\n"
"***********************************************************\n"
"****** 配置文件 plugins2config.yaml 为空,已删除,请重启 ******\n"
"***********************************************************"
)
count = 0
for module in temp_data:
config_group = ConfigGroup(module=module)
for config in temp_data[module]:
config_group.configs[config] = Config(**temp_data[module][config])
count += 1
self._data[module] = config_group
logger.info(
f"加载配置完成,共加载 <u><y>{len(temp_data)}</y></u> 个配置组及对应 <u><y>{count}</y></u> 个配置项"
)
def get_admin_level_data(self):
"""
获取管理插件等级
"""
return self._admin_level_data
def get_data(self) -> Dict[str, ConfigGroup]:
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
+66
View File
@@ -0,0 +1,66 @@
{
"抽卡":{
"buff": ["欧气满满,十连出金","出金不歪"],
"debuff": ["武器大师","保底出金","金色会是痛苦大剑"]
},
"刷世界boss":{
"buff": ["双攻双爆角斗士"],
"debuff": ["只有保底材料","贪生怕死角斗士"]
},
"刷风本":{
"buff": ["会有极品猎人套","会掉真正的少女心","治疗加成少女头"],
"debuff": ["勇往直前少女心","少女飘摇的杀意","少女暴怒的容颜"]
},
"刷火本":{
"buff": ["魔女帽子火伤杯","暴伤魔女帽!","火伤魔女心!"],
"debuff": ["幡 然 醒 悟","这么阴间的地方真的会有魔女套吗?","不务正业火魔女","会匹配到3个卢姥爷"]
},
"刷岩本":{
"buff": ["悠久的磐岩伴你左右","岩神的庇护常在"],
"debuff": ["防御流星杯,你值得拥有"]
},
"刷宗室":{
"buff": ["物理伤害骑士道,元素精通宗室套"],
"debuff": ["贪生怕死骑士道,物理伤害宗室杯"]
},
"刷冰本":{
"buff": ["双暴词条概率up"],
"debuff": ["防御力船帽,无人可及"]
},
"刷雷本":{
"buff": ["愿雷鸟伴你左右"],
"debuff": ["来表演一个只掉平雷套的绝活","风神忽悠雷凶兆"]
},
"锄大地":{
"buff": ["会掉一大堆紫色材料"],
"debuff": ["深渊法师爱你哟","会被冰水法控到死"]
},
"挖矿":{
"buff": ["开矿出双材料"],
"debuff": ["去别人世界会被拒"]
},
"刷天赋本":{
"buff": ["金色!我看到了金色的书!"],
"debuff": ["2蓝2绿不会变"]
},
"刷突破材料":{
"buff": ["金色!我看到了金色的材料!"],
"debuff": ["2蓝2绿不会变"]
},
"升级圣遗物":{
"buff": ["稀有词条跳跳跳","会双爆拉满"],
"debuff": ["女 仆 狂 喜","无中生有防御力","生命拉满","完美避开双爆"]
},
"打风魔龙":{
"buff": ["看我一箭一个风魔鸡","今天特瓦林可以给想要的突破材料","5金加原胚!"],
"debuff": ["会不小心掉下平台","不小心被地板烫死了"]
},
"打狼王":{
"buff": ["今天安德琉斯的心情不错,可以py一下","5金加原胚!"],
"debuff": ["狼尾巴*1"]
},
"打公子":{
"buff": ["今天可以和公子py想要的突破材料","5金加原胚!"],
"debuff": ["要角没有!要命一条!"]
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 772 KiB

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.

Before

Width:  |  Height:  |  Size: 694 KiB

After

Width:  |  Height:  |  Size: 326 KiB

+96 -153
View File
@@ -1,40 +1,48 @@
from services.db_context import db
from typing import Dict
from typing import Optional, List
from services.log import logger
from tortoise import fields
from services.db_context import Model
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)
group_id = db.Column(db.BigInteger(), nullable=False)
gold = db.Column(db.Integer(), default=100)
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={}) # 新道具字段
class BagUser(Model):
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "group_id", unique=True)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
gold = fields.IntField(default=100)
"""金币数量"""
spend_total_gold = fields.IntField(default=0)
"""花费金币总数"""
get_total_gold = fields.IntField(default=0)
"""获取金币总数"""
get_today_gold = fields.IntField(default=0)
"""今日获取金币"""
spend_today_gold = fields.IntField(default=0)
"""今日获取金币"""
property: Dict[str, int] = fields.JSONField(default={})
"""道具"""
class Meta:
table = "bag_users"
table_description = "用户道具数据表"
unique_together = ("user_qq", "group_id")
@classmethod
async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
"""
说明:
说明:
获取金币概况
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
"""
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,
group_id=group_id,
)
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
return (
f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}"
f"\n今日收益:{user.get_today_gold - user.spend_today_gold}"
@@ -44,183 +52,118 @@ class BagUser(db.Model):
@classmethod
async def get_gold(cls, user_qq: int, group_id: int) -> int:
"""
说明:
说明:
获取当前金币
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
"""
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,
group_id=group_id,
)
return 100
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
return user.gold
@classmethod
async def get_property(cls, user_qq: int, group_id: int) -> Dict[str, int]:
async def get_property(
cls, user_qq: int, group_id: int, only_active: bool = False
) -> Dict[str, int]:
"""
说明:
说明:
获取当前道具
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param only_active: 仅仅获取主动使用的道具
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first()
if user:
return user.property
else:
await cls.create(
user_qq=user_qq,
group_id=group_id,
)
return {}
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
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 if x in name_list]:
data[key] = user.property[key]
return data
return user.property
@classmethod
async def add_gold(cls, user_qq: int, group_id: int, num: int):
"""
说明:
说明:
增加金币
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param num: 金币数量
"""
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:
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,
)
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
user.gold = user.gold + num
user.get_total_gold = user.get_total_gold + num
user.get_today_gold = user.get_today_gold + num
await user.save(update_fields=["gold", "get_today_gold", "get_total_gold"])
@classmethod
async def spend_gold(cls, user_qq: int, group_id: int, num: int):
"""
说明:
说明:
花费金币
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param num: 金币数量
"""
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:
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,
)
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
user.gold = user.gold - num
user.spend_total_gold = user.spend_total_gold + num
user.spend_today_gold = user.spend_today_gold + num
await user.save(update_fields=["gold", "spend_total_gold", "spend_today_gold"])
@classmethod
async def add_property(cls, user_qq: int, group_id: int, name: str):
async def add_property(cls, user_qq: int, group_id: int, name: str, num: int = 1):
"""
说明:
说明:
增加道具
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param name: 道具名称
:param num: 道具数量
"""
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:
p = user.property
if p.get(name) is None:
p[name] = 1
else:
p[name] += 1
await user.update(property=p).apply()
else:
await cls.create(user_qq=user_qq, group_id=group_id, property={name: 1})
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
property_ = user.property
if property_.get(name) is None:
property_[name] = 0
property_[name] += num
user.property = property_
await user.save(update_fields=["property"])
@classmethod
async def delete_property(
cls, user_qq: int, group_id: int, name: str, num: int = 1
) -> bool:
"""
说明:
说明:
使用/删除 道具
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param name: 道具名称
:param num: 使用个数
"""
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:
property_ = user.property
if name in property_:
if property_.get(name) == num:
del property_[name]
else:
property_[name] -= num
await user.update(property=property_).apply()
return True
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
property_ = user.property
if name in property_:
if (n := property_.get(name, 0)) < num:
return False
if n == num:
del property_[name]
else:
property_[name] -= num
await user.save(update_fields=["property"])
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.group_id == group_id)).gino.all()
return query
async def _run_script(cls):
await cls.raw("ALTER TABLE bag_users DROP props;")
"""删除 props 字段"""
+70 -65
View File
@@ -1,119 +1,124 @@
from services.db_context import db
import time
from typing import Union
from tortoise import fields
from services.db_context import Model
from services.log import logger
class BanUser(db.Model):
__tablename__ = "ban_users"
class BanUser(Model):
user_qq = db.Column(db.BigInteger(), nullable=False, primary_key=True)
ban_level = db.Column(db.Integer(), nullable=False)
ban_time = db.Column(db.BigInteger())
duration = db.Column(db.BigInteger())
user_qq = fields.IntField(pk=True)
"""用户id"""
ban_level = fields.IntField()
"""使用ban命令的用户等级"""
ban_time = fields.BigIntField()
"""ban开始的时间"""
duration = fields.BigIntField()
"""ban时长"""
_idx1 = db.Index("ban_group_users_idx1", "user_qq", unique=True)
class Meta:
table = "ban_users"
table_description = ".ban/b了 封禁人员数据表"
@classmethod
async def check_ban_level(cls, user_qq: int, level: int) -> bool:
"""
说明:
说明:
检测ban掉目标的用户与unban用户的权限等级大小
参数:
参数:
:param user_qq: unban用户的qq号
:param level: ban掉目标用户的权限等级
"""
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
if not user:
return False
if user.ban_level > level:
return True
user = await cls.filter(user_qq=user_qq).first()
if user:
logger.debug(
f"检测用户被ban等级,user_level: {user.ban_level},level: {level}",
target=user_qq,
)
return bool(user and user.ban_level > level)
return False
@classmethod
async def check_ban_time(cls, user_qq: int) -> str:
async def check_ban_time(cls, user_qq: int) -> Union[str, int]:
"""
说明:
说明:
检测用户被ban时长
参数:
参数:
:param user_qq: qq号
"""
query = cls.query.where((cls.user_qq == user_qq))
user = await query.gino.first()
if not user:
return ""
if time.time() - (user.ban_time + user.duration) > 0 and user.duration != -1:
return ""
if user.duration == -1:
return "∞"
return time.time() - user.ban_time - user.duration
logger.debug(f"获取用户ban时长", target=user_qq)
if user := await cls.filter(user_qq=user_qq).first():
if (
time.time() - (user.ban_time + user.duration) > 0
and user.duration != -1
):
return ""
if user.duration == -1:
return "∞"
return int(time.time() - user.ban_time - user.duration)
return ""
@classmethod
async def is_ban(cls, user_qq: int) -> bool:
"""
说明:
说明:
判断用户是否被ban
参数:
参数:
:param user_qq: qq号
"""
logger.debug(f"检测是否被ban", target=user_qq)
if await cls.check_ban_time(user_qq):
return True
else:
await cls.unban(user_qq)
return False
return False
@classmethod
async def is_super_ban(cls, user_qq: int) -> bool:
"""
说明:
判断用户是否被ban
参数:
说明:
判断用户是否被超级用户ban / b了
参数:
:param user_qq: qq号
"""
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
if not user:
return False
if user.ban_level == 10:
return True
logger.debug(f"检测是否被超级用户权限封禁", target=user_qq)
if user := await cls.filter(user_qq=user_qq).first():
if user.ban_level == 10:
return True
return False
@classmethod
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
async def ban(cls, user_qq: int, ban_level: int, duration: int):
"""
说明:
说明:
ban掉目标用户
参数:
参数:
:param user_qq: 目标用户qq号
:param ban_level: 使用ban命令用户的权限
:param duration: ban时长,秒
"""
query = cls.query.where((cls.user_qq == user_qq))
query = query.with_for_update()
user = await query.gino.first()
if not await cls.check_ban_time(user_qq):
logger.debug(f"封禁用户,等级:{ban_level},时长: {duration}", target=user_qq)
if await cls.filter(user_qq=user_qq).first():
await cls.unban(user_qq)
user = None
if user is None:
await cls.create(
user_qq=user_qq,
ban_level=ban_level,
ban_time=time.time(),
duration=duration,
)
return True
else:
return False
await cls.create(
user_qq=user_qq,
ban_level=ban_level,
ban_time=time.time(),
duration=duration,
)
@classmethod
async def unban(cls, user_qq: int) -> bool:
"""
说明:
说明:
unban用户
参数:
参数:
:param user_qq: qq号
"""
query = cls.query.where((cls.user_qq == user_qq))
query = query.with_for_update()
user = await query.gino.first()
if user is None:
return False
else:
await cls.delete.where((cls.user_qq == user_qq)).gino.status()
if user := await cls.filter(user_qq=user_qq).first():
logger.debug("解除封禁", target=user_qq)
await user.delete()
return True
return False
+63 -160
View File
@@ -1,80 +1,30 @@
from datetime import datetime, timedelta
from typing import List, Literal, Optional, Tuple, Union
from typing import Any, List, Literal, Optional, Tuple, Union
from services.db_context import db
from tortoise import fields
from tortoise.functions import Count
from services.db_context import Model
class ChatHistory(db.Model):
__tablename__ = "chat_history"
class ChatHistory(Model):
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())
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField(null=True)
"""群聊id"""
text = fields.TextField(null=True)
"""文本内容"""
plain_text = fields.TextField(null=True)
"""纯文本"""
create_time = fields.DatetimeField(auto_now_add=True)
"""创建时间"""
@classmethod
async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str):
await cls.create(
user_qq=user_qq, group_id=group_id, text=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
class Meta:
table = "chat_history"
table_description = "聊天记录数据表"
@classmethod
async def get_group_msg_rank(
@@ -83,132 +33,85 @@ class ChatHistory(db.Model):
limit: int = 10,
order: str = "DESC",
date_scope: Optional[Tuple[datetime, datetime]] = None,
) -> Optional[Tuple[int, int]]:
) -> List["ChatHistory"]:
"""
说明:
说明:
获取排行数据
参数:
参数:
: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} "
o = "-" if order == "DESC" else ""
query = cls.filter(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}"
print(sql)
return await db.all(db.text(sql))
query = query.filter(create_time__range=date_scope)
return list(
await query.annotate(count=Count("user_qq"))
.order_by(o + "count")
.group_by("user_qq")
.limit(limit)
.values_list("user_qq", "count")
) # type: ignore
@classmethod
async def get_group_first_msg_datetime(cls, gid: int) -> Optional[datetime]:
async def get_group_first_msg_datetime(cls, group_id: int) -> Optional[datetime]:
"""
说明:
说明:
获取群第一条记录消息时间
参数:
:param gid:
参数:
:param group_id: 群聊id
"""
if (
msg := await cls.query.where(cls.group_id == gid)
.order_by(cls.create_time)
.gino.first()
message := await cls.filter(group_id=group_id)
.order_by("create_time")
.first()
):
return msg.create_time
return None
return message.create_time
@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(
async def get_message(
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,
):
) -> List["ChatHistory"]:
"""
说明:
说明:
获取消息查询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)
query = cls.filter(user_qq=uid)
if msg_type == "private":
query = query.where(cls.group_id == None)
query = query.filter(group_id__isnull=True)
elif msg_type == "group":
query = query.where(cls.group_id != None)
query = query.filter(group_id__not_isnull=True)
else:
query = query.where(cls.group_id == gid)
query = cls.filter(group_id=gid)
if uid:
query = query.where(cls.user_qq == uid)
query = query.filter(user_qq=uid)
if days:
if isinstance(days, int):
query = query.where(
cls.create_time >= datetime.now() - timedelta(days=days)
query = query.filter(
create_time__gte=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
query = query.filter(create_time__range=days)
return await query.all() # type: ignore
@classmethod
async def _run_script(cls):
return [
"alter table chat_history alter group_id drop not null;", # 允许 group_id 为空
"alter table chat_history alter text drop not null;", # 允许 text 为空
"alter table chat_history alter plain_text drop not null;", # 允许 plain_text 为空
]
+28 -83
View File
@@ -1,115 +1,60 @@
from services.db_context import db
from tortoise import fields
from configs.config import Config
from services.db_context import Model
class FriendUser(db.Model):
__tablename__ = "friend_users"
class FriendUser(Model):
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.BigInteger(), nullable=False)
user_name = db.Column(db.Unicode(), nullable=False, default="")
nickname = db.Column(db.Unicode())
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_id = fields.BigIntField(unique=True)
"""用户id"""
user_name = fields.CharField(max_length=255, default="")
"""用户名称"""
nickname = fields.CharField(max_length=255, null=True)
"""私聊下自定义昵称"""
_idx1 = db.Index("friend_users_idx1", "user_id", unique=True)
class Meta:
table = "friend_users"
table_description = "好友信息数据表"
@classmethod
async def get_user_name(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 := await cls.get_or_none(user_id=user_id):
return user.user_name
else:
return ""
return ""
@classmethod
async def add_friend_info(cls, user_id: int, user_name: str) -> bool:
async def get_user_nickname(cls, user_id: int) -> str:
"""
说明:
添加好友信息
参数:
:param user_id: qq号
:param user_name: 用户名称
"""
try:
query = cls.query.where(cls.user_id == user_id)
user = await query.with_for_update().gino.first()
if not user:
await cls.create(
user_id=user_id,
user_name=user_name,
)
else:
await user.update(
user_name=user_name,
).apply()
return True
except Exception:
return False
@classmethod
async def delete_friend_info(cls, user_id: int) -> bool:
"""
说明:
删除好友信息
参数:
:param user_id: qq号
"""
try:
query = cls.query.where(cls.user_id == user_id)
user = await query.with_for_update().gino.first()
if user:
await user.delete()
return True
except Exception:
return False
@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 := await cls.get_or_none(user_id=user_id):
if user.nickname:
_tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
if black_word := Config.get_config("nickname", "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:
async def set_user_nickname(cls, user_id: int, nickname: str):
"""
说明:
说明:
设置用户昵称
参数:
参数:
:param user_id: qq号
:param nickname: 昵称
"""
try:
query = cls.query.where(cls.user_id == user_id)
user = await query.with_for_update().gino.first()
if not user:
await cls.create(
user_id=user_id,
nickname=nickname,
)
else:
await user.update(
nickname=nickname,
).apply()
return True
except Exception:
return False
await cls.update_or_create(user_id=user_id, defaults={"nickname": nickname})
+136 -73
View File
@@ -1,19 +1,37 @@
from services.db_context import db
from typing import Optional, List
from services.log import logger
from typing import Dict, List, Optional, Tuple
from tortoise import fields
from services.db_context import Model
class GoodsInfo(db.Model):
class GoodsInfo(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) # 限时
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
goods_name = fields.CharField(255, unique=True)
"""商品名称"""
goods_price = fields.IntField()
"""价格"""
goods_description = fields.TextField()
"""描述"""
goods_discount = fields.FloatField(default=1)
"""折扣"""
goods_limit_time = fields.BigIntField(default=0)
"""限时"""
daily_limit = fields.IntField(default=0)
"""每日限购"""
daily_purchase_limit: Dict[str, Dict[str, int]] = fields.JSONField(default={})
"""用户限购记录"""
is_passive = fields.BooleanField(default=False)
"""是否为被动道具"""
icon = fields.TextField(null=True)
"""图标路径"""
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
class Meta:
table = "goods_info"
table_description = "商品数据表"
@classmethod
async def add_goods(
@@ -23,48 +41,47 @@ class GoodsInfo(db.Model):
goods_description: str,
goods_discount: float = 1,
goods_limit_time: int = 0,
) -> bool:
daily_limit: int = 0,
is_passive: bool = False,
icon: Optional[str] = None,
):
"""
说明:
说明:
添加商品
参数:
参数:
: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,
)
return True
except Exception as e:
logger.error(f"GoodsInfo add_goods 发生错误 {type(e)}:{e}")
return False
if not await cls.filter(goods_name=goods_name).first():
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,
)
@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
if goods := await cls.get_or_none(goods_name=goods_name):
await goods.delete()
return True
return False
@classmethod
async def update_goods(
@@ -74,56 +91,50 @@ class GoodsInfo(db.Model):
goods_description: Optional[str] = None,
goods_discount: Optional[float] = None,
goods_limit_time: Optional[int] = None,
) -> bool:
daily_limit: Optional[int] = None,
is_passive: Optional[bool] = None,
icon: Optional[str] = None,
):
"""
说明:
说明:
更新商品信息
参数:
参数:
: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 goods := await cls.get_or_none(goods_name=goods_name):
await cls.update_or_create(
goods_name=goods_name,
defaults={
"goods_price": goods_price or goods.goods_price,
"goods_description": goods_description or goods.goods_description,
"goods_discount": goods_discount or goods.goods_discount,
"goods_limit_time": goods_limit_time
if goods_limit_time is not None
else goods.goods_limit_time,
"daily_limit": daily_limit
if daily_limit is not None
else goods.daily_limit,
"is_passive": is_passive
if is_passive is not None
else goods.is_passive,
"icon": icon or goods.icon,
},
)
if not query:
return False
if goods_price:
await query.update(goods_price=goods_price).apply()
if goods_description:
await query.update(goods_description=goods_description).apply()
if goods_discount:
await query.update(goods_discount=goods_discount).apply()
if goods_limit_time:
await query.update(goods_limit_time=goods_limit_time).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: 商品名称
"""
query = await cls.query.where(cls.goods_name == goods_name).gino.first()
return query
@classmethod
async def get_all_goods(cls) -> List["GoodsInfo"]:
"""
说明:
说明:
获得全部有序商品对象
"""
query = await cls.query.gino.all()
query = await cls.all()
id_lst = [x.id for x in query]
goods_lst = []
for _ in range(len(query)):
@@ -131,3 +142,55 @@ class GoodsInfo(db.Model):
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.save(update_fields=["daily_purchase_limit"])
@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
+17 -104
View File
@@ -1,111 +1,24 @@
from services.db_context import db
from services.log import logger
from typing import List, Optional
from tortoise import fields
class GroupInfo(db.Model):
__tablename__ = "group_info"
from services.db_context import Model
from services.log import logger
group_id = db.Column(db.BigInteger(), nullable=False, primary_key=True)
group_name = db.Column(db.Unicode(), nullable=False, default="")
max_member_count = db.Column(db.Integer(), nullable=False, default=0)
member_count = db.Column(db.Integer(), nullable=False, default=0)
group_flag = db.Column(db.Integer(), nullable=False, default=0)
_idx1 = db.Index("group_info_idx1", "group_id", unique=True)
class GroupInfo(Model):
@classmethod
async def get_group_info(cls, group_id: int) -> "GroupInfo":
"""
说明:
获取群信息
参数:
:param group_id: 群号
"""
query = cls.query.where(cls.group_id == group_id)
return await query.gino.first()
group_id = fields.BigIntField(pk=True)
"""群聊id"""
group_name = fields.TextField(default="")
"""群聊名称"""
max_member_count = fields.IntField(default=0)
"""最大人数"""
member_count = fields.IntField(default=0)
"""当前人数"""
group_flag: int = fields.IntField(default=0)
"""群认证标记"""
@classmethod
async def add_group_info(
cls,
group_id: int,
group_name: str,
max_member_count: int,
member_count: int,
group_flag: Optional[int] = None,
) -> bool:
"""
说明:
添加群信息
参数:
:param group_id: 群号
:param group_name: 群名称
:param max_member_count: 群员最大数量
:param member_count: 群员数量
:param group_flag: 群认证,0为未认证,1为认证
"""
try:
group = (
await cls.query.where(cls.group_id == group_id)
.with_for_update()
.gino.first()
)
if group:
await group.update(
group_name=group_name,
max_member_count=max_member_count,
member_count=member_count,
).apply()
if group_flag is not None:
await group.update(group_flag=group_flag).apply()
else:
await cls.create(
group_id=group_id,
group_name=group_name,
max_member_count=max_member_count,
member_count=member_count,
group_flag=group_flag,
)
return True
except Exception as e:
logger.info(f"GroupInfo 调用 add_group_info 发生错误 {type(e)}:{e}")
return False
@classmethod
async def delete_group_info(cls, group_id: int):
"""
说明:
删除群信息
参数:
:param group_id: 群号
"""
await cls.delete.where(cls.group_id == group_id).gino.status()
@classmethod
async def get_all_group(cls) -> List["GroupInfo"]:
"""
说明:
获取所有群对象
"""
query = await cls.query.gino.all()
return query
@classmethod
async def set_group_flag(cls, group_id: int, group_flag: int) -> bool:
"""
设置群认证
:param group_id: 群号
:param group_flag: 群认证,0为未认证,1为认证
"""
group = (
await cls.query.where(cls.group_id == group_id)
.with_for_update()
.gino.first()
)
if group:
if group.group_flag != group_flag:
await group.update(
group_flag=group_flag,
).apply()
return True
return False
class Meta:
table = "group_info"
table_description = "群聊信息表"
+71 -149
View File
@@ -1,195 +1,117 @@
from datetime import datetime
from typing import List, Optional, Set
from tortoise import fields
from configs.config import Config
from services.db_context import db
from typing import List, Optional
from services.db_context import Model
from services.log import logger
class GroupInfoUser(db.Model):
__tablename__ = "group_info_users"
class GroupInfoUser(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)
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())
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
user_name = fields.CharField(255, default="")
"""用户昵称"""
group_id = fields.BigIntField()
"""群聊id"""
user_join_time: datetime = fields.DatetimeField(null=True)
"""用户入群时间"""
nickname = fields.CharField(255, null=True)
"""群聊昵称"""
uid = fields.BigIntField(null=True)
"""用户uid"""
_idx1 = db.Index("info_group_users_idx1", "user_qq", "group_id", unique=True)
class Meta:
table = "group_info_users"
table_description = "群员信息数据表"
unique_together = ("user_qq", "group_id")
@classmethod
async def add_member_info(
cls,
user_qq: int,
group_id: int,
user_name: str,
user_join_time: datetime,
uid: Optional[int] = None,
) -> bool:
async def get_group_member_id_list(cls, group_id: int) -> Set[int]:
"""
说明:
添加群内用户信息
参数:
:param user_qq: qq号
:param group_id: 群号
:param user_name: 用户名称
:param user_join_time: 入群时间
:param uid: 用户唯一 id(自动生成)
"""
query = cls.query.where(
(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,
group_id=group_id,
user_join_time=user_join_time,
uid=uid
)
return True
except Exception:
return False
@classmethod
async def get_member_info(
cls, user_qq: int, group_id: int
) -> "GroupInfoUser":
"""
说明:
查询群员信息
参数:
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where(
(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, group_id: int) -> bool:
"""
说明:
删除群员信息
参数:
:param user_qq: qq号
:param group_id: 群号
"""
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 is None:
return True
else:
await cls.delete.where(
(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, group_id: int) -> List[int]:
"""
说明:
说明:
获取该群所有用户qq
参数:
参数:
:param group_id: 群号
"""
member_list = []
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
return set(
await cls.filter(group_id=group_id).values_list("user_qq", flat=True)
) # type: ignore
@classmethod
async def set_group_member_nickname(
cls, user_qq: int, group_id: int, nickname: str
) -> bool:
async def set_user_nickname(cls, user_qq: int, group_id: int, nickname: str):
"""
说明:
说明:
设置群员在该群内的昵称
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param nickname: 昵称
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
await cls.update_or_create(
user_qq=user_qq,
group_id=group_id,
defaults={"nickname": nickname},
)
user = await query.with_for_update().gino.first()
if user:
await user.update(nickname=nickname).apply()
return True
return False
@classmethod
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
return list(
await cls.filter(user_qq=user_qq).values_list("group_id", flat=True)
) # type: ignore
@classmethod
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
async def get_user_nickname(cls, user_qq: int, group_id: int) -> str:
"""
说明:
说明:
获取用户在该群的昵称
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
user = await query.gino.first()
if user:
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
if user.nickname:
_tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
nickname = ""
if black_word := Config.get_config("nickname", "BLACK_WORD"):
for x in user.nickname:
_tmp += "*" if x in black_word else x
return _tmp
nickname += "*" if x in black_word else x
return nickname
return user.nickname
return ""
@classmethod
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.group_id == group_id)
async def get_group_member_uid(cls, user_qq: int, group_id: int) -> Optional[int]:
logger.debug(
f"GroupInfoUser 尝试获取 用户[<u><e>{user_qq}</e></u>] 群聊[<u><e>{group_id}</e></u>] UID"
)
user = await query.gino.first()
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.group_id == 114514)).with_for_update()
_max_uid_user = await _max_uid.gino.first()
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
_max_uid_user, _ = await cls.get_or_create(user_qq=114514, group_id=114514)
_max_uid = _max_uid_user.uid
if not user or not user.uid:
all_user = await cls.query.where(cls.user_qq == user_qq).gino.all()
if not user.uid:
all_user = await cls.filter(user_qq=user_qq).all()
for x in all_user:
if x.uid:
return x.uid
else:
if not user:
await GroupInfoUser.add_member_info(user_qq, group_id, '', datetime.min)
user = await cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
).gino.first()
await user.update(
uid=_max_uid + 1,
).apply()
await _max_uid_user.update(
uid=_max_uid + 1,
).apply()
return user.uid if user and user.uid else None
user.uid = _max_uid + 1
_max_uid_user.uid = _max_uid + 1
await cls.bulk_update([user, _max_uid_user], ["uid"])
logger.debug(
f"GroupInfoUser 获取 用户[<u><e>{user_qq}</e></u>] 群聊[<u><e>{group_id}</e></u>] UID: {user.uid}"
)
return user.uid
@classmethod
async def _run_script(cls):
return [
"alter table group_info_users alter user_join_time drop not null;" # 允许 user_join_time 为空
]
+48 -72
View File
@@ -1,124 +1,100 @@
from services.db_context import db
from tortoise import fields
from services.db_context import Model
class LevelUser(db.Model):
__tablename__ = "level_users"
class LevelUser(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
user_level = db.Column(db.BigInteger(), nullable=False)
group_flag = db.Column(db.Integer(), nullable=False, default=0)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
user_level = fields.BigIntField()
"""用户权限等级"""
group_flag = fields.IntField(default=0)
"""特殊标记,是否随群管理员变更而设置权限"""
_idx1 = db.Index("level_group_users_idx1", "user_qq", "group_id", unique=True)
class Meta:
table = "level_users"
table_description = "用户权限数据库"
unique_together = ("user_qq", "group_id")
@classmethod
async def get_user_level(cls, user_qq: int, group_id: int) -> int:
"""
说明:
说明:
获取用户在群内的等级
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first()
if user:
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
return user.user_level
else:
return -1
return -1
@classmethod
async def set_level(
cls, user_qq: int, group_id: int, level: int, group_flag: int = 0
) -> bool:
):
"""
说明:
说明:
设置用户在群内的权限
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param level: 权限等级
:param group_flag: 是否被自动更新刷新权限 0:是,1:否
"""
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()
return False
await cls.update_or_create(
user_qq=user_qq,
group_id=group_id,
defaults={"user_level": level, "group_flag": group_flag},
)
@classmethod
async def delete_level(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
说明:
删除用户权限
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
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:
return False
else:
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
await user.delete()
return True
return False
@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: 权限等级
"""
if group_id != 0:
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
user = await query.gino.first()
if user is None:
return False
user_level = user.user_level
if group_id:
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
return user.user_level >= level
else:
query = cls.query.where(cls.user_qq == user_qq)
highest_level = 0
for user in await query.gino.all():
if user.user_level > highest_level:
highest_level = user.user_level
user_level = highest_level
if user_level >= level:
return True
else:
return False
user_list = await cls.filter(user_qq=user_qq).all()
user = max(user_list, key=lambda x: x.user_level)
return user.user_level >= level
return False
@classmethod
async def is_group_flag(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
说明:
检测是否会被自动更新刷新权限
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
user = await cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
).gino.first()
if not user:
return False
if user.group_flag == 1:
return True
else:
return False
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
return user.group_flag == 1
return False
+49 -77
View File
@@ -1,99 +1,71 @@
from datetime import datetime
from typing import List
from services.db_context import db
from typing import List, Literal, Optional, Tuple
from tortoise import fields
from services.db_context import Model
class SignGroupUser(db.Model):
__tablename__ = "sign_group_users"
class SignGroupUser(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = 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)
add_probability = db.Column(
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
)
specify_probability = db.Column(
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
checkin_count = fields.IntField(default=0)
"""签到次数"""
checkin_time_last = fields.DatetimeField(auto_now=True)
"""最后签到时间"""
impression = fields.DecimalField(10, 3, default=0)
"""好感度"""
add_probability = fields.DecimalField(10, 3, default=0)
"""双倍签到增加概率"""
specify_probability = fields.DecimalField(10, 3, default=0)
"""使用指定双倍概率"""
# specify_probability = fields.DecimalField(10, 3, default=0)
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "group_id", unique=True)
class Meta:
table = "sign_group_users"
table_description = "群员签到数据表"
unique_together = ("user_qq", "group_id")
@classmethod
async def ensure(
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.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,
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):
async def sign(cls, user: "SignGroupUser", impression: float):
"""
说明:
签到
说明:
:param user: 用户
:param impression: 增加的好感度
:param checkin_time_last: 签到时间
"""
await user.update(
checkin_count=user.checkin_count + 1,
checkin_time_last=checkin_time_last,
impression=user.impression + impression,
add_probability=0,
specify_probability=0,
).apply()
user.checkin_count = user.checkin_count + 1
user.add_probability = 0
user.specify_probability = 0
user.impression = float(user.impression) + impression
await user.save()
@classmethod
async def get_all_impression(cls, group_id: int) -> "list, list, list":
async def get_all_impression(
cls, group_id: Optional[int]
) -> Tuple[List[int], List[int], List[float]]:
"""
说明:
说明:
获取该群所有用户 id 及对应 好感度
参数:
参数:
:param group_id: 群号
"""
impression_list = []
user_qq_list = []
user_group = []
if group_id:
query = cls.query.where(cls.group_id == group_id)
query = cls.filter(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.group_id)
return user_qq_list, impression_list, user_group
query = cls
value_list = await query.all().values_list("user_qq", "group_id", "impression") # type: ignore
qq_list = []
group_list = []
impression_list = []
for value in value_list:
qq_list.append(value[0])
group_list.append(value[1])
impression_list.append(float(value[2]))
return qq_list, impression_list, group_list
+29
View File
@@ -0,0 +1,29 @@
from datetime import datetime
from tortoise import fields
from services.db_context import Model
class UserShopGoldLog(Model):
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
type = fields.IntField()
"""金币使用类型 0: 购买, 1: 使用, 2: 插件"""
name = fields.CharField(255)
"""商品/插件 名称"""
spend_gold = fields.IntField(default=0)
"""花费金币"""
num = fields.IntField()
"""数量"""
create_time = fields.DatetimeField(auto_now_add=True)
"""创建时间"""
class Meta:
table = "user_shop_gold_log"
table_description = "金币使用日志表"
+14 -15
View File
@@ -1,20 +1,20 @@
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from nonebot import on_command
from nonebot.rule import to_me
import os
import random
from nonebot import on_command, on_keyword
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.utils import FreqLimiter
from configs.config import NICKNAME
import random
from nonebot import on_keyword
import os
from nonebot.rule import to_me
from configs.config import NICKNAME
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from utils.utils import FreqLimiter
__zx_plugin_name__ = "基本设置 [Hidden]"
__plugin_usage__ = "用法: 无"
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_author__ = "HibiKier"
_flmt = FreqLimiter(300)
@@ -29,7 +29,7 @@ async def _(event: GroupMessageEvent):
return
_flmt.start_cd(event.group_id)
await config_play_game.finish(
image(random.choice(os.listdir(IMAGE_PATH / "dayouxi")), "dayouxi")
image(IMAGE_PATH / random.choice(os.listdir(IMAGE_PATH / "dayouxi")))
)
@@ -40,14 +40,14 @@ self_introduction = on_command(
@self_introduction.handle()
async def _():
if NICKNAME.find('真寻') != -1:
if NICKNAME.find("真寻") != -1:
result = (
"我叫绪山真寻\n"
"你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n"
"年龄的话我还是个**岁初中生(至少现在是)\n"
"身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n"
"我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n"
"最好的朋友是椛!\n" + image("zhenxun")
"最好的朋友是椛!\n" + image("zhenxun.jpg")
)
await self_introduction.finish(result)
@@ -57,5 +57,4 @@ my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True)
@my_wife.handle()
async def _():
await my_wife.finish(image("laopo.jpg", "other"))
await my_wife.finish(image(IMAGE_PATH / "other" / "laopo.jpg"))
+17 -14
View File
@@ -1,17 +1,16 @@
from typing import List
from nonebot import on_message
from nonebot.adapters.onebot.v11 import (
Bot,
GroupMessageEvent,
Message,
MessageEvent,
)
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.rule import to_me
from configs.config import NICKNAME, Config
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.utils import get_message_img, get_message_text
from .data_source import get_chat_result, hello, no_result
from configs.config import NICKNAME, Config
__zx_plugin_name__ = "AI"
__plugin_usage__ = f"""
@@ -25,19 +24,25 @@ __plugin_settings__ = {
"cmd": ["Ai", "ai", "AI", "aI"],
}
__plugin_configs__ = {
"TL_KEY": {"value": [], "help": "图灵Key"},
"ALAPI_AI_CHECK": {"value": False, "help": "是否检测青云客骂娘回复", "default_value": False},
"TL_KEY": {"value": [], "help": "图灵Key", "type": List[str]},
"ALAPI_AI_CHECK": {
"value": False,
"help": "是否检测青云客骂娘回复",
"default_value": False,
"type": bool,
},
"TEXT_FILTER": {
"value": ["鸡", "口交"],
"help": "文本过滤器,将敏感词更改为*",
"default_value": [],
"type": List[str],
},
}
Config.add_plugin_config(
"alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token"
)
ai = on_message(rule=to_me(), priority=8)
ai = on_message(rule=to_me(), priority=998)
@ai.handle()
@@ -60,11 +65,9 @@ async def _(bot: Bot, event: MessageEvent):
await ai.finish(hello())
img = img[0] if img else ""
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
nickname = await GroupInfoUser.get_user_nickname(event.user_id, event.group_id)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
nickname = await FriendUser.get_user_nickname(event.user_id)
if not nickname:
if isinstance(event, GroupMessageEvent):
nickname = event.sender.card or event.sender.nickname
+54 -47
View File
@@ -1,11 +1,13 @@
import os
import random
import re
from utils.http_utils import AsyncHttpx
from configs.path_config import IMAGE_PATH, DATA_PATH
from configs.config import NICKNAME, Config
from configs.path_config import DATA_PATH, IMAGE_PATH
from services.log import logger
from utils.message_builder import image, face
from configs.config import Config, NICKNAME
from utils.http_utils import AsyncHttpx
from utils.message_builder import face, image
from .utils import ai_message_manager
try:
@@ -124,37 +126,43 @@ async def xie_ai(text: str) -> str:
:param text: 问题
:return: 青云可回复
"""
res = await AsyncHttpx.get(f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}")
content = ""
data = json.loads(res.text)
if data["result"] == 0:
content = data["content"]
if "菲菲" in content:
content = content.replace("菲菲", NICKNAME)
if "艳儿" in content:
content = content.replace("艳儿", NICKNAME)
if "公众号" in content:
content = ""
if "{br}" in content:
content = content.replace("{br}", "\n")
if "提示" in content:
content = content[: content.find("提示")]
if "淘宝" in content or "taobao.com" in content:
return ""
while True:
r = re.search("{face:(.*)}", content)
if r:
id_ = r.group(1)
content = content.replace(
"{" + f"face:{id_}" + "}", str(face(int(id_)))
)
else:
break
return (
content
if not content and not Config.get_config("ai", "ALAPI_AI_CHECK")
else await check_text(content)
res = await AsyncHttpx.get(
f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}"
)
content = ""
try:
data = json.loads(res.text)
if data["result"] == 0:
content = data["content"]
if "菲菲" in content:
content = content.replace("菲菲", NICKNAME)
if "艳儿" in content:
content = content.replace("艳儿", NICKNAME)
if "公众号" in content:
content = ""
if "{br}" in content:
content = content.replace("{br}", "\n")
if "提示" in content:
content = content[: content.find("提示")]
if "淘宝" in content or "taobao.com" in content:
return ""
while True:
r = re.search("{face:(.*)}", content)
if r:
id_ = r.group(1)
content = content.replace(
"{" + f"face:{id_}" + "}", str(face(int(id_)))
)
else:
break
return (
content
if not content and not Config.get_config("ai", "ALAPI_AI_CHECK")
else await check_text(content)
)
except Exception as e:
logger.error(f"Ai xie_ai 发生错误 {type(e)}:{e}")
return ""
def hello() -> str:
@@ -172,9 +180,9 @@ def hello() -> str:
)
img = random.choice(os.listdir(IMAGE_PATH / "zai"))
if img[-4:] == ".gif":
result += image(img, "zai")
result += image(IMAGE_PATH / "zai" / img)
else:
result += image(img, "zai")
result += image(IMAGE_PATH / "zai" / img)
return result
@@ -183,17 +191,16 @@ def no_result() -> str:
"""
没有回答时的回复
"""
return (
random.choice(
[
"你在说啥子?",
f"纯洁的{NICKNAME}没听懂",
"下次再告诉你(下次一定)",
"你觉得我听懂了吗?嗯?",
"我!不!知!道!",
]
)
+ image(random.choice(os.listdir(IMAGE_PATH / "noresult")), "noresult")
return random.choice(
[
"你在说啥子?",
f"纯洁的{NICKNAME}没听懂",
"下次再告诉你(下次一定)",
"你觉得我听懂了吗?嗯?",
"我!不!知!道!",
]
) + image(
IMAGE_PATH / "noresult" / random.choice(os.listdir(IMAGE_PATH / "noresult"))
)
+5 -8
View File
@@ -1,14 +1,11 @@
from configs.config import Config
from pathlib import Path
import nonebot
from configs.config import Config
Config.add_plugin_config(
"alapi",
"ALAPI_TOKEN",
None,
help_="在https://admin.alapi.cn/user/login登录后获取token"
"alapi", "ALAPI_TOKEN", None, help_="在https://admin.alapi.cn/user/login登录后获取token"
)
nonebot.load_plugins("plugins/alapi")
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
+2 -25
View File
@@ -1,7 +1,3 @@
from nonebot.adapters.onebot.v11 import MessageSegment
from utils.image_utils import BuildImage
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from typing import Optional, Tuple, Union
from configs.config import Config
from utils.http_utils import AsyncHttpx
@@ -23,27 +19,8 @@ async def get_data(url: str, params: Optional[dict] = None) -> Tuple[Union[dict,
return "没有搜索到...", 997
return data, 200
else:
if data["code"] == 101:
return "缺失ALAPI TOKEN,请在配置文件中填写!", 999
return f'发生了错误...code:{data["code"]}', 999
except TimeoutError:
return "超时了....", 998
def gen_wbtop_pic(data: dict) -> MessageSegment:
"""
生成微博热搜图片
:param data: 微博热搜数据
"""
bk = BuildImage(700, 32 * 50 + 280, 700, 32, color="#797979")
wbtop_bk = BuildImage(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
bk.paste(wbtop_bk)
text_bk = BuildImage(700, 32 * 50, 700, 32, color="#797979")
for i, data in enumerate(data):
title = f"{i+1}. {data['hot_word']}"
hot = data["hot_word_num"]
img = BuildImage(700, 30, font_size=20)
w, h = img.getsize(title)
img.text((10, int((30 - h) / 2)), title)
img.text((580, int((30 - h) / 2)), hot)
text_bk.paste(img)
bk.paste(text_bk, (0, 280))
return image(b64=bk.pic2bs4())
+97 -50
View File
@@ -1,24 +1,29 @@
from nonebot import on_command
from typing import Any, Optional, Tuple
import nonebot
from nonebot import Driver, on_command, on_regex
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import ArgStr, CommandArg, RegexGroup
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from configs.config import Config
from models.level_user import LevelUser
from services.log import logger
from utils.image_utils import text2image
from utils.manager import group_manager
from utils.message_builder import image
from utils.utils import get_bot, is_number, scheduler
from .data_source import (
BilibiliSub,
SubManager,
add_live_sub,
delete_sub,
add_up_sub,
add_season_sub,
add_up_sub,
delete_sub,
get_media_id,
get_sub_status,
SubManager,
BilibiliSub,
)
from models.level_user import LevelUser
from configs.config import Config
from utils.utils import is_number, scheduler, get_bot
from typing import Optional
from services.log import logger
from nonebot import Driver
from nonebot.params import CommandArg, ArgStr
import nonebot
__zx_plugin_name__ = "B站订阅"
__plugin_usage__ = """
@@ -27,18 +32,18 @@ usage:
主播订阅相当于 直播间订阅 + UP订阅
指令:[示例Id乱打的,仅做示例]
添加订阅 ['主播'/'UP'/'番剧'] [id/链接/番名]
删除订阅 [id]
删除订阅 ['主播'/'UP'/'id'] [id]
查看订阅
示例:添加订阅主播 2345344 <-(直播房间id)
示例:添加订阅UP 2355543 <-(个人主页id)
示例:添加订阅番剧 史莱姆 <-(支持模糊搜索)
示例:添加订阅番剧 125344 <-(番剧id)
示例:删除订阅 2324344 <-(任意id,通过查看订阅获取)
示例:删除订阅id 2324344 <-(任意id,通过查看订阅获取)
""".strip()
__plugin_des__ = "非常便利的B站订阅通知"
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"]
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 ['主播'/'UP'/'id'] [id]", "查看订阅"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_author__ = "HibiKier & NumberSir"
__plugin_settings__ = {
"level": 5,
"default_status": True,
@@ -50,12 +55,25 @@ __plugin_configs__ = {
"value": 5,
"help": "群内bilibili订阅需要管理的权限",
"default_value": 5,
}
"type": int,
},
"LIVE_MSG_AT_ALL": {
"value": False,
"help": "直播提醒是否AT全体(仅在真寻是管理员时生效)",
"default_value": False,
"type": bool,
},
"UP_MSG_AT_ALL": {
"value": False,
"help": "UP动态投稿提醒是否AT全体(仅在真寻是管理员时生效)",
"default_value": False,
"type": bool,
},
}
add_sub = on_command("添加订阅", priority=5, block=True)
del_sub = on_command("删除订阅", priority=5, block=True)
show_sub_info = on_command("查看订阅", priority=5, block=True)
show_sub_info = on_regex("^查看订阅$", priority=5, block=True)
driver: Driver = nonebot.get_driver()
@@ -70,6 +88,7 @@ async def _():
@add_sub.handle()
@del_sub.handle()
async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip().split()
if len(msg) < 2:
@@ -143,25 +162,30 @@ async def _(
)
@del_sub.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if not is_number(msg):
await del_sub.finish("Id必须为数字!", at_sender=True)
id_ = (
f"{event.user_id}:{event.group_id}"
if isinstance(event, GroupMessageEvent)
else f"{event.user_id}"
)
if await BilibiliSub.delete_bilibili_sub(int(msg), id_):
await del_sub.send(f"删除订阅id:{msg} 成功...")
@del_sub.got("sub_type")
@del_sub.got("sub_user")
@del_sub.got("id")
async def _(
event: MessageEvent,
id_: str = ArgStr("id"),
sub_type: str = ArgStr("sub_type"),
sub_user: str = ArgStr("sub_user"),
):
if sub_type in ["主播", "直播"]:
result = await BilibiliSub.delete_bilibili_sub(int(id_), sub_user, "live")
elif sub_type.lower() in ["up", "用户"]:
result = await BilibiliSub.delete_bilibili_sub(int(id_), sub_user, "up")
else:
result = await BilibiliSub.delete_bilibili_sub(int(id_), sub_user)
if result:
await del_sub.send(f"删除订阅id:{id_} 成功...")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除订阅 {id_}"
)
else:
await del_sub.send(f"删除订阅id:{msg} 失败...")
await del_sub.send(f"删除订阅id:{id_} 失败...")
@show_sub_info.handle()
@@ -170,7 +194,7 @@ async def _(event: MessageEvent):
id_ = f"{event.group_id}"
else:
id_ = f"{event.user_id}"
data = await BilibiliSub.get_sub_data(id_)
data = await BilibiliSub.filter(sub_users__contains=id_).all()
live_rst = ""
up_rst = ""
season_rst = ""
@@ -195,7 +219,13 @@ async def _(event: MessageEvent):
live_rst = (
"该群目前没有任何订阅..." if isinstance(event, GroupMessageEvent) else "您目前没有任何订阅..."
)
await show_sub_info.send(live_rst + up_rst + season_rst)
await show_sub_info.send(
image(
await text2image(
live_rst + up_rst + season_rst, padding=10, color="#f9f6f2"
)
)
)
# 推送
@@ -207,18 +237,18 @@ async def _():
bot = get_bot()
sub = None
if bot:
try:
await sub_manager.reload_sub_data()
sub = await sub_manager.random_sub_data()
if sub:
logger.debug(f"Bilibili订阅开始检测:{sub.sub_id}")
rst = await get_sub_status(sub.sub_id, sub.sub_type)
# try:
await sub_manager.reload_sub_data()
sub = await sub_manager.random_sub_data()
if sub:
logger.debug(f"Bilibili订阅开始检测:{sub.sub_id}")
rst = await get_sub_status(sub.sub_id, sub.sub_type)
await send_sub_msg(rst, sub, bot)
if sub.sub_type == "live":
rst = await get_sub_status(sub.sub_id, "up")
await send_sub_msg(rst, sub, bot)
if sub.sub_type == "live":
rst = await get_sub_status(sub.sub_id, "up")
await send_sub_msg(rst, sub, bot)
except Exception as e:
logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id if sub else 0} {type(e)}:{e}")
# except Exception as e:
# logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id if sub else 0} {type(e)}:{e}")
async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
@@ -228,13 +258,30 @@ async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
:param sub: BilibiliSub
:param bot: Bot
"""
temp_group = []
if rst:
for x in sub.sub_users.split(",")[:-1]:
try:
if ":" in x:
await bot.send_group_msg(
group_id=int(x.split(":")[1]), message=Message(rst)
)
if ":" in x and x.split(":")[1] not in temp_group:
group_id = int(x.split(":")[1])
temp_group.append(group_id)
if (
await bot.get_group_member_info(
group_id=group_id, user_id=int(bot.self_id), no_cache=True
)
)["role"] in ["owner", "admin"]:
if (
sub.sub_type == "live"
and Config.get_config("bilibili_sub", "LIVE_MSG_AT_ALL")
) or (
sub.sub_type == "up"
and Config.get_config("bilibili_sub", "UP_MSG_AT_ALL")
):
rst = "[CQ:at,qq=all]\n" + rst
if group_manager.get_plugin_status("bilibili_sub", group_id):
await bot.send_group_msg(
group_id=group_id, message=Message(rst)
)
else:
await bot.send_private_msg(user_id=int(x), message=Message(rst))
except Exception as e:

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