Compare commits

...
291 Commits
Author SHA1 Message Date
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
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
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
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
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 1bb9b2cb3f fix setu 2022-07-04 20:21:35 +08:00
HibiKier 7ba129b3bf update README.md 2022-07-04 20:03:38 +08:00
HibiKier 1e2c9ca28a Merge pull request #886 from yajiwa/main
修复B站订阅UP动态
2022-07-04 19:34:33 +08:00
yajiwa c6f37fd05f update bilibili_sub 2022-07-04 15:45:15 +08:00
HibiKier b6b569fff9 Update goods_info.py 2022-07-04 13:13:06 +08:00
HibiKier ac57c016a6 Update goods_info.py 2022-07-04 13:09:16 +08:00
HibiKier 28fdd9de95 Update __version__ 2022-07-04 12:29:33 +08:00
HibiKier 1ec946aaa9 Update README.md 2022-07-04 08:40:44 +08:00
HibiKier d6110e3c6f update bilibili_sub 2022-07-03 22:00:49 +08:00
HibiKier 4c5302bd4c fix shop update goods 2022-07-03 16:47:19 +08:00
HibiKier 21ee3d5c3e update send_setu 2022-07-03 16:33:14 +08:00
HibiKier e5c036cee8 update shop image 2022-07-03 13:55:26 +08:00
HibiKier 6f82488af7 Merge pull request #879 from VirtualTowel/main
修复图库内图片无法被连续删除的问题
2022-07-03 13:53:49 +08:00
VirtualTowel 57a7903c63 修复图库内图片无法被连续删除的问题 2022-07-01 20:12:39 +08:00
HibiKier 27b89b333a Merge pull request #866 from Excalibur5100/main
修复色图插件api修改无法搜索图片
2022-06-28 20:48:33 +08:00
Excalibur5100 ce2c4e7492 修复色图插件最近加tag参数后搜不到图的问题
插件所用API更新,最大数量num改为20
https://api.lolicon.app/#/setu
2022-06-28 19:48:59 +08:00
HibiKier cad98a2a33 Update goods_info.py 2022-06-26 22:23:19 +08:00
HibiKier 40da48e685 update models 2022-06-26 19:29:51 +08:00
HibiKier 1c393e5c3e update shop daily_limit 2022-06-26 03:08:23 +08:00
HibiKier 667c143c74 update pix 2022-06-26 01:37:47 +08:00
HibiKier bc089c18ce update bt 2022-06-26 01:26:14 +08:00
HibiKier 24b730c0e2 Merge pull request #847 from po-lan/main
对WSL虚拟机 代理 添加写法
2022-06-24 20:59:28 +08:00
po-lan 9ed9e9b973 对WSL虚拟机 代理 添加写法 2022-06-23 17:57:47 +08:00
HibiKier 5b0027aa3d Update README.md 2022-06-22 22:49:26 +08:00
HibiKier 810c5e4e8b Update README.md 2022-06-21 21:59:41 +08:00
HibiKier 907534958f Merge pull request #840 from yajiwa/main
update parse_bilibili
2022-06-21 21:59:23 +08:00
HibiKier f08a18ab07 Update data_class.py 2022-06-21 21:01:14 +08:00
github-actions[bot] 40549d5ca7 Auto generate poetry.lock 2022-06-21 00:56:57 +00:00
yajiwa 3e67edc506 update pyproject.toml 2022-06-21 08:53:49 +08:00
yajiwa 9c56a81f65 update parse_bilibili 2022-06-21 08:50:05 +08:00
HibiKier a9a636c9ae Update plugins2settings_manager.py 2022-06-20 22:31:57 +08:00
HibiKier 98374dcd74 Update README.md 2022-06-20 22:07:48 +08:00
HibiKier 10ca6eec91 update webui 2022-06-20 21:54:10 +08:00
HibiKier 216d32cf21 Update README.md 2022-06-19 23:16:11 +08:00
HibiKier 248fae4fe6 Update __version__ 2022-06-19 23:15:40 +08:00
HibiKier b479b6839d Update README.md 2022-06-19 22:29:44 +08:00
HibiKier 1a4e1e9515 Merge pull request #835 from yajiwa/main
词条优化问题展示,修改含机器人昵称和@逻辑
2022-06-19 22:29:20 +08:00
yajiwa e5160a4ee8 Merge branch 'HibiKier:main' into main 2022-06-19 17:26:13 +08:00
yajiwa 56ea3964a7 update word_bank 2022-06-19 17:24:50 +08:00
HibiKier ad73778286 update README.md 2022-06-19 16:55:02 +08:00
HibiKier 3e548f48c8 Merge pull request #828 from McElaga/main
修复原神树脂重复提醒的bug
2022-06-19 16:54:25 +08:00
HibiKier ae466931fa fix webui 2022-06-19 16:44:37 +08:00
HibiKier 68052b526f update image_utils 2022-06-18 15:23:36 +08:00
HibiKier 903b5b88a7 update image_utils 2022-06-18 15:09:55 +08:00
HibiKier 007823d6b2 update README.md 2022-06-18 15:03:05 +08:00
HibiKier db5c4fb349 Merge pull request #830 from po-lan/main
我不太会提交单个文件,我就把俄罗斯轮盘的文件 改回去了,再提交的
2022-06-18 15:00:46 +08:00
HibiKier c37901290a fix nickname 2022-06-18 14:57:54 +08:00
HibiKier da67f1f6f8 update webui 2022-06-18 14:48:46 +08:00
HibiKier 5172fa69e5 fix web ui 2022-06-18 14:31:44 +08:00
po-lan dd7280cd0d 恢复 原先的文件 2022-06-18 14:08:59 +08:00
McElaga 0d0f522c88 Merge branch 'HibiKier:main' into main 2022-06-18 09:27:12 +08:00
McElaga 5429e6ed5c Merge branch 'main' of https://github.com/McElaga/zhenxun_bot 2022-06-18 09:15:24 +08:00
McElaga 9db69fa05b 修复一点逻辑小问题 2022-06-18 09:15:19 +08:00
HibiKier 3b8d52bcb5 Update README.md 2022-06-17 18:50:37 +08:00
HibiKier 807f39a336 Update README.md 2022-06-17 18:50:15 +08:00
HibiKier fea2f30461 Merge pull request #820 from LambdaYH/patch-2
修复wordbank的一些小问题
2022-06-17 18:49:42 +08:00
po-lan 5d97e3f95f Update __init__.py 2022-06-16 16:15:39 +08:00
po-lan 63e6ca3e99 Update __init__.py 2022-06-16 15:40:46 +08:00
po-lan b11590ec3c ban掉被击毙的人一段时间 2022-06-16 15:38:20 +08:00
po-lan 3a43ed6919 如果需要 保存到 config 可以少调用一次 2022-06-16 14:38:41 +08:00
po-lan 15ce9c91fb Update __init__.py 2022-06-16 14:25:22 +08:00
LambdaYH 0e8d7537d4 fix wordbank 2022-06-16 00:43:32 +08:00
Cinte 1fca0787be fix: 修复之前更改正则引入的问题 2022-06-15 23:16:39 +08:00
HibiKier af30285c00 Update browser.py 2022-06-15 10:08:43 +08:00
HibiKier a84cab7afd replace bt url 2022-06-14 20:40:11 +08:00
HibiKier 593573ddfb fix pix 2022-06-14 19:48:32 +08:00
HibiKier e9e9f81bdb Merge pull request #806 from LambdaYH/patch-2
fix: 修复添加词条时对answer中图片的处理
2022-06-14 19:31:53 +08:00
HibiKier 61f624841b Merge pull request #810 from LambdaYH/patch-3
fix: 自动更新群组
2022-06-14 19:31:18 +08:00
HibiKier 4bb38a2730 Merge pull request #812 from po-lan/main
可关闭 ssl 验证
2022-06-14 19:22:25 +08:00
HibiKier d4ec0df00c Update http_utils.py 2022-06-14 19:22:12 +08:00
po-lan c8a7d855f8 Update http_utils.py 2022-06-14 18:47:43 +08:00
Cinte 73a126dcd5 fix: 自动更新群组 2022-06-14 09:18:03 +08:00
HibiKier 0736533389 fix search_image 2022-06-13 22:16:45 +08:00
Cinte 2695d658ab fix: 修复添加词条时对answer中图片的处理 2022-06-13 22:11:18 +08:00
HibiKier 947166e793 Merge pull request #804 from po-lan/main
Windows 重启适配
2022-06-13 20:20:30 +08:00
po-lan 80c49a7cf5 Update __init__.py 2022-06-13 15:34:28 +08:00
po-lan 55bfa8f669 Update __init__.py
Windows 重启适配
2022-06-13 15:24:28 +08:00
HibiKier 74ade14f5e Update README.md 2022-06-13 11:07:34 +08:00
HibiKier c9b5218ebc Merge pull request #798 from CopilotLaLaLa/main
webui中token.json文件写入补充
2022-06-13 11:07:11 +08:00
HibiKier b324b2bd65 Merge pull request #800 from yajiwa/main
update setu_img
2022-06-13 11:06:20 +08:00
HibiKier 35c038efa2 Update utils.py 2022-06-13 11:05:16 +08:00
HibiKier caa404d58d Update utils.py 2022-06-13 11:03:21 +08:00
yajiwa 830103b9d5 update change_img_md5 2022-06-13 10:59:29 +08:00
yajiwa 6e18379597 update setu_img 2022-06-13 10:08:51 +08:00
yajiwa 6effbacb28 add change_img_md5 2022-06-13 10:08:09 +08:00
CopilotLaLaLa a20a1a0234 同步原仓库 2022-06-12 15:23:10 +00:00
CopilotLaLaLa 3667724061 token_json文件写入 2022-06-12 15:16:07 +00:00
HibiKier 785179e4a7 update pix 2022-06-11 17:57:19 +08:00
HibiKier 715338f821 Merge pull request #791 from mmmjie/main
两处BUG的修复
2022-06-10 21:31:51 +08:00
mmmjie 7d5a82ab6d Update update_picture.py
对于temp/temp的错误路径,减少了一个temp
TEMP_PATH 已经指向了一个temp了
2022-06-10 00:37:18 +08:00
mmmjie e764cfcc1c Update white2black_image.py
随着7b836ac 对utils/image_utils.py 的改动
调整此插件对于 utils/image_utils.py改动的引用部分
2022-06-10 00:35:57 +08:00
HibiKier 363acf37bc fix bug and update 2022-06-09 20:39:48 +08:00
HibiKier 5fd687c1e4 Merge pull request #778 from SinKy-Yan/main
fix auto update bug
2022-06-09 19:37:26 +08:00
HibiKier dbedcbb93d Update pyproject.toml 2022-06-08 11:51:32 +08:00
HibiKier 9e9611f11f Update README.md 2022-06-08 11:43:10 +08:00
HibiKier 44002838da Merge pull request #779 from MingxuanGame/main
chore(deps): update `nonebot-adapter-onebot`
2022-06-08 11:42:43 +08:00
MingxuanGame 4daab8459f chore(deps): update nonebot-adapter-onebot 2022-06-07 11:57:34 +00:00
HibiKier 5a002f75cc Merge pull request #777 from LambdaYH/patch-1
fix image_utils.py
2022-06-07 19:27:31 +08:00
源源球球✨ a2180a1365 fix auto update bug 2022-06-07 10:19:23 +00:00
Cinte 7b836acf36 fix image_utils.py
https://github.com/HibiKier/zhenxun_bot/commit/ae8a214a3a5c08a51cacd1dc37583c0b32e6332f
之前这个commit里面看到函数参数有写着int类型就把`font_size`类型转换给去了,结果导致了部分地方输入float类型后报错。现在改回来
2022-06-07 17:06:16 +08:00
HibiKier a112a561cc Update README.md 2022-06-05 20:30:49 +08:00
HibiKier 6dcc2a69f4 Update README.md 2022-06-05 19:56:42 +08:00
HibiKier 74e9c55a09 update v0.1.5.8 2022-06-05 19:51:23 +08:00
HibiKier d4d6e736a4 Merge pull request #764 from McElaga/main
金币红包功能增加更多封面
2022-06-05 19:08:51 +08:00
HibiKier 5cf9938fa2 Merge pull request #763 from RShock/main
fix gold_redbag
2022-06-05 19:04:40 +08:00
McElaga 72ad0ad983 commit on main 2022-06-04 12:34:18 +08:00
咕咕型小r 690750d91e fix gold_redbag 2022-06-04 12:09:05 +08:00
HibiKier 9f1dfc4b9c Merge pull request #756 from McElaga/main
修复原神树脂提醒bug(已实测)
2022-06-03 16:15:50 +08:00
HibiKier 05eab5307f Update README.md 2022-06-03 16:13:29 +08:00
HibiKier b0fe70c960 Merge pull request #745 from LambdaYH/main
稍微调整了一下查看所有请求中的年龄绘制
2022-06-03 16:07:01 +08:00
McElaga 09d7992bc4 comit on main 2022-06-03 12:09:15 +08:00
McElaga c832a432c1 commit on main 2022-06-03 11:52:40 +08:00
HibiKier 41c22f4314 fix ShopRegister 2022-06-03 01:14:34 +08:00
HibiKier 252d45c79b fix webui update plugin_shop 2022-06-03 00:59:00 +08:00
Cinte ae8a214a3a Update image_utils.py 2022-06-02 10:06:55 +08:00
LambdaYH 86ce6d7664 fix: 稍微调整了一下查看所有请求中的年龄绘制 2022-06-02 10:02:03 +08:00
McElaga 67e96d6106 commit on main 2022-06-02 08:55:24 +08:00
HibiKier 24d9ec2b75 Update __init__.py 2022-06-01 11:05:12 +08:00
HibiKier 501e47c6ec fix image2text 2022-05-31 20:45:28 +08:00
HibiKier 5534a5a5c2 Merge pull request #707 from HiDolen/main
修复抽卡插件:方舟更新UP池信息时,若公告的第一个池子过期会导致无法更新UP池信息
2022-05-31 20:14:48 +08:00
HibiKier 7246aabf40 Merge pull request #712 from McElaga/main
修复发红包图片背景未透明化;修复原神树脂提醒参数错误
2022-05-31 20:07:35 +08:00
HibiKier 604ffae87e Merge pull request #711 from LambdaYH/patch-1
bot_friend_group将group_handle.修改为friend_handle.
2022-05-31 20:06:12 +08:00
HibiKier 2d5c16456b Merge pull request #721 from LambdaYH/patch-2
修复开启/关闭全部功能时帮助图片未重绘
2022-05-31 20:01:39 +08:00
Cinte d44f7633dc 修复开启/关闭全部功能时帮助图片未重绘 2022-05-30 20:43:48 +08:00
Cinte 469ac4035c 大概是把group_handle写成了friend_handle 2022-05-30 11:27:14 +08:00
McElaga dab218a6d7 commit on main 2022-05-30 11:14:47 +08:00
Dolen d6fc675d57 修复抽卡插件:避免被跳过的卡池信息污染后面的卡池信息 2022-05-30 11:11:49 +08:00
McElaga 04148f7365 commit on main 2022-05-30 11:00:19 +08:00
Dolen 4c34ac570f 修复抽卡插件:方舟更新UP池信息时,若公告的第一个池子过期会导致无法更新UP池信息 2022-05-29 23:13:36 +08:00
HibiKier fbdb8758a3 Update README.md 2022-05-29 22:21:26 +08:00
HibiKier 2d08747d70 Merge pull request #705 from yajiwa/main
商店插件判断是否有requirements.txt文件
2022-05-29 22:21:03 +08:00
yajiwa 0b4bacbbd1 update plugin_shop 2022-05-29 21:57:01 +08:00
yajiwa e0412c7edb Merge branch 'HibiKier:main' into main 2022-05-29 21:03:12 +08:00
HibiKier 38501cebf1 Update data_source.py 2022-05-29 20:56:03 +08:00
HibiKier ee45d0217e Update __init__.py 2022-05-29 20:55:32 +08:00
HibiKier 558f362919 update v0.1.5.8 2022-05-29 20:47:18 +08:00
HibiKier fb9db2f50c fix 2022-05-29 19:57:57 +08:00
HibiKier c1862e9c68 fix bt 2022-05-29 19:15:29 +08:00
HibiKier 731bde8e28 update v0.1.5.7 2022-05-29 19:14:36 +08:00
HibiKier 47c87f8694 update db_context 2022-05-28 22:50:23 +08:00
HibiKier 5558cdacc3 Update README.md 2022-05-28 21:09:58 +08:00
HibiKier 4650d244a5 Merge pull request #688 from McElaga/main
修复微博热搜报错,发红包小bug
2022-05-28 21:08:17 +08:00
HibiKier c65b8aae07 update webui 2022-05-28 20:57:08 +08:00
HibiKier 7ba2fb9584 update black_word 2022-05-28 20:55:14 +08:00
HibiKier 9a2cfd0c9b zhenxun_update add config 2022-05-28 18:28:38 +08:00
HibiKier a7d61b1f2b add config 2022-05-28 18:12:08 +08:00
HibiKier 7ab185f7d7 fix poke 2022-05-28 17:48:28 +08:00
HibiKier 724541d691 fix bug 2022-05-28 17:22:51 +08:00
McElaga baa6cda9c2 commit on main 2022-05-28 10:31:27 +08:00
HibiKier 9c987e9aad log2cn 2022-05-26 22:49:48 +08:00
HibiKier 134974ea9c Merge pull request #667 from NumberSir/main
更新抽卡插件
2022-05-26 22:43:11 +08:00
HibiKier 2d946958e3 Merge pull request #668 from HanakoLuna/patch-1
更新BT搜索源地址
2022-05-26 22:42:37 +08:00
Lya_Yami ffe010e9ce 更新BT搜索源地址 2022-05-26 20:47:12 +08:00
HibiKier 1c67252b0c Update README.md 2022-05-26 20:26:14 +08:00
HibiKier 60c1be25d4 Merge pull request #643 from LambdaYH/patch-1
修复[滴滴滴]会被转义成[滴滴滴]导致无法触发的问题
2022-05-26 20:25:45 +08:00
Number_Sir 18323a0916 更新抽卡插件
修复了方舟抽卡图文不符的问题
修复了方舟许多三星抽不出来的问题
修复了方舟重载卡池失败的问题
2022-05-26 20:07:09 +08:00
HibiKier 9d98abded9 Merge pull request #660 from Sakuracio/main
Replace URL
2022-05-26 19:49:23 +08:00
MangataAkihi b06a742b8c Update README.md 2022-05-26 17:20:37 +08:00
github-actions[bot] 87fe44f188 Auto generate poetry.lock 2022-05-26 09:18:16 +00:00
Cinte 96f6ef1693 修复[滴滴滴]会被转义成[滴滴滴]导致无法触发的问题 2022-05-26 09:59:45 +08:00
github-actions[bot] 374b7b7261 Auto generate poetry.lock 2022-05-25 23:42:48 +00:00
HibiKier 23c4141e55 Update README.md 2022-05-25 20:53:09 +08:00
HibiKier c21200c2a9 Merge pull request #610 from yajiwa/main
修复碧蓝航线/明日方舟up池解析出错的问题
2022-05-25 20:52:58 +08:00
HibiKier 4a8b94259d Merge pull request #602 from HiDolen/main-patch
修改翻译插件,添加缺失的冒号
2022-05-25 20:49:51 +08:00
HibiKier 28a58df27b Merge pull request #607 from MingxuanGame/main
feat: stream downloading and progress
2022-05-25 20:49:20 +08:00
HibiKier caaf486bbe Merge branch 'main' into main 2022-05-25 20:49:07 +08:00
HibiKier 0a972a399e Merge pull request #617 from mouhensama/main
把gamedraw的ba卡池搬运了过来并且进行了真寻的适配。
2022-05-25 20:44:07 +08:00
HibiKier 245dad1239 Merge pull request #624 from HiDolen/main-patch2
修改nickname插件:一处文案错误,添加敏感词
2022-05-25 20:42:51 +08:00
Dolen a6b6a2fbff 修改nickname插件:一处文案错误 2022-05-25 17:21:00 +08:00
Dolen 53000a949b 修改nickname插件:添加一个敏感词 2022-05-25 17:03:44 +08:00
Dolen eae1dd59a7 修改nickname插件:一处文案错误 2022-05-25 17:02:09 +08:00
HibiKier e6347a76a8 Update issue-template.md 2022-05-25 14:44:28 +08:00
HibiKier 13e0fb3df7 Delete bug-issue-template.md 2022-05-25 13:42:22 +08:00
HibiKier 3f1b23ef8a Update issue templates 2022-05-25 13:41:35 +08:00
HibiKier acae7f0658 Create ISSUE_TEMPLATE.md 2022-05-25 13:37:29 +08:00
HibiKier a9456b1bd6 Merge pull request #608 from AkashiCoin/main
Use Action to automatically generate poetry.lock
2022-05-25 13:35:39 +08:00
mouhensama e4d5a230d2 把nonebot_plugin_gamedraw的ba卡池搬运了过来并且进行了真寻的适配。 2022-05-25 11:47:08 +08:00
HibiKier fedf44b9fa Update README.md 2022-05-25 10:54:52 +08:00
HibiKier 451db104e8 Update config.py 2022-05-25 08:52:22 +08:00
HibiKier 9ac4c7f4e3 Update README.md 2022-05-25 08:52:15 +08:00
HibiKier 7cf1c6f016 Update README.md 2022-05-25 08:41:59 +08:00
yajiwa 6dd87ee301 fix draw_card 2022-05-25 07:02:42 +08:00
MingxuanGame 96837fa8db fix: rich from dev dependent to main dependent 2022-05-25 01:19:12 +08:00
MingxuanGame d816e76962 fix: rich from dev dependent to main dependent 2022-05-25 01:13:27 +08:00
AkashiCoin 310945d9cd Merge branch 'HibiKier:main' into main 2022-05-25 01:01:11 +08:00
MingxuanGame 1aba480495 feat: stream downloading and progress 2022-05-25 00:56:41 +08:00
HibiKier 07407749fe Update README.md 2022-05-24 22:05:38 +08:00
HibiKier dfab70dd90 Merge pull request #581 from HiDolen/main
修复抽卡插件:方舟抽卡的抽取和显示问题
2022-05-24 22:05:13 +08:00
Dolen 3b15469c98 修改翻译插件,发送消息添加冒号 2022-05-24 08:59:14 -05:00
HibiKier e4590800c2 Update README.md 2022-05-24 21:20:59 +08:00
HibiKier c63d4b8ad0 Merge pull request #573 from jk6589jk/patch-2
修复复读不能复读图片的问题
2022-05-24 21:19:41 +08:00
HibiKier 1fb913e2ed Merge pull request #576 from MingxuanGame/main
refactor&fix(manager): modify argument
2022-05-24 21:18:22 +08:00
HibiKier 72ace2dab7 Merge pull request #579 from yajiwa/main
更新"微博热搜"接口
2022-05-24 21:14:51 +08:00
HibiKier 3bcef18629 Merge pull request #600 from sdy623/main
bugfix: 修正了签到时日期时间的显示不补齐零的bug (符合日期时间表示法 ISO 8601)
2022-05-24 21:13:33 +08:00
sdy623 c91758519c bugfix: 修正了签到时日期时间的显示不补齐零的bug (符合日期时间表示法 ISO 8601) 2022-05-24 20:19:32 +08:00
jk6589jk 9c8f2e7aa0 Update fudu.py 2022-05-24 14:01:08 +08:00
Dolen 5f377af6d5 修复抽卡插件:方舟抽卡的抽取和显示问题 2022-05-24 09:13:10 +08:00
yajiwa 570b5b1766 update wbtop 2022-05-24 06:01:23 +08:00
MingxuanGame c4d53d58eb refactor&fix(manager): modify argument 2022-05-24 01:27:55 +08:00
jk6589jk ed65033cf1 修复复读不能复读图片的问题
IMAGE_PATH = Path() / "resources" / "image"
TEMP_PATH = Path() / "resources" / "temp"
image()默认读取在 resource/img 目录下,读写路径不同,导致找不到图片

打断打断施法!,rst.endswith("打断施法!")在复读内容含有图片时会报错
2022-05-23 22:06:53 +08:00
HibiKier 41836bde26 Update README.md 2022-05-23 22:05:19 +08:00
HibiKier 8381858742 Update README.md 2022-05-23 22:02:49 +08:00
HibiKier 1040bd0d58 update v0.1.5.6 2022-05-23 22:01:56 +08:00
HibiKier 404e47332e Merge pull request #441 from with9/main
添加pixiv搜图多关键词支持;修复p站搜图数量参数问题
2022-05-23 21:52:33 +08:00
HibiKier 3db128785e Update __init__.py 2022-05-23 21:52:08 +08:00
HibiKier 2189ea11df Update README.md 2022-05-23 19:46:30 +08:00
HibiKier 49b9bd65b0 Merge pull request #552 from jk6589jk/patch-1
修复有置顶的up主B站动态获取失败
2022-05-23 19:45:59 +08:00
jk6589jk b3fdb1ff58 修复B站动态获取失败
bili-dyn-item__tag的父项的父项才是完整的一条置顶动态
2022-05-23 12:59:53 +08:00
HibiKier c79e3fdcf0 Update README.md 2022-05-23 07:52:27 +08:00
HibiKier d7509f7030 Merge pull request #545 from yajiwa/main
修复"清除已删除插件数据"
2022-05-23 07:51:54 +08:00
yajiwa 5c99b55502 fix none_plugin_count 2022-05-23 02:35:57 +08:00
yajiwa fd255f022b Merge branch 'HibiKier:main' into main 2022-05-23 02:27:00 +08:00
HibiKier 41642589ae Update __version__ 2022-05-22 20:56:03 +08:00
HibiKier 619fef3bff update README.md 2022-05-22 20:52:59 +08:00
HibiKier 38c0da0cf8 update v0.1.5.4 2022-05-22 20:51:35 +08:00
HibiKier b241a58e84 update check_update 2022-05-22 19:04:58 +08:00
HibiKier 35c9585b22 delete WindowsSelectorEventLoopPolicy 2022-05-22 19:03:22 +08:00
HibiKier d2fe95cc05 fix query_resource_points and sign_in 2022-05-22 18:08:06 +08:00
HibiKier 92e60ba141 fix epic 2022-05-22 15:22:57 +08:00
HibiKier 2356527791 update word_clouds 2022-05-22 12:51:53 +08:00
HibiKier cab0f7b522 update change_pixiv_image_links 2022-05-22 12:49:32 +08:00
github-actions[bot] 8d3f101a68 Auto generate poetry.lock 2022-05-21 18:38:05 +00:00
AkashiCoin c8ac2b6281 Update Generate.yml 2022-05-22 02:35:20 +08:00
AkashiCoin d7d8efd305 Merge branch 'HibiKier:main' into main 2022-05-22 02:04:34 +08:00
HibiKier a4bc04c958 Update pid_search.py 2022-05-22 01:46:52 +08:00
AkashiCoin 5fc208c95a Create Generate.yml 2022-05-22 00:29:54 +08:00
HibiKier 02743d5955 Merge pull request #384 from AkashiCoin/main
Update anime.json of Kyomotoi/AnimeThesaurus
2022-05-21 23:40:13 +08:00
HibiKier a7ffebea35 Merge pull request #503 from yajiwa/main
修复命令不唯一的问题
2022-05-21 23:39:39 +08:00
HibiKier c511ef50a2 update wbtop 2022-05-21 23:34:48 +08:00
HibiKier 82902e0cde update invite_manager 2022-05-21 22:40:05 +08:00
AkashiCoin 1de5ae09bc Merge branch 'HibiKier:main' into main 2022-05-21 20:46:04 +08:00
yajiwa 8b735f1cb5 fix word_clouds 2022-05-21 20:08:53 +08:00
HibiKier 33d1334174 fix what_anime 2022-05-21 19:33:39 +08:00
HibiKier 324b58c21b update README.md 2022-05-21 16:42:19 +08:00
HibiKier b7b1651709 fix what_anime 2022-05-21 16:39:06 +08:00
HibiKier b5a4a6a9ff fix mute and open_case 2022-05-21 15:58:58 +08:00
HibiKier fe2c82b03c fix mute and open_case 2022-05-21 15:58:29 +08:00
HibiKier 81e4bca9ef fix mute 2022-05-21 13:46:29 +08:00
HibiKier c0d055b825 add get_message_img_file 2022-05-21 13:20:58 +08:00
HibiKier 188ae38525 fix bug 2022-05-21 13:15:53 +08:00
HibiKier 86a8fe7096 Merge pull request #462 from yajiwa/main
Update poetry file
2022-05-21 11:47:50 +08:00
yajiwa 0bb2b45f5c Update poetry.lock 2022-05-21 00:23:41 +08:00
yajiwa a17d8731c8 Update pyproject.toml 2022-05-21 00:22:44 +08:00
with9 9cdd2326c8 添加pixiv搜图多关键词支持;修复p站搜图数量参数问题 2022-05-20 19:35:18 +08:00
AkashiCoin d75653631d Merge branch 'HibiKier:main' into main 2022-05-19 23:21:02 +08:00
AkashiCoin e234c8906e Update anime.json 2022-05-19 23:20:00 +08:00
HibiKier 57baea18b5 Merge pull request #348 from sihuan/fix-bilibili_sub
Fix wrong live streamer name, fixes #284
2022-05-19 22:11:59 +08:00
HibiKier 0f3efe29c4 Merge pull request #357 from MingxuanGame/main
fix: mihoyo bbs api changed
2022-05-19 22:04:36 +08:00
HibiKier 89b87a38b3 Merge pull request #342 from yajiwa/main
fix bug
2022-05-19 21:03:23 +08:00
MingxuanGame c52b7ca2e9 fix: mihoyo bbs api changed 2022-05-19 17:47:20 +08:00
SiHuan 371b55dc9e Fix wrong live streamer name, fixes #284 2022-05-19 16:03:33 +08:00
yajiwa 53e572353c fix bug 2022-05-19 15:14:20 +08:00
yajiwa 3ae71c74e9 x 2022-05-19 15:10:42 +08:00
HibiKier cb643c04f7 Merge pull request #265 from yajiwa/main
Add word_clouds
2022-05-19 09:27:54 +08:00
yajiwa faf9ee159b update wordclouds url 2022-05-18 23:10:12 +08:00
yajiwa ffb3b2d73e Add word_clouds 2022-05-18 20:31:14 +08:00
HibiKier ffcc327089 Merge pull request #252 from yajiwa/main
Add wordclouds file
2022-05-18 20:04:13 +08:00
yajiwa dfd5a6a86a Add wordclouds file 2022-05-18 18:45:48 +08:00
HibiKier d43f89b067 Update README.md 2022-05-17 19:52:33 +08:00
HibiKier f15c3ab6a2 Update README.md 2022-05-16 19:20:01 +08:00
HibiKier e27809298e Merge pull request #160 from yajiwa/yajiwa
update word_bank
2022-05-16 19:19:20 +08:00
HibiKier 4b3e28e14b fix shop setu 2022-05-15 21:10:35 +08:00
yajiwa 71ce9153ed no message 2022-05-14 15:54:10 +08:00
yajiwa 25d63966de update word_bank 2022-05-14 15:47:33 +08:00
yajiwa 98afbb54b6 add get imgfile 2022-05-14 15:41:44 +08:00
HibiKier 03a51ca5dd Update README.md 2022-05-14 14:48:11 +08:00
HibiKier 428481b2d5 Merge pull request #159 from noahzark/patch-2
修复B站动态生成失败的问题
2022-05-14 14:47:30 +08:00
Feliciano Long f87c60e6db 修复B站动态生成失败的问题
B站动态样式更改
1. card已变更为bili-dyn-list__item
2. 置顶消息变成了一个tag(此处存疑,暂未发现其他tag
2022-05-13 19:38:24 +08:00
HibiKier 6d824e38bc Update README.md 2022-05-11 22:45:20 +08:00
HibiKier f0fd5bfb9e Merge pull request #155 from AkashiCoin/main
fix: 更改p搜api,解决p搜无法使用的问题
2022-05-11 22:44:32 +08:00
HibiKier 33374df671 Update pyproject.toml 2022-05-10 22:25:43 +08:00
AkashiCoin c035b1b19c Update pid_search.py 2022-05-10 18:47:39 +08:00
HibiKier b3b09ed666 update v0.1.5.3 2022-05-09 21:42:24 +08:00
HibiKier 8029c00a02 Update README.md 2022-05-05 20:32:22 +08:00
HibiKier a2c0921013 Merge pull request #153 from NumberSir/main
修改bilibili_sub插件在windows平台下报错
2022-05-05 20:32:17 +08:00
Number_Sir 31cdabc229 修改bilibili_sub插件在windows平台下报错
改用bilireq库,同时补充部分bilireq暂无的方法如获取番剧、获取用户投稿视频
2022-05-04 17:02:56 +08:00
HibiKier 1059a0aae0 Update README.md 2022-05-03 15:40:19 +08:00
HibiKier e6576e7f40 Update README.md 2022-05-03 15:34:47 +08:00
HibiKier 5837144095 Update data_source.py 2022-05-03 15:31:34 +08:00
199 changed files with 5827 additions and 2906 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错误...
+38
View File
@@ -0,0 +1,38 @@
name: Generate poetry.lock
on:
push:
branches:
- "main"
paths:
- 'pyproject.toml'
jobs:
poetry_lock:
name: Generate
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python
uses: he0119/setup-python@main
with:
python-version: "3.9"
- name: poetry lock
run: |
rm -f poetry.lock
sed -i.bak "8,11d" pyproject.toml
poetry lock
mv pyproject.toml.bak pyproject.toml
# commit
- name: commit file
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add poetry.lock
git commit -m "Auto generate poetry.lock" -a
# push
- name: push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
+9
View File
@@ -0,0 +1,9 @@
### 系统版本:Ubuntu 20.04
### 真寻版本:0.1.5.3
### 错误截图
[img]
### 错误说明
发生了xx错误...
+1
View File
@@ -140,6 +140,7 @@ cython_debug/
test.py test.py
server_ip.py server_ip.py
game_utils.py
member_activity_handle.py member_activity_handle.py
Yu-Gi-Oh/ Yu-Gi-Oh/
csgo/ csgo/
+260 -13
View File
@@ -18,9 +18,10 @@
## 声明 ## 声明
此项目仅用于学习交流,请勿用于非法用途 此项目仅用于学习交流,请勿用于非法用途
## Gitee # Nonebot2
<img style="height: 200px;width: 200px;" src="https://camo.githubusercontent.com/0ef71e86056da694c540790aa4a4e314396884d6c4fdb95362a7538b27a1b034/68747470733a2f2f76322e6e6f6e65626f742e6465762f6c6f676f2e706e67">
# [Gitee](https://gitee.com/two_Dimension/zhenxun_bot) 非常 [ **[NICE](https://github.com/nonebot/nonebot2)** ] 的OneBot框架
## 未完成的文档 ## 未完成的文档
@@ -113,7 +114,7 @@
- [x] 获取b站视频封面 - [x] 获取b站视频封面
- [x] 通过PID获取图片 - [x] 通过PID获取图片
- [x] 功能统计可视化 - [x] 功能统计可视化
- [x] 词云
- [x] 关于 - [x] 关于
### 已实现的管理员功能 ### 已实现的管理员功能
@@ -234,25 +235,268 @@ python bot.py
## 使用Docker ## 使用Docker
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__ __Docker 单机版(仅真寻Bot)__
#### GitHub:[Sakuracio/zxenv](https://github.com/Sakuracio/zxenv) **点击下方的 GitHub 徽标查看教程**
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot) [![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 可能无法正常启动全量版容器**
## 更新 ## 更新
### 2022/5/3 \[v0.1.5.1] ### 2022/7/24 \[v0.1.6.2]
* 订阅up动态提供直链
### 2022/7/23
* 优化开箱次数判断
### 2022/7/16
* cos提供连发命令
* 修复B站视频解析中b23解析错误
### 2022/7/13
* B站订阅提供配置项`LIVE_MSG_AT_ALL`,`UP_MSG_AT_ALL`:控制UP动态投稿和直播是否AT全体
* 修改了Omega图库检测的数据库文件名
* game_utils提供了Game类
### 2022/7/7
* 微博热搜选择单条热搜时也会检测时效性 [@pull/891](https://github.com/HibiKier/zhenxun_bot/pull/891)
### 2022/7/4
* 修复商品未设置限购时无法购买
* 修复B站订阅UP动态 [@pull/886](https://github.com/HibiKier/zhenxun_bot/pull/886)
* 修复色图命令带tag时配置项`MAX_ONCE_NUM2FORWARD`无法生效
### 2022/7/3 \[v0.1.6.1]
* BagUser提供方法`check_props`方法,用于判断用户是否含有该道具并是否使用
* 优化商品显示图片,提供限制,限购,折扣提示
* 修复图库内图片无法被连续删除的问题 [@pull/879](https://github.com/HibiKier/zhenxun_bot/pull/879)
* 色图提供配置项`MAX_ONCE_NUM2FORWARD`:群聊中单次发送图片数量达到指定时使用合并转发
* 优化修复了商品修改命令
* B站订阅UP动态改为详情页截图
### 2022/6/28
* 修复色图插件api修改无法搜索图片 [@pull/866](https://github.com/HibiKier/zhenxun_bot/pull/866)
### 2022/6/26
* 替换了bt URL
* PIX当使用pid查询图片时,会发送该pid下所有图片
* 商店提供了每日购买次数限制
### 2022/6/24
* 对WSL虚拟机 代理 添加写法 [@pull/847](https://github.com/HibiKier/zhenxun_bot/pull/847)
### 2022/6/21
* update parse_bilibili [@pull/840](https://github.com/HibiKier/zhenxun_bot/pull/840)
### 2022/6/19 \[v0.1.6.0]
* 暂时使用hook修复webui中plugins2setting修改时会改变plugins2setting.cmd为字符串
* 修复原神树脂重复提醒的bug [@pull/828](https://github.com/HibiKier/zhenxun_bot/pull/828)
* 词条优化问题展示,修改含机器人昵称和@逻辑 [@pull/835](https://github.com/HibiKier/zhenxun_bot/pull/835)
### 2022/6/18
* 修复昵称系统`BLACK_WORD`为空时造成报错
* 修复特殊头像时背景透明化出错
* 修复text2image纯文本时换行时颜色不统一
* 优化webUI,当有插件出错时不会影响其他插件显示
* 优化Config类型注释 [@pull/830](https://github.com/HibiKier/zhenxun_bot/pull/830)
* 优化browser
### 2022/6/17
* 修复wordbank的一些小问题 @pull/820
### 2022/6/14
* AsyncHttpx提供可关闭 ssl 验证参数 [@pull/812](https://github.com/HibiKier/zhenxun_bot/pull/812)
* fix: 自动更新群组 [@pull/810](https://github.com/HibiKier/zhenxun_bot/pull/810)
* fix: 修复添加词条时对answer中图片的处理 [@pull/806](https://github.com/HibiKier/zhenxun_bot/pull/806)
* 修复pix中指定num无法生效
* 替换了bt URL
### 2022/6/13
* Windows 重启适配 [@pull/804](https://github.com/HibiKier/zhenxun_bot/pull/804)
* 色图等提供修改md5方法 [@pull/800](https://github.com/HibiKier/zhenxun_bot/pull/800)
* webui中token.json文件写入补充 [@pull/798](https://github.com/HibiKier/zhenxun_bot/pull/798)
* 修复识图某些图片可能会出错
### 2022/6/11
* pix当只有一个tag时且为数字时可以通过添加'#'防止判定为数量
### 2022/6/9
* 修复b站订阅同群二人以上相同订阅时发送多次信息
* 修复超级用户帮助中缺少了 ‘插件商店’ 相关帮助
* 昵称系统提供了详细帮助
### 2022/6/5 \[v0.1.5.9]
* webui修复plugin2setting中cmd从list转变为str
* 当命令`我的金币`被风控时将以图片形式发送
* fix gold_redbag [@pull/763](https://github.com/HibiKier/zhenxun_bot/pull/763)
* 金币红包功能增加更多封面 [@pull/764](https://github.com/HibiKier/zhenxun_bot/pull/764)
### 2022/6/3
* 插件仓库在已安装插件边上会提示\[已安装]
* 修复ShopRegister kwargs某些字段无效
* 调整了一下查看所有请求中的年龄绘制 [@pull/745](https://github.com/HibiKier/zhenxun_bot/pull/745)
* 修复原神树脂提醒bug [@pull/756](https://github.com/HibiKier/zhenxun_bot/pull/756)
### 2022/5/31
* 修复开启/关闭全部功能时帮助图片未重绘 [@pull/721](https://github.com/HibiKier/zhenxun_bot/pull/721)
* bot_friend_group将group_handle.修改为friend_handle. [@pull/711](https://github.com/HibiKier/zhenxun_bot/pull/711)
* 修复发红包图片背景未透明化;修复原神树脂提醒参数错误 [@pull/712](https://github.com/HibiKier/zhenxun_bot/pull/712)
* 修复抽卡插件:方舟更新UP池信息时,若公告的第一个池子过期会导致无法更新UP池信息 [@pull/707](https://github.com/HibiKier/zhenxun_bot/pull/707)
* 商店插件判断是否有requirements.txt文件 [@pull/705](https://github.com/HibiKier/zhenxun_bot/pull/705)
* 删除原神玩家查询api返回变更的多余键值
* 优化了text2image方法
### 2022/5/29 \[v0.1.5.8]
* 提供了真寻适配仓库的插件 安装/卸载 操作
* 暂时关闭了插件资源清空
* 通过指令安装插件时会在插件目录下生成plugin_info.json记录当前插件信息
### 2022/5/28
* 修复私聊无法添加昵称
* 修复原神玩家查询层岩巨渊地下矿区没开时报错
* 修复 ```休息吧``` 无法阻断戳一戳
* 当图库无图片时,戳一戳将略过发送图片
* 新增搜图提供配置项```ALLOW_GROUP_R18```:允许在群聊中使用r18参数
* 新增自动更新插件```UPDATE_REMIND```:新版本提醒,原配置项```AUTO_UPDATE_ZHENXUN```改为自动更新升级
* black_word新增当群权限为-1时不再检测该群
* 修复非超级用户绑定原神cookie会被black_word阻拦
* 修复微博热搜报错,发红包小bug [@pull/688](https://github.com/HibiKier/zhenxun_bot/pull/688)
* 更多的中文提示
### 2022/5/26
* 修复\[滴滴滴]会被转义成&#91;滴滴滴&#93;导致无法触发的问题
* 将一些错误以中文提示输出
* 更新BT搜索源地址 [@pull/668](https://github.com/HibiKier/zhenxun_bot/pull/668)
* 更新抽卡插件 [@pull/667](https://github.com/HibiKier/zhenxun_bot/pull/667)
### 2022/5/25
* 修复webui中CountLimit字段limit_type类型错误
* 修改nickname插件:一处文案错误,添加敏感词 [@pull/624](https://github.com/HibiKier/zhenxun_bot/pull/624)
* gamedraw的ba卡池搬运了过来并且进行了真寻的适配 [@pull/617](https://github.com/HibiKier/zhenxun_bot/pull/617)
* feat: stream downloading and progress [@pull/607](https://github.com/HibiKier/zhenxun_bot/pull/607)
* 修改翻译插件,添加缺失的冒号 [@pull/602](https://github.com/HibiKier/zhenxun_bot/pull/602)
* 修复碧蓝航线/明日方舟up池解析出错的问题 [@pull/610](https://github.com/HibiKier/zhenxun_bot/pull/602)
### 2022/5/24
* fix: 修正了签到时日期时间的显示不补齐零的bug (符合日期时间表示法 ISO 8601)[@pull/600](https://github.com/HibiKier/zhenxun_bot/pull/600)
* 更新"微博热搜"接口 [@pull/579](https://github.com/HibiKier/zhenxun_bot/pull/579)
* refactor&fix(manager): modify argument [@pull/576](https://github.com/HibiKier/zhenxun_bot/pull/576)
* 修复复读不能复读图片的问题 [@pull/573](https://github.com/HibiKier/zhenxun_bot/pull/573)
* 修复抽卡插件:方舟抽卡的抽取和显示问题 [@pull/581](https://github.com/HibiKier/zhenxun_bot/pull/581)
### 2022/5/23 \[v0.1.5.6]
* 修复"清除已删除插件数据" [@pull/545](https://github.com/HibiKier/zhenxun_bot/pull/545)
* 修复有置顶的up主B站动态获取失败 [@pull/552](https://github.com/HibiKier/zhenxun_bot/pull/552)
* 添加pixiv搜图多关键词支持;修复p站搜图数量参数问题 [@pull/441](https://github.com/HibiKier/zhenxun_bot/pull/441)
* 修复开箱更新价格错误传参
* 修复pix无法正确查询uid
* 新增色图插件添加配置项```ALLOW_GROUP_R18```:允许群聊中使用色图r
* 新增PIX插件添加配置项```ALLOW_GROUP_SETU```:允许非超级用户使用-s参数
* 新增PIX插件添加配置项```ALLOW_GROUP_R18```:允许非超级用户使用-r参数
### 2022/5/22 \[v0.1.5.4]
* 使用action自动更新poetry.lock [@pull/515](https://github.com/HibiKier/zhenxun_bot/pull/515)
* fix(bilibili_sub): card is None and timeout [@pull/516](https://github.com/HibiKier/zhenxun_bot/pull/516)
* 修复了epic有时获取新免费游戏消息时获取不到图片
* 修复好感度满时签到出错(虽然是不可能满的
* 修复原神资源图标下载路径错误
* 修复自动更新群组可能失败
### 2022/5/21
* 修复搜番无结果时报错无正确反馈
* 解锁了windows上无法使用playwright的限制
* 修复p搜对应pid有多张图时出错,改为连续发送图片
* 修复p搜对数字的错误判断
* 修复添加商品折扣无法正确添加
* 修复了bilibili订阅直播间订阅up名称不一致的问题
* 修复原神玩家查询没开地图时报错
* 最低priority修改为 999
* 修复刷屏检测失效
* 修复刷屏检测设置命令无法生效
* 优化刷屏显示设置禁言时长显示,并改为分钟
* 修复了多连开箱无法指定武器箱
* 修复识番链接无法正确获取
* 新增真寻入群时即刻刷新权限
* 提高了微博热搜截图的等待时间
### 2022/5/19
* fix: mihoyo bbs api changed [@pull/357](https://github.com/HibiKier/zhenxun_bot/pull/357)
* Add word_clouds [@pull/265](https://github.com/HibiKier/zhenxun_bot/pull/265)
* Fix wrong live streamer name [@pull/284](https://github.com/HibiKier/zhenxun_bot/pull/284)
### 2022/5/16
* 词条支持图片和@问题 [@pull/160](https://github.com/HibiKier/zhenxun_bot/pull/160)
### 2022/5/15
* 修复了商店商品无法正确添加
* 修复了多张色图无法正确发送
### 2022/5/14
* 修复B站动态生成失败的问题 [@pull/159](https://github.com/HibiKier/zhenxun_bot/pull/159)
### 2022/5/11
* fix: 更改p搜api,解决p搜无法使用的问题 [@pull/155](https://github.com/HibiKier/zhenxun_bot/pull/155)
### 2022/5/9 \[v0.1.5.3]
* 替换了疫情API
* 修复了私聊.ban/.unban出错
### 2022/5/5
* 修改bilibili_sub插件在windows平台下报错 [@pull/153](https://github.com/HibiKier/zhenxun_bot/pull/153)
### 2022/5/3 \[v0.1.5.2]
* 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数 * 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数
* 添加商品注册装饰器shop_register * 添加商品注册装饰器shop_register
* 修复商品函数kwargs无法获取参数值
### 2022/5/1 ### 2022/5/1
* 删除了`group_last_chat`插件(该功能可由`chat_history`替代 * 删除了`group_last_chat`插件(该功能可由`chat_history`替代
* 新增敏感词检测(全新反击系统,是时候重拳出击了 * 新增敏感词检测(全新反击系统,是时候重拳出击了
### 2022/4/26 \[v0.5.1.0] ### 2022/4/26
* 修复了群白名单无法正确添加 * 修复了群白名单无法正确添加
* 优化了管理员帮助图片,背景图层将位于最下层 * 优化了管理员帮助图片,背景图层将位于最下层
@@ -333,7 +577,7 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
* 修复点歌无法正确发送 * 修复点歌无法正确发送
* 修复我有一个朋友有时文本会包含CQ码 * 修复我有一个朋友有时文本会包含CQ码
* 修复群欢消息被动控制文本未删除 [@pull/124](https://github.com/HibiKier/zhenxun_bot/pull/124) * 修复群欢消息被动控制文本未删除 [@pull/124](https://github.com/HibiKier/zhenxun_bot/pull/124)
* message_builder.image不再提供参数:abspath * message_builder.image不再提供参数:abspath
### 2022/2/23 ### 2022/2/23
@@ -470,10 +714,13 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
__..... 更多更新信息请查看文档__ __..... 更多更新信息请查看文档__
## Todo ## Todo
- [ ] web管理 - [ ] web管理
## 爱发电
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
## 感谢 ## 感谢
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议 [botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
[Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台. [Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台.
@@ -487,4 +734,4 @@ __..... 更多更新信息请查看文档__
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件 [NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库 [Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人 [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.1 __version__: v0.1.6.2
@@ -118,6 +118,8 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
group_manager.unblock_plugin(f, group_id) group_manager.unblock_plugin(f, group_id)
else: else:
group_manager.block_plugin(f, group_id) group_manager.block_plugin(f, group_id)
if group_help_file.exists():
group_help_file.unlink()
return f"已 {status} 全部功能!" return f"已 {status} 全部功能!"
if cmd in [task_data[x] for x in task_data.keys()]: if cmd in [task_data[x] for x in task_data.keys()]:
type_ = "task" type_ = "task"
@@ -232,10 +234,7 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
_exist_member_list = [] _exist_member_list = []
# try: # try:
for user_info in _group_user_list: for user_info in _group_user_list:
if user_info["card"] == "": nickname = user_info["card"] or user_info["nickname"]
nickname = user_info["nickname"]
else:
nickname = user_info["card"]
async with db.transaction(): async with db.transaction():
# 更新权限 # 更新权限
if ( if (
@@ -321,3 +320,4 @@ def set_group_bot_status(group_id: int, status: bool) -> str:
# for x in group_manager.get_task_data(): # for x in group_manager.get_task_data():
# group_manager.close_group_task(group_id, x) # group_manager.close_group_task(group_id, x)
return "那我先睡觉了..." return "那我先睡觉了..."
@@ -2,6 +2,7 @@ from nonebot import on_command, on_notice
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
from ._data_source import update_member_info from ._data_source import update_member_info
__zx_plugin_name__ = "更新群组成员列表 [Admin]" __zx_plugin_name__ = "更新群组成员列表 [Admin]"
__plugin_usage__ = """ __plugin_usage__ = """
usage: usage:
+3 -3
View File
@@ -4,9 +4,8 @@ from nonebot import on_message
from services.log import logger from services.log import logger
from models.group_info import GroupInfo from models.group_info import GroupInfo
from models.friend_user import FriendUser from models.friend_user import FriendUser
from nonebot.adapters.onebot.v11.exception import ActionFailed from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import NICKNAME, Config from configs.config import NICKNAME, Config
from utils.manager import group_manager
from pathlib import Path from pathlib import Path
import shutil import shutil
@@ -42,7 +41,7 @@ Config.add_plugin_config(
) )
cx = on_message(priority=9, block=False) cx = on_message(priority=9999, block=False, rule=lambda: False)
# 早上好 # 早上好
@@ -107,6 +106,7 @@ async def _():
group_info["group_name"], group_info["group_name"],
group_info["max_member_count"], group_info["max_member_count"],
group_info["member_count"], group_info["member_count"],
1
) )
logger.info(f"自动更新群组 {g} 信息成功") logger.info(f"自动更新群组 {g} 信息成功")
except Exception as e: except Exception as e:
+6 -4
View File
@@ -125,11 +125,13 @@ async def _(
msg = arg.extract_plain_text().strip() msg = arg.extract_plain_text().strip()
if msg: if msg:
if str(event.user_id) in bot.config.superusers: if str(event.user_id) in bot.config.superusers:
if is_number(arg.extract_plain_text().strip().split()[0]): msg_splt = msg.split()
qq = int(msg[0]) if is_number(msg_splt[0]):
msg = msg[1:]
qq = int(msg_splt[0])
msg = msg_splt[1:]
if cmd in [".ban", "/ban"]: if cmd in [".ban", "/ban"]:
time = parse_ban_time(msg) time = parse_ban_time(" ".join(msg))
if isinstance(time, str): if isinstance(time, str):
await ban.finish(time) await ban.finish(time)
result = await a_ban(qq, time, str(qq), event, 9) result = await a_ban(qq, time, str(qq), event, 9)
+5 -12
View File
@@ -25,7 +25,9 @@ def parse_ban_time(msg: str) -> Union[int, str]:
return int(msg[0]) * 60 * 60 + int(msg[1]) * 60 return int(msg[0]) * 60 * 60 + int(msg[1]) * 60
async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None) -> str: async def a_ban(
qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None
) -> str:
""" """
ban ban
:param qq: qq :param qq: qq
@@ -38,7 +40,8 @@ async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_lev
ban_level = await LevelUser.get_user_level(event.user_id, event.group_id) ban_level = await LevelUser.get_user_level(event.user_id, event.group_id)
if await BanUser.ban(qq, ban_level, time): if await BanUser.ban(qq, ban_level, time):
logger.info( logger.info(
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time / 60} 分钟" f"USER {event.user_id} GROUP"
f" {event.group_id if isinstance(event, GroupMessageEvent) else ''} 将 USER {qq} 封禁 时长 {time / 60} 分钟"
) )
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!" result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
if time != -1: if time != -1:
@@ -57,13 +60,3 @@ async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_lev
time += " 分钟" time += " 分钟"
result = f"{user_name} 已在黑名单!预计 {time}后解封" result = f"{user_name} 已在黑名单!预计 {time}后解封"
return result return result
+3 -2
View File
@@ -2,6 +2,7 @@ from configs.config import Config
from models.chat_history import ChatHistory from models.chat_history import ChatHistory
from nonebot import on_message from nonebot import on_message
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from utils.utils import get_message_text
from ._rule import rule from ._rule import rule
@@ -22,10 +23,10 @@ chat_history = on_message(rule=rule, priority=1, block=False)
async def _(event: MessageEvent): async def _(event: MessageEvent):
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
await ChatHistory.add_chat_msg( await ChatHistory.add_chat_msg(
event.user_id, event.group_id, str(event.get_message()) event.user_id, event.group_id, str(event.get_message()), get_message_text(event.json())
) )
else: else:
await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message())) await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message()), get_message_text(event.json()))
# @test.handle() # @test.handle()
+20 -4
View File
@@ -1,15 +1,16 @@
from nonebot import on_notice, on_request from nonebot import on_notice, on_request
from configs.path_config import IMAGE_PATH, DATA_PATH from configs.path_config import IMAGE_PATH, DATA_PATH
from models.level_user import LevelUser
from utils.message_builder import image from utils.message_builder import image
from models.group_member_info import GroupInfoUser from models.group_member_info import GroupInfoUser
from datetime import datetime from datetime import datetime
from services.log import logger from services.log import logger
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
ActionFailed,
GroupIncreaseNoticeEvent, GroupIncreaseNoticeEvent,
GroupDecreaseNoticeEvent, GroupDecreaseNoticeEvent,
) )
from nonebot.adapters.onebot.v11.exception import ActionFailed
from utils.manager import group_manager, plugins2settings_manager, requests_manager from utils.manager import group_manager, plugins2settings_manager, requests_manager
from configs.config import NICKNAME from configs.config import NICKNAME
from models.group_info import GroupInfo from models.group_info import GroupInfo
@@ -96,6 +97,23 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
for plugin in data.keys(): 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) 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: else:
join_time = datetime.now() join_time = datetime.now()
user_info = await bot.get_group_member_info( user_info = await bot.get_group_member_info(
@@ -128,9 +146,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
msg = msg.replace("[at]", "") msg = msg.replace("[at]", "")
at_flag = True at_flag = True
if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists(): if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists():
img = image( img = image(DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg")
DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg"
)
if msg or img: if msg or img:
msg = msg.strip() + img msg = msg.strip() + img
msg = "\n" + msg if at_flag else msg msg = "\n" + msg if at_flag else msg
+3
View File
@@ -56,6 +56,9 @@ def _create_help_img(
for matcher in _matchers: for matcher in _matchers:
plugin_name = None plugin_name = None
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
if not _plugin:
logger.warning(f"获取 功能:{matcher.plugin_name} 失败...")
continue
_module = _plugin.module _module = _plugin.module
try: try:
plugin_name = _module.__getattribute__("__zx_plugin_name__") plugin_name = _module.__getattribute__("__zx_plugin_name__")
+12 -5
View File
@@ -1,6 +1,5 @@
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException 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.friend_user import FriendUser
from models.group_member_info import GroupInfoUser from models.group_member_info import GroupInfoUser
from models.bag_user import BagUser from models.bag_user import BagUser
@@ -23,6 +22,7 @@ from nonebot.typing import T_State
from typing import Optional from typing import Optional
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
ActionFailed,
MessageEvent, MessageEvent,
GroupMessageEvent, GroupMessageEvent,
PokeNotifyEvent, PokeNotifyEvent,
@@ -91,7 +91,10 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
except AttributeError: except AttributeError:
pass pass
# 群黑名单检测 群总开关检测 # 群黑名单检测 群总开关检测
if isinstance(event, GroupMessageEvent) or matcher.plugin_name == other_limit_plugins: if (
isinstance(event, GroupMessageEvent)
or matcher.plugin_name in other_limit_plugins
):
try: try:
if ( if (
group_manager.get_group_level(event.group_id) < 0 group_manager.get_group_level(event.group_id) < 0
@@ -106,7 +109,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
raise IgnoredException("功能总开关关闭状态") raise IgnoredException("功能总开关关闭状态")
except AttributeError: except AttributeError:
pass pass
if module in admin_manager.keys() and matcher.priority not in [1, 9]: if module in admin_manager.keys() and matcher.priority not in [1, 999]:
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
# 个人权限 # 个人权限
if ( if (
@@ -146,9 +149,13 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if event.is_tome(): if event.is_tome():
status_message_manager.add(event.user_id) status_message_manager.add(event.user_id)
raise IgnoredException("权限不足") raise IgnoredException("权限不足")
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]: if module in plugins2info_dict.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 (
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: if status_message_manager.get(event.group_id) is None:
status_message_manager.delete(event.group_id) status_message_manager.delete(event.group_id)
if plugins2info_dict[module]["level"] > group_manager.get_group_level( if plugins2info_dict[module]["level"] > group_manager.get_group_level(
+4 -4
View File
@@ -1,11 +1,11 @@
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
Event, Event,
MessageEvent, MessageEvent,
ActionFailed,
PokeNotifyEvent, PokeNotifyEvent,
GroupMessageEvent, GroupMessageEvent,
) )
@@ -31,7 +31,7 @@ _flmt = FreqLimiter(300)
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State): async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if ( if (
(isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent)) (isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent))
and matcher.priority not in [1, 9] and matcher.priority not in [1, 999]
) or matcher.plugin_name in other_limit_plugins: ) or matcher.plugin_name in other_limit_plugins:
try: try:
if ( if (
@@ -58,7 +58,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not static_flmt.check(event.user_id): if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中") raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id) static_flmt.start_cd(event.user_id)
if matcher.priority != 9: if matcher.priority != 999:
try: try:
ban_result = Config.get_config("hook", "BAN_RESULT") ban_result = Config.get_config("hook", "BAN_RESULT")
if ( if (
@@ -79,7 +79,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not static_flmt.check(event.user_id): if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中") raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id) static_flmt.start_cd(event.user_id)
if matcher.priority != 9: if matcher.priority != 999:
try: try:
ban_result = Config.get_config("hook", "BAN_RESULT") ban_result = Config.get_config("hook", "BAN_RESULT")
if ban_result and matcher.plugin_name not in ignore_rst_module: if ban_result and matcher.plugin_name not in ignore_rst_module:
+2 -2
View File
@@ -1,9 +1,9 @@
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
ActionFailed,
MessageEvent, MessageEvent,
GroupMessageEvent, GroupMessageEvent,
) )
@@ -25,7 +25,7 @@ _blmt = BanCheckLimiter(
async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State): async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State):
if not isinstance(event, MessageEvent): if not isinstance(event, MessageEvent):
return 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 state["_prefix"]["raw_command"]:
if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'): if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
if await BanUser.ban( if await BanUser.ban(
@@ -20,26 +20,36 @@ def init_none_plugin_count_manager():
""" """
清除已删除插件数据 清除已删除插件数据
""" """
modules = [x.module for x in get_matchers()] modules = [x.plugin_name for x in get_matchers()]
for module in none_plugin_count_manager.keys(): plugins_manager_list = list(plugins_manager.keys())
if module not in modules: for module in plugins_manager_list:
none_plugin_count_manager.add_count(module) if module not in modules or none_plugin_count_manager.check(module):
else:
none_plugin_count_manager.reset(module)
if none_plugin_count_manager.check(module):
try: try:
plugin_name = plugins_manager.get(module)["plugin_name"] plugin_name = plugins_manager.get(module)["plugin_name"]
except (AttributeError, KeyError): except (AttributeError, KeyError):
plugin_name = "" plugin_name = ""
try: if none_plugin_count_manager.check(module):
plugins2settings_manager.delete(module) try:
plugins2count_manager.delete(module) plugins2settings_manager.delete(module)
plugins2cd_manager.delete(module) plugins2settings_manager.save()
plugins2block_manager.delete(module) plugins2count_manager.delete(module)
plugins_manager.delete(module) plugins2count_manager.save()
resources_manager.remove_resource(module) plugins2cd_manager.delete(module)
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...") plugins2cd_manager.save()
except Exception as e: plugins2block_manager.delete(module)
logger.error( plugins2block_manager.save()
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}" 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} 插件疑似已删除,加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,当前次数:{none_plugin_count_manager._data[module]}")
else:
none_plugin_count_manager.reset(module)
none_plugin_count_manager.save()
@@ -3,6 +3,7 @@ from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import admin_manager, plugins_manager from utils.manager import admin_manager, plugins_manager
from configs.config import Config from configs.config import Config
from services.log import logger from services.log import logger
from utils.text_utils import prompt2cn
from utils.utils import get_matchers from utils.utils import get_matchers
from ruamel import yaml from ruamel import yaml
import nonebot import nonebot
@@ -56,7 +57,9 @@ def init_plugins_config(data_path):
_override=True, _override=True,
) )
else: else:
Config.add_plugin_config(matcher.plugin_name, key, plugin_configs[key]) Config.add_plugin_config(
matcher.plugin_name, key, plugin_configs[key]
)
else: else:
plugin_configs = _data[matcher.plugin_name] plugin_configs = _data[matcher.plugin_name]
for key in plugin_configs: for key in plugin_configs:
@@ -79,7 +82,10 @@ def init_plugins_config(data_path):
_data[plugin].yaml_set_start_comment(plugin_name, indent=2) _data[plugin].yaml_set_start_comment(plugin_name, indent=2)
# 初始化未设置的管理员权限等级 # 初始化未设置的管理员权限等级
for k, v in Config.get_admin_level_data(): for k, v in Config.get_admin_level_data():
admin_manager.set_admin_level(k, v) try:
admin_manager.set_admin_level(k, v)
except KeyError as e:
raise KeyError(f"{e} ****** 请检查是否有插件加载失败 ******")
# 存完插件基本设置 # 存完插件基本设置
with open(plugins2config_file, "w", encoding="utf8") as wf: with open(plugins2config_file, "w", encoding="utf8") as wf:
round_trip_dump( round_trip_dump(
@@ -96,14 +102,23 @@ def init_plugins_config(data_path):
for plugin in Config.keys(): for plugin in Config.keys():
_tmp_data[plugin] = {} _tmp_data[plugin] = {}
for k in Config[plugin].keys(): for k in Config[plugin].keys():
if _data.get(plugin) and k in _data[plugin].keys(): try:
Config.set_config(plugin, k, _data[plugin][k]) if _data.get(plugin) and k in _data[plugin].keys():
if level2module := Config.get_level2module(plugin, k): Config.set_config(plugin, k, _data[plugin][k])
try: if level2module := Config.get_level2module(plugin, k):
admin_manager.set_admin_level(level2module, _data[plugin][k]) try:
except KeyError: admin_manager.set_admin_level(
logger.warning(f"{level2module} 设置权限等级失败:{_data[plugin][k]}") level2module, _data[plugin][k]
_tmp_data[plugin][k] = Config.get_config(plugin, k) )
except KeyError:
logger.warning(
f"{level2module} 设置权限等级失败:{_data[plugin][k]}"
)
_tmp_data[plugin][k] = Config.get_config(plugin, k)
except AttributeError as e:
raise AttributeError(
f"{e}\n" + prompt2cn("可能为config.yaml配置文件填写不规范", 46)
)
Config.save() Config.save()
temp_file = Path() / "configs" / "temp_config.yaml" temp_file = Path() / "configs" / "temp_config.yaml"
try: try:
@@ -28,7 +28,7 @@ def init_plugins_cd_limit(data_path):
_module = _plugin.module _module = _plugin.module
plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__") plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
plugins2cd_manager.add_cd_limit( plugins2cd_manager.add_cd_limit(
matcher.plugin_name, data_dict=plugin_cd_limit matcher.plugin_name, **plugin_cd_limit
) )
except AttributeError: except AttributeError:
pass pass
@@ -76,7 +76,7 @@ def init_plugins_block_limit(data_path):
_module = _plugin.module _module = _plugin.module
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__") plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
plugins2block_manager.add_block_limit( plugins2block_manager.add_block_limit(
matcher.plugin_name, data_dict=plugin_block_limit matcher.plugin_name, **plugin_block_limit
) )
except AttributeError: except AttributeError:
pass pass
@@ -124,7 +124,7 @@ def init_plugins_count_limit(data_path):
_module = _plugin.module _module = _plugin.module
plugin_count_limit = _module.__getattribute__("__plugin_count_limit__") plugin_count_limit = _module.__getattribute__("__plugin_count_limit__")
plugins2count_manager.add_count_limit( plugins2count_manager.add_count_limit(
matcher.plugin_name, data_dict=plugin_count_limit matcher.plugin_name, **plugin_count_limit
) )
except AttributeError: except AttributeError:
pass pass
+2 -2
View File
@@ -1,6 +1,7 @@
from nonebot import on_request, on_message from nonebot import on_request, on_message
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
ActionFailed,
FriendRequestEvent, FriendRequestEvent,
GroupRequestEvent, GroupRequestEvent,
MessageEvent, MessageEvent,
@@ -8,7 +9,6 @@ from nonebot.adapters.onebot.v11 import (
from models.friend_user import FriendUser from models.friend_user import FriendUser
from datetime import datetime from datetime import datetime
from configs.config import NICKNAME, Config from configs.config import NICKNAME, Config
from nonebot.adapters.onebot.v11.exception import ActionFailed
from utils.manager import requests_manager from utils.manager import requests_manager
from models.group_info import GroupInfo from models.group_info import GroupInfo
from utils.utils import scheduler from utils.utils import scheduler
@@ -25,7 +25,7 @@ __plugin_configs__ = {
friend_req = on_request(priority=5, block=True) friend_req = on_request(priority=5, block=True)
group_req = on_request(priority=5, block=True) group_req = on_request(priority=5, block=True)
x = on_message(priority=9, block=False) x = on_message(priority=999, block=False, rule=lambda: False)
exists_data = {"private": {}, "group": {}} exists_data = {"private": {}, "group": {}}
+14 -7
View File
@@ -1,4 +1,4 @@
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message, MessageEvent
from nonebot import on_command from nonebot import on_command
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.rule import to_me from nonebot.rule import to_me
@@ -22,9 +22,15 @@ __plugin_des__ = "区区昵称,才不想叫呢!"
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"] __plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = "HibiKier" __plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["昵称", "昵称系统"],
}
__plugin_configs__ = { __plugin_configs__ = {
"BLACK_WORD": { "BLACK_WORD": {
"value": ["爸", "爹", "爷"], "value": ["爸", "爹", "爷", "父亲"],
"help": "昵称所屏蔽的关键词,会被替换为 *", "help": "昵称所屏蔽的关键词,会被替换为 *",
"default_value": None "default_value": None
} }
@@ -47,7 +53,7 @@ cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=Tru
@nickname.handle() @nickname.handle()
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()): async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip() msg = arg.extract_plain_text().strip()
if not msg: if not msg:
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True) await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
@@ -57,8 +63,9 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True) await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True)
_tmp = "" _tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD") black_word = Config.get_config("nickname", "BLACK_WORD")
for x in msg: if black_word:
_tmp += "*" if x in black_word else x for x in msg:
_tmp += "*" if x in black_word else x
msg = _tmp msg = _tmp
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
if await GroupInfoUser.set_group_member_nickname( if await GroupInfoUser.set_group_member_nickname(
@@ -73,7 +80,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..", f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住的{msg}的,放心吧", f"{NICKNAME}会好好记住{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.", f"好..好.,那窝以后就叫你{msg}了.",
] ]
) )
@@ -90,7 +97,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..", f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住的{msg}的,放心吧", f"{NICKNAME}会好好记住{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.", f"好..好.,那窝以后就叫你{msg}了.",
] ]
) )
+68
View File
@@ -0,0 +1,68 @@
from nonebot import on_command, on_regex
from .data_source import show_plugin_repo, install_plugin, uninstall_plugin, download_json
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import CommandArg
from utils.message_builder import image
from nonebot.permission import SUPERUSER
__zx_plugin_name__ = "插件商店 [Superuser]"
__plugin_usage__ = """
usage:
下载安装插件
指令:
查看插件仓库
更新插件仓库
安装插件 [name/id] (重新安装等同于更新)
卸载插件 [name/id]
""".strip()
__plugin_des__ = "从真寻适配仓库中下载插件"
__plugin_cmd__ = ["查看插件仓库", "更新插件仓库", "安装插件 [name/id]", "卸载插件 [name/id]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
show_repo = on_regex("^查看插件仓库$", priority=1, block=True, permission=SUPERUSER)
update_repo = on_regex("^更新插件仓库$", priority=1, block=True, permission=SUPERUSER)
install_plugin_matcher = on_command("安装插件", priority=1, block=True, permission=SUPERUSER)
uninstall_plugin_matcher = on_command("卸载插件", priority=1, block=True, permission=SUPERUSER)
@install_plugin_matcher.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
arg = arg.extract_plain_text().strip()
msg = await install_plugin(arg)
await install_plugin_matcher.send(msg)
@uninstall_plugin_matcher.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
arg = arg.extract_plain_text().strip()
msg = await uninstall_plugin(arg)
await install_plugin_matcher.send(msg)
@update_repo.handle()
async def _(bot: Bot, event: MessageEvent):
code = await download_json()
if code == 200:
await update_repo.finish("更新插件仓库信息成功!")
await update_repo.send("更新插件仓库信息失败!")
@show_repo.handle()
async def _(bot: Bot, event: MessageEvent):
msg = await show_plugin_repo()
if isinstance(msg, int):
await show_repo.finish("文件下载失败或解压失败..")
await show_repo.send(image(b64=msg))
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看插件仓库"
)
+198
View File
@@ -0,0 +1,198 @@
import os
import shutil
import zipfile
from pathlib import Path
from typing import Union, Tuple
from utils.manager import plugins_manager
import ujson as json
from services import logger
from utils.http_utils import AsyncHttpx
from configs.path_config import TEMP_PATH, DATA_PATH
from utils.image_utils import text2image, BuildImage
from utils.utils import is_number
path = DATA_PATH / "plugin_shop"
if not path.exists():
path.mkdir(parents=True, exist_ok=True)
repo_json_url = "https://github.com/zhenxun-org/nonebot_plugins_zhenxun_bot/archive/refs/heads/index.zip"
repo_zip_path = TEMP_PATH / "plugin_repo_json.zip"
plugin_json = path / "zhenxun_plugins.json"
extensive_plugin_path = Path() / "extensive_plugin"
path = DATA_PATH / "plugin_shop"
if not path.exists():
path.mkdir(parents=True, exist_ok=True)
if not extensive_plugin_path.exists():
extensive_plugin_path.mkdir(parents=True, exist_ok=True)
data = {}
async def install_plugin(name: str) -> str:
"""
安装插件
:param name: 插件名或下标
"""
try:
if is_number(name):
name, code = await get_plugin_name(int(name))
if code != 200:
return name
plugin_url = data[name]["download_url"]
url = (await AsyncHttpx.get(plugin_url)).headers.get("Location")
zip_file = TEMP_PATH / f"{name}.zip"
if zip_file.exists():
zip_file.unlink()
if await AsyncHttpx.download_file(url, zip_file):
logger.debug("开始解压插件压缩包...")
# 解压
zf = zipfile.ZipFile(zip_file, "r")
extract_path = TEMP_PATH / f"{name}"
if extract_path.exists():
shutil.rmtree(extract_path.absolute(), ignore_errors=True)
extract_path.mkdir(exist_ok=True, parents=True)
for file in zf.namelist():
zf.extract(file, extract_path)
zf.close()
logger.debug("解压插件压缩包完成...")
logger.debug("开始移动插件文件夹...")
if (extensive_plugin_path / f"{name}").exists():
logger.debug("extensive_plugin目录下文件夹已存在,删除该目录插件文件夹...")
shutil.rmtree(
(extensive_plugin_path / f"{name}").absolute(), ignore_errors=True
)
extract_path.rename(extensive_plugin_path / f"{name}")
tmp = ""
if "pyproject.toml" in os.listdir(extensive_plugin_path / f"{name}"):
tmp = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
os.system(
f"poetry run pip install -r {(extensive_plugin_path / f'{name}' / 'pyproject.toml').absolute()}"
)
elif "requirements.txt" in os.listdir(extensive_plugin_path / f"{name}"):
tmp = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
os.system(
f"poetry run pip install -r {(extensive_plugin_path / f'{name}' / 'requirements.txt').absolute()}"
)
with open(extensive_plugin_path / f"{name}" / "plugin_info.json", "w") as f:
json.dump(data[name], f, ensure_ascii=False, indent=4)
logger.debug("移动插件文件夹完成...")
logger.info(f"成功安装插件 {name} 成功!\n{tmp}")
return f"成功安装插件 {name},请重启真寻!"
except Exception as e:
logger.error(f"安装插件 {name} 失败 {type(e)}:{e}")
return f"安装插件 {name} 失败 {type(e)}:{e}"
async def uninstall_plugin(name: str) -> str:
"""
删除插件
:param name: 插件名或下标
"""
try:
if is_number(name):
name, code = await get_plugin_name(int(name))
if code != 200:
return name
if name not in os.listdir(extensive_plugin_path):
return f"未安装 {name} 插件!"
shutil.rmtree((extensive_plugin_path / name).absolute(), ignore_errors=True)
logger.info(f"插件 {name} 删除成功!")
return f"插件 {name} 删除成功!"
except Exception as e:
logger.error(f"删除插件 {name} 失败 {type(e)}:{e}")
return f"删除插件 {name} 失败 {type(e)}:{e}"
async def show_plugin_repo() -> Union[int, str]:
"""
获取插件仓库数据并格式化
"""
if not plugin_json.exists():
code = await download_json()
if code != 200:
return code
plugin_info = json.load(open(plugin_json, "r", encoding="utf8"))
load_plugin_list = plugins_manager.get_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_manager.get_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
+12
View File
@@ -108,6 +108,18 @@ async def _():
"ALTER TABLE genshin ADD bind_group Integer;", "ALTER TABLE genshin ADD bind_group Integer;",
"genshin" "genshin"
), # 新增原神群号绑定字段 ), # 新增原神群号绑定字段
(
"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: for sql in sql_str:
try: try:
+4
View File
@@ -77,7 +77,11 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
await BagUser.get_gold(event.user_id, event.group_id) await BagUser.get_gold(event.user_id, event.group_id)
) < goods.goods_price * num * goods.goods_discount: ) < goods.goods_price * num * goods.goods_discount:
await buy.finish("您的金币好像不太够哦", at_sender=True) await buy.finish("您的金币好像不太够哦", at_sender=True)
flag, n = await GoodsInfo.check_user_daily_purchase(goods, event.user_id, event.group_id, num)
if flag:
await buy.finish(f"该次购买将超过每日次数限制,目前该道具还可以购买{n}次哦", at_sender=True)
if await BagUser.buy_property(event.user_id, event.group_id, goods, num): if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
await GoodsInfo.add_user_daily_purchase(goods, event.user_id, event.group_id, num)
await buy.send( await buy.send(
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!", f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
at_sender=True, at_sender=True,
+7 -2
View File
@@ -1,9 +1,10 @@
from nonebot import on_command from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, ActionFailed
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot.adapters.onebot.v11.permission import GROUP from nonebot.adapters.onebot.v11.permission import GROUP
from utils.data_utils import init_rank from utils.data_utils import init_rank
from models.bag_user import BagUser from models.bag_user import BagUser
from utils.image_utils import text2image
from utils.message_builder import image from utils.message_builder import image
from utils.utils import is_number from utils.utils import is_number
@@ -34,7 +35,11 @@ gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP)
@my_gold.handle() @my_gold.handle()
async def _(event: GroupMessageEvent): 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() @gold_rank.handle()
+15 -3
View File
@@ -1,10 +1,10 @@
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info, GoodsInfo
from nonebot.adapters.onebot.v11 import MessageEvent, Message from nonebot.adapters.onebot.v11 import MessageEvent, Message
from nonebot import on_command from nonebot import on_command
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from utils.message_builder import image from utils.message_builder import image
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from utils.utils import is_number from utils.utils import is_number, scheduler
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot.plugin import export from nonebot.plugin import export
from services.log import logger from services.log import logger
@@ -128,6 +128,18 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True) await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功") logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功")
else: 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} 失败") logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败")
@scheduler.scheduled_job(
"cron",
hour=0,
minute=0,
)
async def _():
try:
await GoodsInfo.reset_daily_purchase()
logger.info("商品每日限购次数重置成功...")
except Exception as e:
logger.error(f"商品每日限购次数重置发生错误 {type(e)}:{e}")
+107 -49
View File
@@ -1,9 +1,11 @@
from PIL import Image
from models.goods_info import GoodsInfo from models.goods_info import GoodsInfo
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
from models.sign_group_user import SignGroupUser from models.sign_group_user import SignGroupUser
from utils.utils import is_number from utils.utils import is_number
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from typing import Optional, Union from typing import Optional, Union, Tuple
from configs.config import Config from configs.config import Config
from nonebot import Driver from nonebot import Driver
from nonebot.plugin import require from nonebot.plugin import require
@@ -13,6 +15,7 @@ import time
driver: Driver = nonebot.get_driver() driver: Driver = nonebot.get_driver()
use = require("use") use = require("use")
@@ -31,6 +34,7 @@ async def init_default_shop_goods():
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)", "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
), ),
load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"), load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
daily_limit=(10, 20, 30),
** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3}, ** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
) )
async def sign_card(user_id: int, group_id: int, prob: float): async def sign_card(user_id: int, group_id: int, prob: float):
@@ -61,8 +65,9 @@ async def create_shop_help() -> str:
_list.append(goods) _list.append(goods)
A = BuildImage(1000, h, color="#f9f6f2") A = BuildImage(1000, h, color="#f9f6f2")
current_h = 0 current_h = 0
total_n = 0
for goods in _list: for goods in _list:
bk = BuildImage(700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf") bk = BuildImage(1180, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
goods_image = BuildImage( goods_image = BuildImage(
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf" 600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
) )
@@ -74,16 +79,27 @@ async def create_shop_help() -> str:
) )
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5) await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
await name_image.atext((390, 0), "售价:", center_type="by_height") await name_image.atext((390, 0), "售价:", center_type="by_height")
await name_image.atext( if goods.goods_discount != 1:
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height" 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( await name_image.atext(
( (
440 440
+ BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w, + BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w,
0, 0,
), ),
" 金币", f" 金币",
center_type="by_height", center_type="by_height",
) )
await name_image.acircle_corner(5) await name_image.acircle_corner(5)
@@ -91,15 +107,18 @@ async def create_shop_help() -> str:
await goods_image.atext((15, 50), f"简介:{goods.goods_description}") await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
await goods_image.acircle_corner(20) await goods_image.acircle_corner(20)
await bk.apaste(goods_image, alpha=True) await bk.apaste(goods_image, alpha=True)
n = 0
_w = 550
# 添加限时图标和时间 # 添加限时图标和时间
if goods.goods_limit_time > 0: if goods.goods_limit_time > 0:
n += 140
_limit_time_logo = BuildImage( _limit_time_logo = BuildImage(
40, 40, background=f"{IMAGE_PATH}/other/time.png" 40, 40, background=f"{IMAGE_PATH}/other/time.png"
) )
await bk.apaste(_limit_time_logo, (600, 0), True) await bk.apaste(_limit_time_logo, (_w + 50, 0), True)
await bk.apaste( await bk.apaste(
BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"), BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"),
(640, 10), (_w + 90, 10),
True, True,
) )
limit_time = time.strftime( limit_time = time.strftime(
@@ -108,28 +127,66 @@ async def create_shop_help() -> str:
y_m_d = limit_time[0] y_m_d = limit_time[0]
_h_m = limit_time[1].split(":") _h_m = limit_time[1].split(":")
h_m = _h_m[0] + "时 " + _h_m[1] + "分" h_m = _h_m[0] + "时 " + _h_m[1] + "分"
await bk.atext((605, 38), str(y_m_d)) await bk.atext((_w + 55, 38), str(y_m_d))
await bk.atext((615, 57), str(h_m)) await bk.atext((_w + 65, 57), str(h_m))
await bk.aline((550, -1, 710, -1), "#a29ad6", 5) _w += 140
await bk.aline((550, 80, 710, 80), "#a29ad6", 5) 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((550, -1, 550 + n, -1), "#a29ad6", 5)
await bk.aline((550, 80, 550 + n, 80), "#a29ad6", 5)
# 添加限时图标和时间
idx += 1 idx += 1
await A.apaste(bk, (0, current_h), True) await A.apaste(bk, (0, current_h), True)
current_h += 90 current_h += 90
w = 1000 w = 850
if total_n:
w += total_n
h = A.h + 230 + 100 h = A.h + 230 + 100
h = 1000 if h < 1000 else h h = 1000 if h < 1000 else h
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png") shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
shop = BuildImage(w, h, font_size=20, color="#f9f6f2") 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_3.png")
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan.png") zx_img.transpose(Image.FLIP_LEFT_RIGHT)
zx_img.replace_color_tran(((240, 240, 240), (255, 255, 255)), (249, 246, 242)) 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) await shop.apaste(shop_logo, (450, 30), True)
shop.text( shop.text(
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170), (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() return shop.pic2bs4()
@@ -139,8 +196,8 @@ async def register_goods(
des: str, des: str,
discount: Optional[float] = 1, discount: Optional[float] = 1,
limit_time: Optional[int] = 0, limit_time: Optional[int] = 0,
**kwargs, daily_limit: Optional[int] = 0,
): ) -> bool:
""" """
添加商品 添加商品
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时 例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
@@ -151,26 +208,21 @@ async def register_goods(
:param des: 商品简介 :param des: 商品简介
:param discount: 商品折扣 :param discount: 商品折扣
:param limit_time: 商品限时销售时间,单位为小时 :param limit_time: 商品限时销售时间,单位为小时
:param kwargs: kwargs :param daily_limit: 每日购买次数限制
:return: 是否添加成功 :return: 是否添加成功
""" """
if kwargs: if not await GoodsInfo.get_goods_info(name):
name = kwargs.get("name")
price = kwargs.get("price")
des = kwargs.get("des")
discount = kwargs.get("discount")
limit_time = kwargs.get("time_limit")
if await GoodsInfo.get_goods_info(name):
limit_time = float(limit_time) if limit_time else limit_time limit_time = float(limit_time) if limit_time else limit_time
discount = discount if discount is None else 1 discount = discount if discount is not None else 1
limit_time = ( limit_time = (
int(time.time() + limit_time * 60 * 60) int(time.time() + limit_time * 60 * 60)
if limit_time is not None and limit_time != 0 if limit_time is not None and limit_time != 0
else 0 else 0
) )
return await GoodsInfo.add_goods( return await GoodsInfo.add_goods(
name, int(price), des, float(discount), limit_time name, int(price), des, float(discount), limit_time, daily_limit
) )
return False
# 删除商品 # 删除商品
@@ -198,7 +250,7 @@ async def delete_goods(name: str, id_: int) -> "str, str, int":
# 更新商品信息 # 更新商品信息
async def update_goods(**kwargs) -> "str, str, int": async def update_goods(**kwargs) -> Tuple[bool, str, str]:
""" """
更新商品信息 更新商品信息
:param kwargs: kwargs :param kwargs: kwargs
@@ -208,17 +260,18 @@ async def update_goods(**kwargs) -> "str, str, int":
goods_lst = await GoodsInfo.get_all_goods() goods_lst = await GoodsInfo.get_all_goods()
if is_number(kwargs["name"]): if is_number(kwargs["name"]):
if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst): if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst):
return "序号错误,没有该序号的商品...", "", 999 return False, "序号错误,没有该序号的商品...", ""
goods = goods_lst[int(kwargs["name"]) - 1] goods = goods_lst[int(kwargs["name"]) - 1]
else: else:
goods = await GoodsInfo.get_goods_info(kwargs["name"]) goods = await GoodsInfo.get_goods_info(kwargs["name"])
if not goods: if not goods:
return "名称错误,没有该名称的商品...", "", 999 return False, "名称错误,没有该名称的商品...", ""
name = goods.goods_name name: str = goods.goods_name
price = goods.goods_price price = goods.goods_price
des = goods.goods_description des = goods.goods_description
discount = goods.goods_discount discount = goods.goods_discount
limit_time = goods.goods_limit_time limit_time = goods.goods_limit_time
daily_limit = goods.daily_limit
new_time = 0 new_time = 0
tmp = "" tmp = ""
if kwargs.get("price"): if kwargs.get("price"):
@@ -235,24 +288,25 @@ async def update_goods(**kwargs) -> "str, str, int":
new_time = time.strftime( new_time = time.strftime(
"%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M:%S",
time.localtime(time.time() + kwargs["limit_time"] * 60 * 60), 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"] limit_time = kwargs["limit_time"]
return ( if kwargs.get("daily_limit"):
await GoodsInfo.update_goods( tmp += f'每日购买限制:{daily_limit} --> {kwargs["daily_limit"]}\n' if daily_limit else "取消了购买限制\n"
name, daily_limit = int(kwargs["daily_limit"])
int(price), await GoodsInfo.update_goods(
des,
float(discount),
int(
time.time() + limit_time * 60 * 60
if limit_time != 0 and new_time
else 0
),
),
name, name,
tmp[:-1], int(price),
des,
float(discount),
int(
time.time() + limit_time * 60 * 60
if limit_time != 0 and new_time
else 0
),
daily_limit
) )
return True, name, tmp[:-1],
def parse_goods_info(msg: str) -> Union[dict, str]: def parse_goods_info(msg: str) -> Union[dict, str]:
@@ -282,6 +336,10 @@ def parse_goods_info(msg: str) -> Union[dict, str]:
data["discount"] = sp[1] data["discount"] = sp[1]
elif sp[0] == "limit_time": elif sp[0] == "limit_time":
if not is_number(sp[1]) or float(sp[1]) < 0: if not is_number(sp[1]) or float(sp[1]) < 0:
return "limit_time参数不合法,必须大于0!" return "limit_time参数不合法,必须为数字且大于0!"
data["limit_time"] = sp[1] 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 return data
+4 -5
View File
@@ -26,7 +26,7 @@ class GoodsUseFuncManager:
判断商品使用方法是否被注册 判断商品使用方法是否被注册
:param goods_name: 商品名称 :param goods_name: 商品名称
""" """
return bool(self._data.get(goods_name)) return bool(self ._data.get(goods_name))
def get_max_num_limit(self, goods_name: str) -> int: def get_max_num_limit(self, goods_name: str) -> int:
""" """
@@ -61,16 +61,15 @@ class GoodsUseFuncManager:
return param_list_ return param_list_
goods_name = param.goods_name goods_name = param.goods_name
if self.exists(goods_name): if self.exists(goods_name):
if args := inspect.signature(self._data[goods_name]["func"]).parameters: args = inspect.signature(self._data[goods_name]["func"]).parameters
print(parse_args(args)) if args and list(args.keys())[0] != "kwargs":
print(kwargs)
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]): if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
return await self._data[goods_name]["func"]( return await self._data[goods_name]["func"](
*parse_args(args) *parse_args(args)
) )
else: else:
return self._data[goods_name]["func"]( return self._data[goods_name]["func"](
**kwargs, *parse_args(args)
) )
else: else:
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]): if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
+6 -6
View File
@@ -119,18 +119,18 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
) )
flag = await requests_manager.approve(bot, id_, "group") flag = await requests_manager.approve(bot, id_, "group")
else: else:
await friend_handle.send("同意群聊请求失败,未找到此id的请求..") await group_handle.send("同意群聊请求失败,未找到此id的请求..")
else: else:
flag = await requests_manager.refused(bot, id_, "group") flag = await requests_manager.refused(bot, id_, "group")
if flag == 1: if flag == 1:
await friend_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..") await group_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..")
requests_manager.delete_request(id_, "group") requests_manager.delete_request(id_, "group")
elif flag == 2: elif flag == 2:
await friend_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..") await group_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..")
else: else:
await friend_handle.send(f"{cmd[:2]}群聊请求成功!") await group_handle.send(f"{cmd[:2]}群聊请求成功!")
else: else:
await friend_handle.send("id必须为纯数字!") await group_handle.send("id必须为纯数字!")
@cls_request.handle() @cls_request.handle()
@@ -150,4 +150,4 @@ async def _():
@clear_request.handle() @clear_request.handle()
async def _(): async def _():
requests_manager.clear() requests_manager.clear()
await cls_request.send("已清空所有好友/群聊请求..") await clear_request.send("已清空所有好友/群聊请求..")
+12 -12
View File
@@ -1,4 +1,11 @@
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GROUP, GroupMessageEvent, Message from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent,
GROUP,
GroupMessageEvent,
Message,
ActionFailed,
)
from nonebot import on_command, on_regex from nonebot import on_command, on_regex
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.typing import T_State from nonebot.typing import T_State
@@ -8,7 +15,6 @@ from utils.manager import group_manager, plugins2settings_manager
from models.group_info import GroupInfo from models.group_info import GroupInfo
from services.log import logger from services.log import logger
from configs.config import NICKNAME from configs.config import NICKNAME
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.params import Command, CommandArg from nonebot.params import Command, CommandArg
from typing import Tuple from typing import Tuple
@@ -92,7 +98,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
level = 0 level = 0
if not msg: if not msg:
await add_group_level.finish("用法:修改群权限 [group] [level]") await add_group_level.finish("用法:修改群权限 [group] [level]")
msg = msg.split(" ") msg = msg.split()
if len(msg) < 2: if len(msg) < 2:
await add_group_level.finish("参数不完全..[group] [level]") await add_group_level.finish("参数不完全..[group] [level]")
if is_number(msg[0]) and is_number(msg[1]): if is_number(msg[0]) and is_number(msg[1]):
@@ -137,9 +143,7 @@ async def _():
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0] cmd = cmd[0]
msg = arg.extract_plain_text().strip().split() msg = arg.extract_plain_text().strip().split()
all_group = [ all_group = [g["group_id"] for g in await bot.get_group_list()]
g["group_id"] for g in await bot.get_group_list()
]
group_list = [] group_list = []
for group in msg: for group in msg:
if is_number(group) and int(group) in all_group: if is_number(group) and int(group) in all_group:
@@ -151,9 +155,7 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
else: else:
group_manager.delete_group_white_list(group) group_manager.delete_group_white_list(group)
group_list = [str(x) for x in group_list] group_list = [str(x) for x in group_list]
await manager_group_whitelist.send( await manager_group_whitelist.send("已成功将 " + "\n".join(group_list) + " " + cmd)
"已成功将 " + "\n".join(group_list) + " " + cmd
)
else: else:
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名") await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
@@ -199,6 +201,4 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
else: else:
if await GroupInfo.get_group_info(group_id): if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 0) await GroupInfo.set_group_flag(group_id, 0)
await group_auth.send( await group_auth.send(f"已为 {group_id} {cmd[:2]}群认证..")
f'已为 {group_id} {cmd[:2]}群认证..'
)
@@ -45,6 +45,7 @@ async def _():
group_info["group_name"], group_info["group_name"],
group_info["max_member_count"], group_info["max_member_count"],
group_info["member_count"], group_info["member_count"],
1
): ):
num += 1 num += 1
logger.info(f"自动更新群组 {g} 信息成功") logger.info(f"自动更新群组 {g} 信息成功")
+1
View File
@@ -12,6 +12,7 @@ driver.on_shutdown(disconnect)
nonebot.load_plugin("nonebot_plugin_apscheduler") nonebot.load_plugin("nonebot_plugin_apscheduler")
nonebot.load_plugins("basic_plugins") nonebot.load_plugins("basic_plugins")
nonebot.load_plugins("plugins") nonebot.load_plugins("plugins")
nonebot.load_plugins("extensive_plugin")
# 最后加载权限控制 # 最后加载权限控制
nonebot.load_plugins("basic_plugins/hooks") nonebot.load_plugins("basic_plugins/hooks")
+5
View File
@@ -2,6 +2,10 @@ from typing import Optional
from pathlib import Path from pathlib import Path
from .utils import ConfigsManager from .utils import ConfigsManager
import platform
if platform.system() == "Linux":
import os
hostip = os.popen("cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }'").read().replace("\n","")
# 回复消息名称 # 回复消息名称
NICKNAME: str = "小真寻" NICKNAME: str = "小真寻"
@@ -18,6 +22,7 @@ port: str = "" # 数据库端口
database: str = "" # 数据库名称 database: str = "" # 数据库名称
# 代理,例如 "http://127.0.0.1:7890" # 代理,例如 "http://127.0.0.1:7890"
# 如果是WLS 可以 f"http://{hostip}:7890" 使用寄主机的代理
SYSTEM_PROXY: Optional[str] = None # 全局代理 SYSTEM_PROXY: Optional[str] = None # 全局代理
+34 -8
View File
@@ -2,6 +2,7 @@ from typing import Optional, Any, Union
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel.yaml import YAML
from ruamel import yaml from ruamel import yaml
from ruamel.yaml.scanner import ScannerError
class ConfigsManager: class ConfigsManager:
@@ -21,9 +22,24 @@ class ConfigsManager:
if file.exists(): if file.exists():
with open(file, "r", encoding="utf8") as f: with open(file, "r", encoding="utf8") as f:
self._data = _yaml.load(f) self._data = _yaml.load(f)
if not self._data:
self.file.unlink()
raise ValueError(
"配置文件为空!\n"
"***********************************************************\n"
"****** 配置文件 plugins2config.yaml 为空,已删除,请重启 ******\n"
"***********************************************************"
)
if self._simple_file.exists(): if self._simple_file.exists():
with open(self._simple_file, "r", encoding="utf8") as f: try:
self._simple_data = _yaml.load(f) 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( def add_plugin_config(
self, self,
@@ -78,18 +94,22 @@ class ConfigsManager:
del self._data[module] del self._data[module]
self.save() self.save()
def set_config(self, module: str, key: str, value: str): def set_config(self, module: str, key: str, value: Any , save_simple_data: bool = False):
""" """
设置配置值 设置配置值
:param module: 模块名 :param module: 模块名
:param key: 配置名称 :param key: 配置名称
:param value: 值 :param value: 值
:param save_simple_data: 同时保存至config.yaml
""" """
if module in self._data.keys(): if module in self._data.keys():
if self._data[module].get(key) is not None and self._data[module][key] != value: if (
self._data[module].get(key) is not None
and self._data[module][key] != value
):
self._data[module][key]["value"] = value self._data[module][key]["value"] = value
self._simple_data[module][key] = value self._simple_data[module][key] = value
self.save() self.save(save_simple_data = save_simple_data)
def set_help(self, module: str, key: str, help_: str): def set_help(self, module: str, key: str, help_: str):
""" """
@@ -103,7 +123,7 @@ class ConfigsManager:
self._data[module][key]["help"] = help_ self._data[module][key]["help"] = help_
self.save() self.save()
def set_default_value(self, module: str, key: str, value: str): def set_default_value(self, module: str, key: str, value: Any):
""" """
设置配置默认值 设置配置默认值
:param module: 模块名 :param module: 模块名
@@ -115,7 +135,9 @@ class ConfigsManager:
self._data[module][key]["default_value"] = value self._data[module][key]["default_value"] = value
self.save() 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 module: 模块名
@@ -161,7 +183,11 @@ class ConfigsManager:
if save_simple_data: if save_simple_data:
with open(self._simple_file, "w", encoding="utf8") as f: with open(self._simple_file, "w", encoding="utf8") as f:
yaml.dump( 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 if path else self.file
with open(path, "w", encoding="utf8") as f: with open(path, "w", encoding="utf8") as f:
+1450 -155
View File
File diff suppressed because it is too large Load Diff
+19 -19
View File
@@ -22,9 +22,9 @@ class BagUser(db.Model):
@classmethod @classmethod
async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str: async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
""" """
说明: 说明:
获取金币概况 获取金币概况
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 所在群号 :param group_id: 所在群号
""" """
@@ -44,9 +44,9 @@ class BagUser(db.Model):
@classmethod @classmethod
async def get_gold(cls, user_qq: int, group_id: int) -> int: async def get_gold(cls, user_qq: int, group_id: int) -> int:
""" """
说明: 说明:
获取当前金币 获取当前金币
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 所在群号 :param group_id: 所在群号
""" """
@@ -64,9 +64,9 @@ class BagUser(db.Model):
@classmethod @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) -> Dict[str, int]:
""" """
说明: 说明:
获取当前道具 获取当前道具
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 所在群号 :param group_id: 所在群号
""" """
@@ -84,9 +84,9 @@ class BagUser(db.Model):
@classmethod @classmethod
async def add_gold(cls, user_qq: int, group_id: int, num: int): async def add_gold(cls, user_qq: int, group_id: int, num: int):
""" """
说明: 说明:
增加金币 增加金币
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 所在群号 :param group_id: 所在群号
:param num: 金币数量 :param num: 金币数量
@@ -112,9 +112,9 @@ class BagUser(db.Model):
@classmethod @classmethod
async def spend_gold(cls, user_qq: int, group_id: int, num: int): async def spend_gold(cls, user_qq: int, group_id: int, num: int):
""" """
说明: 说明:
花费金币 花费金币
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 所在群号 :param group_id: 所在群号
:param num: 金币数量 :param num: 金币数量
@@ -140,9 +140,9 @@ class BagUser(db.Model):
@classmethod @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):
""" """
说明: 说明:
增加道具 增加道具
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 所在群号 :param group_id: 所在群号
:param name: 道具名称 :param name: 道具名称
@@ -165,9 +165,9 @@ class BagUser(db.Model):
cls, user_qq: int, group_id: int, name: str, num: int = 1 cls, user_qq: int, group_id: int, name: str, num: int = 1
) -> bool: ) -> bool:
""" """
说明: 说明:
使用/删除 道具 使用/删除 道具
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 所在群号 :param group_id: 所在群号
:param name: 道具名称 :param name: 道具名称
@@ -192,9 +192,9 @@ class BagUser(db.Model):
cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int
) -> bool: ) -> bool:
""" """
说明: 说明:
购买道具 购买道具
参数: 参数:
:param user_qq: 用户qq :param user_qq: 用户qq
:param group_id: 所在群聊 :param group_id: 所在群聊
:param goods: 商品 :param goods: 商品
@@ -209,14 +209,14 @@ class BagUser(db.Model):
return True return True
except Exception as e: except Exception as e:
logger.error(f"buy_property 发生错误 {type(e)}:{e}") logger.error(f"buy_property 发生错误 {type(e)}:{e}")
return False return False
@classmethod @classmethod
async def get_all_users(cls, group_id: Optional[int] = None) -> List["BagUser"]: async def get_all_users(cls, group_id: Optional[int] = None) -> List["BagUser"]:
""" """
说明: 说明:
获取所有用户数据 获取所有用户数据
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
if not group_id: if not group_id:
+12 -12
View File
@@ -15,9 +15,9 @@ class BanUser(db.Model):
@classmethod @classmethod
async def check_ban_level(cls, user_qq: int, level: int) -> bool: async def check_ban_level(cls, user_qq: int, level: int) -> bool:
""" """
说明: 说明:
检测ban掉目标的用户与unban用户的权限等级大小 检测ban掉目标的用户与unban用户的权限等级大小
参数: 参数:
:param user_qq: unban用户的qq号 :param user_qq: unban用户的qq号
:param level: ban掉目标用户的权限等级 :param level: ban掉目标用户的权限等级
""" """
@@ -31,9 +31,9 @@ class BanUser(db.Model):
@classmethod @classmethod
async def check_ban_time(cls, user_qq: int) -> str: async def check_ban_time(cls, user_qq: int) -> str:
""" """
说明: 说明:
检测用户被ban时长 检测用户被ban时长
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
""" """
query = cls.query.where((cls.user_qq == user_qq)) query = cls.query.where((cls.user_qq == user_qq))
@@ -49,9 +49,9 @@ class BanUser(db.Model):
@classmethod @classmethod
async def is_ban(cls, user_qq: int) -> bool: async def is_ban(cls, user_qq: int) -> bool:
""" """
说明: 说明:
判断用户是否被ban 判断用户是否被ban
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
""" """
if await cls.check_ban_time(user_qq): if await cls.check_ban_time(user_qq):
@@ -63,9 +63,9 @@ class BanUser(db.Model):
@classmethod @classmethod
async def is_super_ban(cls, user_qq: int) -> bool: async def is_super_ban(cls, user_qq: int) -> bool:
""" """
说明: 说明:
判断用户是否被ban 判断用户是否被ban
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
""" """
user = await cls.query.where((cls.user_qq == user_qq)).gino.first() user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
@@ -77,9 +77,9 @@ class BanUser(db.Model):
@classmethod @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) -> bool:
""" """
说明: 说明:
ban掉目标用户 ban掉目标用户
参数: 参数:
:param user_qq: 目标用户qq号 :param user_qq: 目标用户qq号
:param ban_level: 使用ban命令用户的权限 :param ban_level: 使用ban命令用户的权限
:param duration: ban时长,秒 :param duration: ban时长,秒
@@ -104,9 +104,9 @@ class BanUser(db.Model):
@classmethod @classmethod
async def unban(cls, user_qq: int) -> bool: async def unban(cls, user_qq: int) -> bool:
""" """
说明: 说明:
unban用户 unban用户
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
""" """
query = cls.query.where((cls.user_qq == user_qq)) query = cls.query.where((cls.user_qq == user_qq))
+21 -21
View File
@@ -11,12 +11,13 @@ class ChatHistory(db.Model):
user_qq = db.Column(db.BigInteger(), nullable=False) user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger()) group_id = db.Column(db.BigInteger())
text = db.Column(db.Text()) text = db.Column(db.Text())
plain_text = db.Column(db.Text())
create_time = db.Column(db.DateTime(timezone=True), nullable=False) create_time = db.Column(db.DateTime(timezone=True), nullable=False)
@classmethod @classmethod
async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str): async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str, plain_text: str):
await cls.create( await cls.create(
user_qq=user_qq, group_id=group_id, text=text, create_time=datetime.now() user_qq=user_qq, group_id=group_id, text=text, plain_text=plain_text, create_time=datetime.now()
) )
@classmethod @classmethod
@@ -27,9 +28,9 @@ class ChatHistory(db.Model):
days: Optional[int] = None, days: Optional[int] = None,
) -> List["ChatHistory"]: ) -> List["ChatHistory"]:
""" """
说明: 说明:
获取用户消息 获取用户消息
参数: 参数:
:param uid: 用户qq :param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊 :param msg_type: 消息类型,私聊或群聊
:param days: 限制日期 :param days: 限制日期
@@ -45,9 +46,9 @@ class ChatHistory(db.Model):
date_scope: Tuple[datetime, datetime] = None, date_scope: Tuple[datetime, datetime] = None,
) -> List["ChatHistory"]: ) -> List["ChatHistory"]:
""" """
说明: 说明:
获取群聊指定用户聊天记录 获取群聊指定用户聊天记录
参数: 参数:
:param uid: qq :param uid: qq
:param gid: 群号 :param gid: 群号
:param limit: 获取数量 :param limit: 获取数量
@@ -62,9 +63,9 @@ class ChatHistory(db.Model):
@classmethod @classmethod
async def get_group_user_msg_count(cls, uid: int, gid: int) -> Optional[int]: async def get_group_user_msg_count(cls, uid: int, gid: int) -> Optional[int]:
""" """
说明: 说明:
查询群聊指定用户的聊天记录数量 查询群聊指定用户的聊天记录数量
参数: 参数:
:param uid: qq :param uid: qq
:param gid: 群号 :param gid: 群号
""" """
@@ -85,9 +86,9 @@ class ChatHistory(db.Model):
date_scope: Optional[Tuple[datetime, datetime]] = None, date_scope: Optional[Tuple[datetime, datetime]] = None,
) -> Optional[Tuple[int, int]]: ) -> Optional[Tuple[int, int]]:
""" """
说明: 说明:
获取排行数据 获取排行数据
参数: 参数:
:param gid: 群号 :param gid: 群号
:param limit: 获取数量 :param limit: 获取数量
:param order: 排序类型,desc,des :param order: 排序类型,desc,des
@@ -97,15 +98,14 @@ class ChatHistory(db.Model):
if date_scope: if date_scope:
sql += f"AND create_time BETWEEN '{date_scope[0]}' AND '{date_scope[1]}' " 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}" 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)) return await db.all(db.text(sql))
@classmethod @classmethod
async def get_group_first_msg_datetime(cls, gid: int) -> Optional[datetime]: async def get_group_first_msg_datetime(cls, gid: int) -> Optional[datetime]:
""" """
说明: 说明:
获取群第一条记录消息时间 获取群第一条记录消息时间
参数: 参数:
:param gid: :param gid:
""" """
if ( if (
@@ -124,9 +124,9 @@ class ChatHistory(db.Model):
days: Optional[int] = None, days: Optional[int] = None,
) -> int: ) -> int:
""" """
说明: 说明:
获取用户消息数量 获取用户消息数量
参数: 参数:
:param uid: 用户qq :param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊 :param msg_type: 消息类型,私聊或群聊
:param days: 限制日期 :param days: 限制日期
@@ -142,9 +142,9 @@ class ChatHistory(db.Model):
days: Optional[int] = None, days: Optional[int] = None,
) -> List["ChatHistory"]: ) -> List["ChatHistory"]:
""" """
说明: 说明:
获取群聊消息 获取群聊消息
参数: 参数:
:param gid: 用户qq :param gid: 用户qq
:param days: 限制日期 :param days: 限制日期
""" """
@@ -157,9 +157,9 @@ class ChatHistory(db.Model):
days: Optional[int] = None, days: Optional[int] = None,
) -> List["ChatHistory"]: ) -> List["ChatHistory"]:
""" """
说明: 说明:
获取群聊消息数量 获取群聊消息数量
参数: 参数:
:param gid: 用户qq :param gid: 用户qq
:param days: 限制日期 :param days: 限制日期
""" """
@@ -178,9 +178,9 @@ class ChatHistory(db.Model):
is_select_count: bool = False, is_select_count: bool = False,
): ):
""" """
说明: 说明:
获取消息查询query 获取消息查询query
参数: 参数:
:param uid: 用户qq :param uid: 用户qq
:param gid: 群号 :param gid: 群号
:param type_: 类型,私聊或群聊 :param type_: 类型,私聊或群聊
+10 -10
View File
@@ -15,9 +15,9 @@ class FriendUser(db.Model):
@classmethod @classmethod
async def get_user_name(cls, user_id: int) -> str: async def get_user_name(cls, user_id: int) -> str:
""" """
说明: 说明:
获取好友用户名称 获取好友用户名称
参数: 参数:
:param user_id: qq号 :param user_id: qq号
""" """
query = cls.query.where(cls.user_id == user_id) query = cls.query.where(cls.user_id == user_id)
@@ -30,9 +30,9 @@ class FriendUser(db.Model):
@classmethod @classmethod
async def add_friend_info(cls, user_id: int, user_name: str) -> bool: async def add_friend_info(cls, user_id: int, user_name: str) -> bool:
""" """
说明: 说明:
添加好友信息 添加好友信息
参数: 参数:
:param user_id: qq号 :param user_id: qq号
:param user_name: 用户名称 :param user_name: 用户名称
""" """
@@ -55,9 +55,9 @@ class FriendUser(db.Model):
@classmethod @classmethod
async def delete_friend_info(cls, user_id: int) -> bool: async def delete_friend_info(cls, user_id: int) -> bool:
""" """
说明: 说明:
删除好友信息 删除好友信息
参数: 参数:
:param user_id: qq号 :param user_id: qq号
""" """
try: try:
@@ -72,9 +72,9 @@ class FriendUser(db.Model):
@classmethod @classmethod
async def get_friend_nickname(cls, user_id: int) -> str: async def get_friend_nickname(cls, user_id: int) -> str:
""" """
说明: 说明:
获取用户昵称 获取用户昵称
参数: 参数:
:param user_id: qq号 :param user_id: qq号
""" """
query = cls.query.where(cls.user_id == user_id) query = cls.query.where(cls.user_id == user_id)
@@ -92,9 +92,9 @@ class FriendUser(db.Model):
@classmethod @classmethod
async def set_friend_nickname(cls, user_id: int, nickname: str) -> bool: async def set_friend_nickname(cls, user_id: int, nickname: str) -> bool:
""" """
说明: 说明:
设置用户昵称 设置用户昵称
参数: 参数:
:param user_id: qq号 :param user_id: qq号
:param nickname: 昵称 :param nickname: 昵称
""" """
+103 -37
View File
@@ -1,5 +1,5 @@
from services.db_context import db from services.db_context import db
from typing import Optional, List from typing import Optional, List, Tuple
from services.log import logger from services.log import logger
@@ -12,27 +12,33 @@ class GoodsInfo(db.Model):
goods_description = db.Column(db.TEXT(), nullable=False) # 商品描述 goods_description = db.Column(db.TEXT(), nullable=False) # 商品描述
goods_discount = db.Column(db.Numeric(scale=3, asdecimal=False), default=1) # 打折 goods_discount = db.Column(db.Numeric(scale=3, asdecimal=False), default=1) # 打折
goods_limit_time = db.Column(db.BigInteger(), default=0) # 限时 goods_limit_time = db.Column(db.BigInteger(), default=0) # 限时
daily_limit = db.Column(db.Integer(), nullable=False, default=0) # 每日购买限制
daily_purchase_limit = db.Column(
db.JSON(), nullable=False, default={}
) # 每日购买限制数据存储
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True) _idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
@classmethod @classmethod
async def add_goods( async def add_goods(
cls, cls,
goods_name: str, goods_name: str,
goods_price: int, goods_price: int,
goods_description: str, goods_description: str,
goods_discount: float = 1, goods_discount: float = 1,
goods_limit_time: int = 0, goods_limit_time: int = 0,
daily_limit: int = 0,
) -> bool: ) -> bool:
""" """
说明: 说明:
添加商品 添加商品
参数: 参数:
:param goods_name: 商品名称 :param goods_name: 商品名称
:param goods_price: 商品价格 :param goods_price: 商品价格
:param goods_description: 商品简介 :param goods_description: 商品简介
:param goods_discount: 商品折扣 :param goods_discount: 商品折扣
:param goods_limit_time: 商品限时 :param goods_limit_time: 商品限时
:param daily_limit: 每日购买限制
""" """
try: try:
if not await cls.get_goods_info(goods_name): if not await cls.get_goods_info(goods_name):
@@ -42,6 +48,7 @@ class GoodsInfo(db.Model):
goods_description=goods_description, goods_description=goods_description,
goods_discount=goods_discount, goods_discount=goods_discount,
goods_limit_time=goods_limit_time, goods_limit_time=goods_limit_time,
daily_limit=daily_limit,
) )
return True return True
except Exception as e: except Exception as e:
@@ -51,15 +58,15 @@ class GoodsInfo(db.Model):
@classmethod @classmethod
async def delete_goods(cls, goods_name: str) -> bool: async def delete_goods(cls, goods_name: str) -> bool:
""" """
说明: 说明:
删除商品 删除商品
参数: 参数:
:param goods_name: 商品名称 :param goods_name: 商品名称
""" """
query = ( query = (
await cls.query.where(cls.goods_name == goods_name) await cls.query.where(cls.goods_name == goods_name)
.with_for_update() .with_for_update()
.gino.first() .gino.first()
) )
if not query: if not query:
return False return False
@@ -68,59 +75,59 @@ class GoodsInfo(db.Model):
@classmethod @classmethod
async def update_goods( async def update_goods(
cls, cls,
goods_name: str, goods_name: str,
goods_price: Optional[int] = None, goods_price: Optional[int] = None,
goods_description: Optional[str] = None, goods_description: Optional[str] = None,
goods_discount: Optional[float] = None, goods_discount: Optional[float] = None,
goods_limit_time: Optional[int] = None, goods_limit_time: Optional[int] = None,
daily_limit: Optional[int] = None
) -> bool: ) -> bool:
""" """
说明: 说明:
更新商品信息 更新商品信息
参数: 参数:
:param goods_name: 商品名称 :param goods_name: 商品名称
:param goods_price: 商品价格 :param goods_price: 商品价格
:param goods_description: 商品简介 :param goods_description: 商品简介
:param goods_discount: 商品折扣 :param goods_discount: 商品折扣
:param goods_limit_time: 商品限时时间 :param goods_limit_time: 商品限时时间
:param daily_limit: 每日次数限制
""" """
try: try:
query = ( query = (
await cls.query.where(cls.goods_name == goods_name) await cls.query.where(cls.goods_name == goods_name)
.with_for_update() .with_for_update()
.gino.first() .gino.first()
) )
if not query: if not query:
return False return False
if goods_price: await query.update(
await query.update(goods_price=goods_price).apply() goods_price=goods_price or query.goods_price,
if goods_description: goods_description=goods_description or query.goods_description,
await query.update(goods_description=goods_description).apply() goods_discount=goods_discount or query.goods_discount,
if goods_discount: goods_limit_time=goods_limit_time if goods_limit_time is not None else query.goods_limit_time,
await query.update(goods_discount=goods_discount).apply() daily_limit=daily_limit if daily_limit is not None else query.daily_limit,
if goods_limit_time: ).apply()
await query.update(goods_limit_time=goods_limit_time).apply()
return True return True
except Exception as e: except Exception as e:
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}") logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
return False return False
@classmethod @classmethod
async def get_goods_info(cls, goods_name: str) -> "GoodsInfo": async def get_goods_info(cls, goods_name: str) -> "GoodsInfo":
""" """
说明: 说明:
获取商品对象 获取商品对象
参数: 参数:
:param goods_name: 商品名称 :param goods_name: 商品名称
""" """
query = await cls.query.where(cls.goods_name == goods_name).gino.first() return await cls.query.where(cls.goods_name == goods_name).gino.first()
return query
@classmethod @classmethod
async def get_all_goods(cls) -> List["GoodsInfo"]: async def get_all_goods(cls) -> List["GoodsInfo"]:
""" """
说明: 说明:
获得全部有序商品对象 获得全部有序商品对象
""" """
query = await cls.query.gino.all() query = await cls.query.gino.all()
@@ -131,3 +138,62 @@ class GoodsInfo(db.Model):
goods_lst.append([x for x in query if x.id == min_id][0]) goods_lst.append([x for x in query if x.id == min_id][0])
id_lst.remove(min_id) id_lst.remove(min_id)
return goods_lst return goods_lst
@classmethod
async def add_user_daily_purchase(
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
):
"""
说明:
添加用户明日购买限制
参数:
:param goods: 商品
:param user_id: 用户id
:param group_id: 群号
:param num: 数量
"""
user_id = str(user_id)
group_id = str(group_id)
if goods and goods.daily_limit and goods.daily_limit > 0:
if not goods.daily_purchase_limit.get(group_id):
goods.daily_purchase_limit[group_id] = {}
if not goods.daily_purchase_limit[group_id].get(user_id):
goods.daily_purchase_limit[group_id][user_id] = 0
goods.daily_purchase_limit[group_id][user_id] += num
await goods.update(daily_purchase_limit=goods.daily_purchase_limit).apply()
@classmethod
async def check_user_daily_purchase(
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
) -> Tuple[bool, int]:
"""
说明:
检测用户每日购买上限
参数:
:param goods: 商品
:param user_id: 用户id
:param group_id: 群号
:param num: 数量
"""
user_id = str(user_id)
group_id = str(group_id)
if goods and goods.daily_limit > 0:
if (
not goods.daily_limit
or not goods.daily_purchase_limit.get(group_id)
or not goods.daily_purchase_limit[group_id].get(user_id)
):
return goods.daily_limit - num < 0, goods.daily_limit
if goods.daily_purchase_limit[group_id][user_id] + num > goods.daily_limit:
return (
True,
goods.daily_limit - goods.daily_purchase_limit[group_id][user_id],
)
return False, 0
@classmethod
async def reset_daily_purchase(cls):
"""
重置每次次数限制
"""
await cls.update.values(daily_purchase_limit={}).gino.status()
+7 -7
View File
@@ -17,9 +17,9 @@ class GroupInfo(db.Model):
@classmethod @classmethod
async def get_group_info(cls, group_id: int) -> "GroupInfo": async def get_group_info(cls, group_id: int) -> "GroupInfo":
""" """
说明: 说明:
获取群信息 获取群信息
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
query = cls.query.where(cls.group_id == group_id) query = cls.query.where(cls.group_id == group_id)
@@ -35,9 +35,9 @@ class GroupInfo(db.Model):
group_flag: Optional[int] = None, group_flag: Optional[int] = None,
) -> bool: ) -> bool:
""" """
说明: 说明:
添加群信息 添加群信息
参数: 参数:
:param group_id: 群号 :param group_id: 群号
:param group_name: 群名称 :param group_name: 群名称
:param max_member_count: 群员最大数量 :param max_member_count: 群员最大数量
@@ -74,9 +74,9 @@ class GroupInfo(db.Model):
@classmethod @classmethod
async def delete_group_info(cls, group_id: int): async def delete_group_info(cls, group_id: int):
""" """
说明: 说明:
删除群信息 删除群信息
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
await cls.delete.where(cls.group_id == group_id).gino.status() await cls.delete.where(cls.group_id == group_id).gino.status()
@@ -84,7 +84,7 @@ class GroupInfo(db.Model):
@classmethod @classmethod
async def get_all_group(cls) -> List["GroupInfo"]: async def get_all_group(cls) -> List["GroupInfo"]:
""" """
说明: 说明:
获取所有群对象 获取所有群对象
""" """
query = await cls.query.gino.all() query = await cls.query.gino.all()
+14 -14
View File
@@ -27,9 +27,9 @@ class GroupInfoUser(db.Model):
uid: Optional[int] = None, uid: Optional[int] = None,
) -> bool: ) -> bool:
""" """
说明: 说明:
添加群内用户信息 添加群内用户信息
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
:param user_name: 用户名称 :param user_name: 用户名称
@@ -57,9 +57,9 @@ class GroupInfoUser(db.Model):
cls, user_qq: int, group_id: int cls, user_qq: int, group_id: int
) -> "GroupInfoUser": ) -> "GroupInfoUser":
""" """
说明: 说明:
查询群员信息 查询群员信息
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
""" """
@@ -71,9 +71,9 @@ class GroupInfoUser(db.Model):
@classmethod @classmethod
async def delete_member_info(cls, user_qq: int, group_id: int) -> bool: async def delete_member_info(cls, user_qq: int, group_id: int) -> bool:
""" """
说明: 说明:
删除群员信息 删除群员信息
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
""" """
@@ -96,9 +96,9 @@ class GroupInfoUser(db.Model):
@classmethod @classmethod
async def get_group_member_id_list(cls, group_id: int) -> List[int]: async def get_group_member_id_list(cls, group_id: int) -> List[int]:
""" """
说明: 说明:
获取该群所有用户qq 获取该群所有用户qq
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
member_list = [] member_list = []
@@ -112,9 +112,9 @@ class GroupInfoUser(db.Model):
cls, user_qq: int, group_id: int, nickname: str cls, user_qq: int, group_id: int, nickname: str
) -> bool: ) -> bool:
""" """
说明: 说明:
设置群员在该群内的昵称 设置群员在该群内的昵称
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
:param nickname: 昵称 :param nickname: 昵称
@@ -131,9 +131,9 @@ class GroupInfoUser(db.Model):
@classmethod @classmethod
async def get_user_all_group(cls, user_qq: int) -> List[int]: async def get_user_all_group(cls, user_qq: int) -> List[int]:
""" """
说明: 说明:
获取该用户所在的所有群聊 获取该用户所在的所有群聊
参数: 参数:
:param user_qq: 用户qq :param user_qq: 用户qq
""" """
query = await cls.query.where(cls.user_qq == user_qq).gino.all() query = await cls.query.where(cls.user_qq == user_qq).gino.all()
@@ -144,9 +144,9 @@ class GroupInfoUser(db.Model):
@classmethod @classmethod
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str: async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
""" """
说明: 说明:
获取用户在该群的昵称 获取用户在该群的昵称
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
""" """
+25 -20
View File
@@ -1,3 +1,5 @@
from asyncpg import UniqueViolationError
from services.db_context import db from services.db_context import db
@@ -15,9 +17,9 @@ class LevelUser(db.Model):
@classmethod @classmethod
async def get_user_level(cls, user_qq: int, group_id: int) -> int: async def get_user_level(cls, user_qq: int, group_id: int) -> int:
""" """
说明: 说明:
获取用户在群内的等级 获取用户在群内的等级
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
""" """
@@ -33,9 +35,9 @@ class LevelUser(db.Model):
cls, user_qq: int, group_id: int, level: int, group_flag: int = 0 cls, user_qq: int, group_id: int, level: int, group_flag: int = 0
) -> bool: ) -> bool:
""" """
说明: 说明:
设置用户在群内的权限 设置用户在群内的权限
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
:param level: 权限等级 :param level: 权限等级
@@ -44,24 +46,27 @@ class LevelUser(db.Model):
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id)) query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update() query = query.with_for_update()
user = await query.gino.first() user = await query.gino.first()
if user is None: try:
await cls.create( if not user:
user_qq=user_qq, await cls.create(
group_id=group_id, user_qq=user_qq,
user_level=level, group_id=group_id,
group_flag=group_flag, user_level=level,
) group_flag=group_flag,
return True )
else: return True
await user.update(user_level=level, group_flag=group_flag).apply() else:
await user.update(user_level=level, group_flag=group_flag).apply()
return False
except UniqueViolationError:
return False return False
@classmethod @classmethod
async def delete_level(cls, user_qq: int, group_id: int) -> bool: async def delete_level(cls, user_qq: int, group_id: int) -> bool:
""" """
说明: 说明:
删除用户权限 删除用户权限
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
""" """
@@ -77,9 +82,9 @@ class LevelUser(db.Model):
@classmethod @classmethod
async def check_level(cls, user_qq: int, group_id: int, level: int) -> bool: async def check_level(cls, user_qq: int, group_id: int, level: int) -> bool:
""" """
说明: 说明:
检查用户权限等级是否大于 level 检查用户权限等级是否大于 level
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
:param level: 权限等级 :param level: 权限等级
@@ -107,9 +112,9 @@ class LevelUser(db.Model):
@classmethod @classmethod
async def is_group_flag(cls, user_qq: int, group_id: int) -> bool: async def is_group_flag(cls, user_qq: int, group_id: int) -> bool:
""" """
说明: 说明:
检测是否会被自动更新刷新权限 检测是否会被自动更新刷新权限
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
""" """
+2 -2
View File
@@ -80,9 +80,9 @@ class SignGroupUser(db.Model):
@classmethod @classmethod
async def get_all_impression(cls, group_id: int) -> "list, list, list": async def get_all_impression(cls, group_id: int) -> "list, list, list":
""" """
说明: 说明:
获取该群所有用户 id 及对应 好感度 获取该群所有用户 id 及对应 好感度
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
impression_list = [] impression_list = []
+1 -1
View File
@@ -37,7 +37,7 @@ 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"
) )
ai = on_message(rule=to_me(), priority=8) ai = on_message(rule=to_me(), priority=998)
@ai.handle() @ai.handle()
+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 typing import Optional, Tuple, Union
from configs.config import Config from configs.config import Config
from utils.http_utils import AsyncHttpx 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 "没有搜索到...", 997
return data, 200 return data, 200
else: else:
if data["code"] == 101:
return "缺失ALAPI TOKEN,请在配置文件中填写!", 999
return f'发生了错误...code:{data["code"]}', 999 return f'发生了错误...code:{data["code"]}', 999
except TimeoutError: except TimeoutError:
return "超时了....", 998 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())
+32 -6
View File
@@ -1,6 +1,8 @@
from nonebot import on_command from nonebot import on_command
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from utils.message_builder import at
from .data_source import ( from .data_source import (
add_live_sub, add_live_sub,
delete_sub, delete_sub,
@@ -38,7 +40,7 @@ usage:
__plugin_des__ = "非常便利的B站订阅通知" __plugin_des__ = "非常便利的B站订阅通知"
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"] __plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"]
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = "HibiKier" __plugin_author__ = "HibiKier & NumberSir"
__plugin_settings__ = { __plugin_settings__ = {
"level": 5, "level": 5,
"default_status": True, "default_status": True,
@@ -50,7 +52,17 @@ __plugin_configs__ = {
"value": 5, "value": 5,
"help": "群内bilibili订阅需要管理的权限", "help": "群内bilibili订阅需要管理的权限",
"default_value": 5, "default_value": 5,
} },
"LIVE_MSG_AT_ALL": {
"value": False,
"help": "直播提醒是否AT全体(仅在真寻是管理员时生效)",
"default_value": False,
},
"UP_MSG_AT_ALL": {
"value": False,
"help": "UP动态投稿提醒是否AT全体(仅在真寻是管理员时生效)",
"default_value": False,
},
} }
add_sub = on_command("添加订阅", priority=5, block=True) add_sub = on_command("添加订阅", priority=5, block=True)
@@ -228,13 +240,27 @@ async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
:param sub: BilibiliSub :param sub: BilibiliSub
:param bot: Bot :param bot: Bot
""" """
temp_group = []
if rst: if rst:
for x in sub.sub_users.split(",")[:-1]: for x in sub.sub_users.split(",")[:-1]:
try: try:
if ":" in x: if ":" in x and x.split(":")[1] not in temp_group:
await bot.send_group_msg( group_id = int(x.split(":")[1])
group_id=int(x.split(":")[1]), message=Message(rst) 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
await bot.send_group_msg(group_id=group_id, message=Message(rst))
else: else:
await bot.send_private_msg(user_id=int(x), message=Message(rst)) await bot.send_private_msg(user_id=int(x), message=Message(rst))
except Exception as e: except Exception as e:
+71 -41
View File
@@ -1,13 +1,18 @@
from bilibili_api.exceptions.ResponseCodeException import ResponseCodeException from bilireq.exceptions import ResponseCodeError
from nonebot.adapters.onebot.v11 import MessageSegment
from utils.manager import resources_manager from utils.manager import resources_manager
from asyncio.exceptions import TimeoutError from asyncio.exceptions import TimeoutError
from utils.utils import get_bot
from .model import BilibiliSub from .model import BilibiliSub
from bilibili_api.live import LiveRoom from bilireq.live import get_room_info_by_id
from bilibili_api import bangumi from .utils import get_meta
from utils.message_builder import image from utils.message_builder import image
from bilibili_api.user import User from bilireq.user import get_user_info
from bilibili_api import user from bilireq import dynamic
from typing import Optional from .utils import get_videos
from typing import Optional, Tuple
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from datetime import datetime from datetime import datetime
from utils.browser import get_browser from utils.browser import get_browser
@@ -36,9 +41,9 @@ async def add_live_sub(live_id: int, sub_user: str) -> str:
try: try:
async with db.transaction(): async with db.transaction():
try: try:
live = LiveRoom(live_id) """bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
live_info = (await live.get_room_info())["room_info"] live_info = await get_room_info_by_id(live_id)
except ResponseCodeException: except ResponseCodeError:
return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确" return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确"
uid = live_info["uid"] uid = live_info["uid"]
room_id = live_info["room_id"] room_id = live_info["room_id"]
@@ -78,16 +83,18 @@ async def add_up_sub(uid: int, sub_user: str) -> str:
try: try:
async with db.transaction(): async with db.transaction():
try: try:
u = user.User(uid) """bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await u.get_user_info() user_info = await get_user_info(uid)
except ResponseCodeException: except ResponseCodeError:
return f"未找到UpId:{uid} 的信息,请检查Id是否正确" return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
uname = user_info["name"] uname = user_info["name"]
dynamic_info = await u.get_dynamics(0) """bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
dynamic_upload_time = 0 dynamic_upload_time = 0
if dynamic_info.get("cards"): if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"] dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
video_info = await u.get_videos() """bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(uid)
latest_video_created = 0 latest_video_created = 0
if video_info["list"].get("vlist"): if video_info["list"].get("vlist"):
latest_video_created = video_info["list"]["vlist"][0]["created"] latest_video_created = video_info["list"]["vlist"][0]["created"]
@@ -117,8 +124,9 @@ async def add_season_sub(media_id: int, sub_user: str) -> str:
try: try:
async with db.transaction(): async with db.transaction():
try: try:
season_info = await bangumi.get_meta(media_id) """bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
except ResponseCodeException: season_info = await get_meta(media_id)
except ResponseCodeError:
return f"未找到media_id:{media_id} 的信息,请检查Id是否正确" return f"未找到media_id:{media_id} 的信息,请检查Id是否正确"
season_id = season_info["media"]["season_id"] season_id = season_info["media"]["season_id"]
season_current_episode = season_info["media"]["new_ep"]["index"] season_current_episode = season_info["media"]["new_ep"]["index"]
@@ -200,7 +208,7 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
return await _get_up_status(id_) return await _get_up_status(id_)
elif sub_type == "season": elif sub_type == "season":
return await _get_season_status(id_) return await _get_season_status(id_)
except ResponseCodeException: except ResponseCodeError:
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..." return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
# except Exception as e: # except Exception as e:
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}") # logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
@@ -212,17 +220,18 @@ async def _get_live_status(id_: int) -> Optional[str]:
获取直播订阅状态 获取直播订阅状态
:param id_: 直播间 id :param id_: 直播间 id
""" """
live = LiveRoom(id_) """bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
live_info = (await live.get_room_info())["room_info"] live_info = await get_room_info_by_id(id_)
title = live_info["title"] title = live_info["title"]
room_id = live_info["room_id"] room_id = live_info["room_id"]
live_status = live_info["live_status"] live_status = live_info["live_status"]
cover = live_info["cover"] cover = live_info["user_cover"]
sub = await BilibiliSub.get_sub(id_) sub = await BilibiliSub.get_sub(id_)
if sub.live_status != live_status: if sub.live_status != live_status:
await BilibiliSub.update_sub_info(id_, live_status=live_status) await BilibiliSub.update_sub_info(id_, live_status=live_status)
if sub.live_status == 0 and live_status == 1: if sub.live_status == 0 and live_status == 1:
return ( return (
f""
f"{image(cover)}\n" f"{image(cover)}\n"
f"{sub.uname} 开播啦!\n" f"{sub.uname} 开播啦!\n"
f"标题:{title}\n" f"标题:{title}\n"
@@ -238,22 +247,23 @@ async def _get_up_status(id_: int) -> Optional[str]:
:return: :return:
""" """
_user = await BilibiliSub.get_sub(id_) _user = await BilibiliSub.get_sub(id_)
u = user.User(_user.uid) """bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await u.get_user_info() user_info = await get_user_info(_user.uid)
uname = user_info["name"] uname = user_info["name"]
video_info = await u.get_videos() """bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(id_)
latest_video_created = 0 latest_video_created = 0
video = None video = None
if _user.uname != uname: if _user.uname != uname:
await BilibiliSub.update_sub_info(id_, uname=uname) await BilibiliSub.update_sub_info(id_, uname=uname)
dynamic_img, dynamic_upload_time = await get_user_dynamic(u, _user) dynamic_img, dynamic_upload_time, link = await get_user_dynamic(id_, _user)
if video_info["list"].get("vlist"): if video_info["list"].get("vlist"):
video = video_info["list"]["vlist"][0] video = video_info["list"]["vlist"][0]
latest_video_created = video["created"] latest_video_created = video["created"]
rst = "" rst = ""
if dynamic_img: if dynamic_img:
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time) await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n" rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n{link}"
if ( if (
latest_video_created latest_video_created
and _user.latest_video_created and _user.latest_video_created
@@ -280,7 +290,8 @@ async def _get_season_status(id_) -> Optional[str]:
获取 番剧 更新状态 获取 番剧 更新状态
:param id_: 番剧 id :param id_: 番剧 id
""" """
season_info = await bangumi.get_meta(id_) """bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
season_info = await get_meta(id_)
title = season_info["media"]["title"] title = season_info["media"]["title"]
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode _idx = (await BilibiliSub.get_sub(id_)).season_current_episode
new_ep = season_info["media"]["new_ep"]["index"] new_ep = season_info["media"]["new_ep"]["index"]
@@ -297,45 +308,63 @@ async def _get_season_status(id_) -> Optional[str]:
async def get_user_dynamic( async def get_user_dynamic(
u: User, local_user: BilibiliSub uid: int, local_user: BilibiliSub
) -> "Optional[MessageSegment], int": ) -> Tuple[Optional[MessageSegment], int, str]:
""" """
获取用户动态 获取用户动态
:param u: 用户类 :param uid: 用户uid
:param local_user: 数据库存储的用户数据 :param local_user: 数据库存储的用户数据
:return: 最新动态截图与时间 :return: 最新动态截图与时间
""" """
dynamic_info = await u.get_dynamics(0) """bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
browser = await get_browser() browser = await get_browser()
if dynamic_info.get("cards") and browser: if dynamic_info.get("cards") and browser:
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"] dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
dynamic_id = dynamic_info["cards"][0]["desc"]["dynamic_id"]
if local_user.dynamic_upload_time < dynamic_upload_time: if local_user.dynamic_upload_time < dynamic_upload_time:
page = await browser.new_page() context = await browser.new_context()
page = await context.new_page()
try: try:
await page.goto( await page.goto(
f"https://space.bilibili.com/{local_user.uid}/dynamic", f"https://t.bilibili.com/{dynamic_id}",
wait_until="networkidle", wait_until="networkidle",
timeout=10000, timeout=10000,
) )
await page.set_viewport_size({"width": 2560, "height": 1080}) # await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s
# 删除置顶 # 删除置顶
# await page.evaluate(
# """
# xs = document.getElementsByClassName('bili-dyn-item__tag');
# for (x of xs) {
# x.parentNode.parentNode.remove();
# }
# """
# )
# async with page.expect_popup() as popup_info:
# await page.locator(".bili-rich-text__content").click()
# details_page = await popup_info.value
await page.set_viewport_size(
{"width": 2560, "height": 1080, "timeout": 10000 * 20}
)
await page.wait_for_selector(".panel-area")
await page.evaluate( await page.evaluate(
""" """
xs = document.getElementsByClassName('first-card-with-title'); xs = document.getElementById('internationalHeader');
for (x of xs) { xs.remove();
x.remove(); xs = document.getElementsByClassName('panel-area')
} xs[0].remove();
""" """
) )
card = await page.query_selector(".card") card = page.locator(".detail-card")
# 截图并保存 await card.wait_for()
await card.screenshot( await card.screenshot(
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg", path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
timeout=100000,
) )
except Exception as e: except Exception as e:
logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}") logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
finally: finally:
await context.close()
await page.close() await page.close()
return ( return (
image( image(
@@ -343,8 +372,9 @@ async def get_user_dynamic(
"bilibili_sub/dynamic", "bilibili_sub/dynamic",
), ),
dynamic_upload_time, dynamic_upload_time,
f"https://t.bilibili.com/{dynamic_id}"
) )
return None, None return None, 0, ''
class SubManager: class SubManager:
+9 -9
View File
@@ -47,9 +47,9 @@ class BilibiliSub(db.Model):
season_update_time: Optional[datetime] = None, season_update_time: Optional[datetime] = None,
) -> bool: ) -> bool:
""" """
说明: 说明:
添加订阅 添加订阅
参数: 参数:
:param sub_id: 订阅名称,房间号,番剧号等 :param sub_id: 订阅名称,房间号,番剧号等
:param sub_type: 订阅类型 :param sub_type: 订阅类型
:param sub_user: 订阅此条目的用户 :param sub_user: 订阅此条目的用户
@@ -110,9 +110,9 @@ class BilibiliSub(db.Model):
@classmethod @classmethod
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str) -> bool: async def delete_bilibili_sub(cls, sub_id: int, sub_user: str) -> bool:
""" """
说明: 说明:
删除订阅 删除订阅
参数: 参数:
:param sub_id: 订阅名称 :param sub_id: 订阅名称
:param sub_user: 删除此条目的用户 :param sub_user: 删除此条目的用户
""" """
@@ -140,9 +140,9 @@ class BilibiliSub(db.Model):
@classmethod @classmethod
async def get_sub(cls, sub_id: int) -> Optional["BilibiliSub"]: async def get_sub(cls, sub_id: int) -> Optional["BilibiliSub"]:
""" """
说明: 说明:
获取订阅对象 获取订阅对象
参数: 参数:
:param sub_id: 订阅 id :param sub_id: 订阅 id
""" """
return await cls.query.where(cls.sub_id == sub_id).gino.first() return await cls.query.where(cls.sub_id == sub_id).gino.first()
@@ -173,9 +173,9 @@ class BilibiliSub(db.Model):
season_update_time: Optional[datetime] = None, season_update_time: Optional[datetime] = None,
) -> bool: ) -> bool:
""" """
说明: 说明:
更新订阅信息 更新订阅信息
参数: 参数:
:param sub_id: 订阅名称,房间号,番剧号等 :param sub_id: 订阅名称,房间号,番剧号等
:param live_short_id: 直接短 id :param live_short_id: 直接短 id
:param live_status: 主播开播状态 :param live_status: 主播开播状态
@@ -232,7 +232,7 @@ class BilibiliSub(db.Model):
cls, cls,
) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]": ) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]":
""" """
说明: 说明:
分类获取所有数据 分类获取所有数据
""" """
live_data = [] live_data = []
+48 -4
View File
@@ -1,7 +1,8 @@
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from bilibili_api import user # from bilibili_api import user
from bilireq.user import get_user_info
from io import BytesIO from io import BytesIO
@@ -28,8 +29,8 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
:param des: 直播简介 :param des: 直播简介
:return: :return:
""" """
u = user.User(uid)
user_info = await u.get_user_info() user_info = await get_user_info(uid)
name = user_info["name"] name = user_info["name"]
sex = user_info["sex"] sex = user_info["sex"]
face = user_info["face"] face = user_info["face"]
@@ -37,7 +38,6 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
ava = BuildImage(100, 100, background=BytesIO(await get_pic(face))) ava = BuildImage(100, 100, background=BytesIO(await get_pic(face)))
ava.circle() ava.circle()
cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover))) cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover)))
print()
def _create_live_des_image( def _create_live_des_image(
@@ -68,3 +68,47 @@ def _create_live_des_image(
border_img = BuildImage(1772, 2657, background=border) border_img = BuildImage(1772, 2657, background=border)
bk = BuildImage(1772, 2657, font_size=30) bk = BuildImage(1772, 2657, font_size=30)
bk.paste(cover, (0, 100), center_type="by_width") bk.paste(cover, (0, 100), center_type="by_width")
async def get_meta(media_id: int, auth=None, reqtype="both", **kwargs):
"""
根据番剧 ID 获取番剧元数据信息,
作为bilibili_api和bilireq的替代品。
如果bilireq.bangumi更新了,可以转为调用bilireq.bangumi的get_meta方法,两者完全一致。
"""
from bilireq.utils import get
BASE_URL = "https://api.bilibili.com"
url = f"{BASE_URL}/pgc/review/user"
params = {"media_id": media_id}
raw_json = await get(url, raw=True, params=params, auth=auth, reqtype=reqtype, **kwargs)
return raw_json['result']
async def get_videos(
uid: int, tid: int = 0, pn: int = 1, keyword: str = "", order: str = "pubdate",
*, auth=None, reqtype="both", **kwargs
):
"""
获取用户投该视频信息
作为bilibili_api和bilireq的替代品。
如果bilireq.user更新了,可以转为调用bilireq.user的get_videos方法,两者完全一致。
:param uid: 用户 UID
:param tid: 分区 ID
:param pn: 页码
:param keyword: 搜索关键词
:param order: 排序方式,可以为 “pubdate(上传日期从新到旧), stow(收藏从多到少), click(播放量从多到少)”
"""
from bilireq.utils import get
BASE_URL = "https://api.bilibili.com"
url = f"{BASE_URL}/x/space/arc/search"
params = {
"mid": uid,
"ps": 30,
"tid": tid,
"pn": pn,
"keyword": keyword,
"order": order
}
return await get(url, params=params, auth=auth, reqtype=reqtype, **kwargs)
+5 -1
View File
@@ -8,6 +8,7 @@ from nonebot.adapters.onebot.v11 import (
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor from nonebot.message import run_preprocessor
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
from utils.manager import group_manager
from utils.utils import get_message_text, is_number from utils.utils import get_message_text, is_number
from nonebot.params import RegexGroup, CommandArg from nonebot.params import RegexGroup, CommandArg
from .utils import black_word_manager from .utils import black_word_manager
@@ -155,7 +156,11 @@ async def _(
and matcher.plugin_name == "black_word" and matcher.plugin_name == "black_word"
and not await BanUser.is_ban(event.user_id) and not await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers and str(event.user_id) not in bot.config.superusers
and not get_message_text(event.json()).startswith("原神绑定")
): ):
# 屏蔽群权限-1的群
if isinstance(event, GroupMessageEvent) and group_manager.get_group_level(event.group_id) < 0:
return
user_id = event.user_id user_id = event.user_id
group_id = event.group_id if isinstance(event, GroupMessageEvent) else None group_id = event.group_id if isinstance(event, GroupMessageEvent) else None
msg = get_message_text(event.json()) msg = get_message_text(event.json())
@@ -241,7 +246,6 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
uid = int(msg[0]) uid = int(msg[0])
id_ = int(msg[1]) id_ = int(msg[1])
punish_level = int(msg[2]) punish_level = int(msg[2])
print(uid, id_, punish_level)
rst = await set_user_punish(uid, id_, punish_level) rst = await set_user_punish(uid, id_, punish_level)
await set_punish.send(rst) await set_punish.send(rst)
logger.info( logger.info(
+1 -1
View File
@@ -77,7 +77,7 @@ async def show_black_text_image(
(punish_level_str, "等级"), (punish_level_str, "等级"),
(create_time_str, "记录日期"), (create_time_str, "记录日期"),
]: ]:
img = await text2image(s, color="#f9f6f2", _add_height=3.32) img = await text2image(s, color="#f9f6f2", _add_height=2.1)
w = _tmp_img.getsize(type_)[0] if _tmp_img.getsize(type_)[0] > img.w else img.w w = _tmp_img.getsize(type_)[0] if _tmp_img.getsize(type_)[0] > img.w else img.w
A = BuildImage(w + 11, img.h + 50, color="#f9f6f2", font_size=35, font="CJGaoDeGuo.otf") A = BuildImage(w + 11, img.h + 50, color="#f9f6f2", font_size=35, font="CJGaoDeGuo.otf")
await A.atext((10, 10), type_) await A.atext((10, 10), type_)
+10 -11
View File
@@ -25,9 +25,9 @@ class BlackWord(db.Model):
punish_level: int, punish_level: int,
): ):
""" """
说明: 说明:
添加用户发送的敏感词 添加用户发送的敏感词
参数: 参数:
:param user_qq: 用户id :param user_qq: 用户id
:param group_id: 群号 :param group_id: 群号
:param black_word: 黑名单词汇 :param black_word: 黑名单词汇
@@ -52,9 +52,9 @@ class BlackWord(db.Model):
id_: Optional[int] = None, id_: Optional[int] = None,
) -> bool: ) -> bool:
""" """
说明: 说明:
设置处罚 设置处罚
参数: 参数:
:param user_qq: 用户id :param user_qq: 用户id
:param punish: 处罚 :param punish: 处罚
:param black_word: 黑名单词汇 :param black_word: 黑名单词汇
@@ -68,7 +68,6 @@ class BlackWord(db.Model):
user = await query.where(cls.black_word == black_word).order_by(cls.id.desc()).gino.first() user = await query.where(cls.black_word == black_word).order_by(cls.id.desc()).gino.first()
elif id_: elif id_:
user_list = await query.gino.all() user_list = await query.gino.all()
print(len(user_list))
if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)): if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)):
return False return False
user = user_list[id_] user = user_list[id_]
@@ -82,9 +81,9 @@ class BlackWord(db.Model):
cls, user_qq: int, days: int = 7, punish_level: Optional[int] = None cls, user_qq: int, days: int = 7, punish_level: Optional[int] = None
) -> int: ) -> int:
""" """
说明: 说明:
获取用户规定周期内的犯事次数 获取用户规定周期内的犯事次数
参数: 参数:
:param user_qq: 用户qq :param user_qq: 用户qq
:param days: 周期天数 :param days: 周期天数
:param punish_level: 惩罚等级 :param punish_level: 惩罚等级
@@ -102,9 +101,9 @@ class BlackWord(db.Model):
@classmethod @classmethod
async def get_user_punish_level(cls, user_qq: int, days: int = 7) -> Optional[int]: async def get_user_punish_level(cls, user_qq: int, days: int = 7) -> Optional[int]:
""" """
说明: 说明:
获取用户最近一次的惩罚记录等级 获取用户最近一次的惩罚记录等级
参数: 参数:
:param user_qq: 用户qq :param user_qq: 用户qq
:param days: 周期天数 :param days: 周期天数
""" """
@@ -126,9 +125,9 @@ class BlackWord(db.Model):
date_type: str = "=", date_type: str = "=",
) -> List["BlackWord"]: ) -> List["BlackWord"]:
""" """
说明: 说明:
通过指定条件查询数据 通过指定条件查询数据
参数: 参数:
:param user_qq: 用户qq :param user_qq: 用户qq
:param group_id: 群号 :param group_id: 群号
:param date: 日期 :param date: 日期
+1 -3
View File
@@ -6,7 +6,7 @@ from configs.config import Config
from pathlib import Path from pathlib import Path
from services.log import logger from services.log import logger
from models.ban_user import BanUser from models.ban_user import BanUser
from nonebot.adapters.onebot.v11.exception import ActionFailed from nonebot.adapters.onebot.v11 import ActionFailed
from models.group_member_info import GroupInfoUser from models.group_member_info import GroupInfoUser
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
import random import random
@@ -88,9 +88,7 @@ class BlackWordManager:
:param group_id: 群号 :param group_id: 群号
:param message: 消息 :param message: 消息
""" """
print(user_id, group_id, message)
if data := self._check(message): if data := self._check(message):
print(data)
if data[0]: if data[0]:
await _add_user_black_word( await _add_user_black_word(
user_id, group_id, data[0], message, int(data[1]) user_id, group_id, data[0], message, int(data[1])
+1 -1
View File
@@ -80,8 +80,8 @@ async def _(
except TimeoutError: except TimeoutError:
await bt.finish(f"搜索 {keyword} 超时...") await bt.finish(f"搜索 {keyword} 超时...")
except Exception as e: except Exception as e:
await bt.finish(f"bt 其他未知错误..")
logger.error(f"bt 错误 {type(e)}:{e}") logger.error(f"bt 错误 {type(e)}:{e}")
await bt.finish(f"bt 其他未知错误..")
if not send_flag: if not send_flag:
await bt.send(f"{keyword} 未搜索到...") await bt.send(f"{keyword} 未搜索到...")
logger.info(f"USER {event.user_id} BT搜索 {keyword} 第 {page} 页") logger.info(f"USER {event.user_id} BT搜索 {keyword} 第 {page} 页")
+6 -6
View File
@@ -3,13 +3,13 @@ from configs.config import Config
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import platform import platform
if platform.system() == "Windows": # if platform.system() == "Windows":
import asyncio # import asyncio
#
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
url = "http://www.eclzz.mobi" url = "http://www.eclzz.zone/"
async def get_bt_info(keyword: str, page: int): async def get_bt_info(keyword: str, page: int):
@@ -19,7 +19,7 @@ async def get_bt_info(keyword: str, page: int):
:param page: 页数 :param page: 页数
""" """
text = (await AsyncHttpx.get(f"{url}/s/{keyword}_rel_{page}.html", timeout=5)).text text = (await AsyncHttpx.get(f"{url}/s/{keyword}_rel_{page}.html", timeout=5)).text
if text.find("大约0条结果") != -1: if "大约0条结果" in text:
return return
soup = BeautifulSoup(text, "lxml") soup = BeautifulSoup(text, "lxml")
item_lst = soup.find_all("div", {"class": "search-item"}) item_lst = soup.find_all("div", {"class": "search-item"})
+30 -25
View File
@@ -5,7 +5,7 @@ from .data_source import check_update, get_latest_version_data
from services.log import logger from services.log import logger
from utils.utils import scheduler, get_bot from utils.utils import scheduler, get_bot
from pathlib import Path from pathlib import Path
from configs.config import Config from configs.config import NICKNAME, Config
from nonebot.rule import to_me from nonebot.rule import to_me
from nonebot.params import ArgStr from nonebot.params import ArgStr
import platform import platform
@@ -25,6 +25,11 @@ __plugin_cmd__ = ["检查更新真寻", "重启"]
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = "HibiKier" __plugin_author__ = "HibiKier"
__plugin_configs__ = { __plugin_configs__ = {
"UPDATE_REMIND": {
"value": True,
"help": "真寻是否检测版本状态",
"default": True,
},
"AUTO_UPDATE_ZHENXUN": { "AUTO_UPDATE_ZHENXUN": {
"value": False, "value": False,
"help": "真寻是否自动检查更新", "help": "真寻是否自动检查更新",
@@ -66,18 +71,17 @@ async def _(bot: Bot):
) )
@restart.handle() @restart.got("flag", prompt=f"确定是否重启{NICKNAME}?确定请回复[是|好|确定](重启失败咱们将失去联系,请谨慎!)")
async def _():
if str(platform.system()).lower() == "windows":
await restart.finish("暂无windows重启脚本...")
@restart.got("flag", prompt="确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)")
async def _(flag: str = ArgStr("flag")): async def _(flag: str = ArgStr("flag")):
if flag.lower() in ["true", "是", "好", "确定", "确定是"]: if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
await restart.send("开始重启真寻..请稍等...") await restart.send(f"开始重启{NICKNAME}..请稍等...")
open("is_restart", "w") open("is_restart", "w")
os.system("./restart.sh") if str(platform.system()).lower() == "windows":
import sys
python = sys.executable
os.execl(python, python, *sys.argv)
else:
os.system("./restart.sh")
else: else:
await restart.send("已取消操作...") await restart.send("已取消操作...")
@@ -88,7 +92,7 @@ async def _(flag: str = ArgStr("flag")):
minute=0, minute=0,
) )
async def _(): async def _():
if Config.get_config("check_zhenxun_update", "AUTO_UPDATE_ZHENXUN"): if Config.get_config("check_zhenxun_update", "UPDATE_REMIND"):
_version = "v0.0.0" _version = "v0.0.0"
_version_file = Path() / "__version__" _version_file = Path() / "__version__"
if _version_file.exists(): if _version_file.exists():
@@ -108,17 +112,18 @@ async def _():
message=f"检测到真寻版本更新\n" message=f"检测到真寻版本更新\n"
f"当前版本:{_version},最新版本:{latest_version}", f"当前版本:{_version},最新版本:{latest_version}",
) )
# try: if Config.get_config("check_zhenxun_update", "AUTO_UPDATE_ZHENXUN"):
# code = await check_update(bot) try:
# except Exception as e: code = await check_update(bot)
# logger.error(f"更新真寻未知错误 {type(e)}:{e}") except Exception as e:
# await bot.send_private_msg( logger.error(f"更新真寻未知错误 {type(e)}:{e}")
# user_id=int(list(bot.config.superusers)[0]), await bot.send_private_msg(
# message=f"更新真寻未知错误 {type(e)}:{e}\n", user_id=int(list(bot.config.superusers)[0]),
# ) message=f"更新真寻未知错误 {type(e)}:{e}\n",
# else: )
# if code == 200: else:
# await bot.send_private_msg( if code == 200:
# user_id=int(list(bot.config.superusers)[0]), await bot.send_private_msg(
# message=f"更新完毕,请重启真寻....", user_id=int(list(bot.config.superusers)[0]),
# ) message=f"更新完毕,请重启{NICKNAME}....",
)
+8 -5
View File
@@ -14,9 +14,9 @@ import tarfile
import shutil import shutil
import os import os
if str(platform.system()).lower() == "windows": # if str(platform.system()).lower() == "windows":
policy = asyncio.WindowsSelectorEventLoopPolicy() # policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy) # asyncio.set_event_loop_policy(policy)
driver = nonebot.get_driver() driver = nonebot.get_driver()
@@ -162,7 +162,7 @@ def _file_handle(latest_version: str) -> str:
if backup_file.exists(): if backup_file.exists():
backup_file.unlink() backup_file.unlink()
if file not in [config_file, config_path_file]: if file not in [config_file, config_path_file]:
os.rename(file.absolute(), backup_file.absolute()) shutil.move(file.absolute(), backup_file.absolute())
else: else:
with open(file, "r", encoding="utf8") as rf: with open(file, "r", encoding="utf8") as rf:
data = rf.read() data = rf.read()
@@ -174,7 +174,7 @@ def _file_handle(latest_version: str) -> str:
old_file = Path() / file old_file = Path() / file
if old_file not in [config_file, config_path_file] and file != "configs": if old_file not in [config_file, config_path_file] and file != "configs":
if not old_file.exists() and new_file.exists(): if not old_file.exists() and new_file.exists():
os.rename(new_file.absolute(), old_file.absolute()) shutil.move(new_file.absolute(), old_file.absolute())
logger.info(f"已更新文件:{file}") logger.info(f"已更新文件:{file}")
# except Exception as e: # except Exception as e:
# error = f'{type(e)}:{e}' # error = f'{type(e)}:{e}'
@@ -189,6 +189,9 @@ def _file_handle(latest_version: str) -> str:
local_update_info_file.unlink() local_update_info_file.unlink()
with open(_version_file, "w", encoding="utf8") as f: with open(_version_file, "w", encoding="utf8") as f:
f.write(f"__version__: {latest_version}") f.write(f"__version__: {latest_version}")
os.system(
f"poetry run pip install -r {(Path() / 'pyproject.toml').absolute()}"
)
return error return error
+20 -13
View File
@@ -1,4 +1,7 @@
from typing import Tuple, Any
from nonebot import on_regex from nonebot import on_regex
from nonebot.params import RegexGroup
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, MessageEvent from nonebot.adapters.onebot.v11 import Bot, MessageEvent
from utils.message_builder import image from utils.message_builder import image
@@ -11,7 +14,9 @@ __plugin_usage__ = """
usage: usage:
三次元也不戳,嘿嘿嘿 三次元也不戳,嘿嘿嘿
指令: 指令:
cos/coser ?N连cos/coser
示例:cos
示例:5连cos (单次请求张数小于9)
""".strip() """.strip()
__plugin_des__ = "三次元也不戳,嘿嘿嘿" __plugin_des__ = "三次元也不戳,嘿嘿嘿"
__plugin_cmd__ = ["cos/coser"] __plugin_cmd__ = ["cos/coser"]
@@ -31,21 +36,23 @@ __plugin_configs__ = {
}, },
} }
coser = on_regex("^(cos|COS|coser|括丝)$", priority=5, block=True) coser = on_regex(r"^(\d)连?(cos|COS|coser|括丝)$", priority=5, block=True)
url = "https://api.iyk0.com/cos" url = "https://api.iyk0.com/cos"
@coser.handle() @coser.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): async def _(bot: Bot, event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
try: num = reg_group[0] or 1
msg_id = await coser.send(image(url)) for _ in range(int(num)):
withdraw_message_manager.withdraw_message( try:
event, msg_id = await coser.send(image(url))
msg_id["message_id"], withdraw_message_manager.withdraw_message(
Config.get_config("coser", "WITHDRAW_COS_MESSAGE"), event,
) msg_id["message_id"],
except Exception as e: Config.get_config("coser", "WITHDRAW_COS_MESSAGE"),
await coser.send("你cos给我看!") )
logger.error(f"coser 发送了未知错误 {type(e)}:{e}") except Exception as e:
await coser.send("你cos给我看!")
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
+1 -1
View File
@@ -53,7 +53,7 @@ __plugin_settings__ = {
dialogue_data = {} dialogue_data = {}
dialogue = on_command("[滴滴滴]", aliases={"滴滴滴-"}, priority=5, block=True) dialogue = on_command("&#91;滴滴滴&#93;", aliases={"滴滴滴-"}, priority=5, block=True)
reply = on_command("/t", priority=1, permission=SUPERUSER, block=True) reply = on_command("/t", priority=1, permission=SUPERUSER, block=True)
+11 -2
View File
@@ -23,6 +23,7 @@ from .handles.onmyoji_handle import OnmyojiHandle
from .handles.pcr_handle import PcrHandle from .handles.pcr_handle import PcrHandle
from .handles.pretty_handle import PrettyHandle from .handles.pretty_handle import PrettyHandle
from .handles.prts_handle import PrtsHandle from .handles.prts_handle import PrtsHandle
from .handles.ba_handle import BaHandle
from .config import draw_config from .config import draw_config
@@ -30,7 +31,7 @@ from .config import draw_config
__zx_plugin_name__ = "游戏抽卡" __zx_plugin_name__ = "游戏抽卡"
__plugin_usage__ = """ __plugin_usage__ = """
usage: usage:
模拟赛马娘,原神,明日方舟,坎公骑冠剑,公主连结(国/台),碧蓝航线,FGO,阴阳师进行抽卡 模拟赛马娘,原神,明日方舟,坎公骑冠剑,公主连结(国/台),碧蓝航线,FGO,阴阳师,碧蓝档案进行抽卡
指令: 指令:
原神[1-180]抽: 原神常驻池 原神[1-180]抽: 原神常驻池
原神角色[1-180]抽: 原神角色UP池子 原神角色[1-180]抽: 原神角色UP池子
@@ -43,6 +44,7 @@ usage:
碧蓝航线/碧蓝[重型/轻型/特型/活动][1-300]抽: 碧蓝航线重型/轻型/特型/活动卡池 碧蓝航线/碧蓝[重型/轻型/特型/活动][1-300]抽: 碧蓝航线重型/轻型/特型/活动卡池
fgo[1-300]抽: fgo卡池 fgo[1-300]抽: fgo卡池
阴阳师[1-300]抽: 阴阳师卡池 阴阳师[1-300]抽: 阴阳师卡池
ba/碧蓝档案[1-200]抽:碧蓝档案卡池
* 以上指令可以通过 XX一井 来指定最大抽取数量 * * 以上指令可以通过 XX一井 来指定最大抽取数量 *
* 示例:原神一井 * * 示例:原神一井 *
""".strip() """.strip()
@@ -73,6 +75,7 @@ __plugin_cmd__ = [
"pcr/公主连接[1-300]抽", "pcr/公主连接[1-300]抽",
"fgo[1-300]抽", "fgo[1-300]抽",
"阴阳师[1-300]抽", "阴阳师[1-300]抽",
"碧蓝档案[1-200]抽",
"更新方舟信息 [_superuser]", "更新方舟信息 [_superuser]",
"重载方舟卡池 [_superuser]", "重载方舟卡池 [_superuser]",
"更新原神信息 [_superuser]", "更新原神信息 [_superuser]",
@@ -83,6 +86,7 @@ __plugin_cmd__ = [
"更新碧蓝航线信息 [_superuser]", "更新碧蓝航线信息 [_superuser]",
"更新fgo信息 [_superuser]", "更新fgo信息 [_superuser]",
"更新阴阳师信息 [_superuser]", "更新阴阳师信息 [_superuser]",
"更新碧蓝档案信息 [_superuser]",
] ]
__plugin_type__ = ("抽卡相关", 1) __plugin_type__ = ("抽卡相关", 1)
__plugin_version__ = 0.1 __plugin_version__ = 0.1
@@ -105,7 +109,7 @@ class Game:
games = ( games = (
Game({"azur", "碧蓝", "碧蓝航线"}, AzurHandle(), draw_config.AZUR_FLAG), Game({"azur", "碧蓝航线"}, AzurHandle(), draw_config.AZUR_FLAG),
Game({"fgo", "命运冠位指定"}, FgoHandle(), draw_config.FGO_FLAG), Game({"fgo", "命运冠位指定"}, FgoHandle(), draw_config.FGO_FLAG),
Game( Game(
{"genshin", "原神"}, {"genshin", "原神"},
@@ -130,6 +134,11 @@ games = (
reload_time=4, reload_time=4,
), ),
Game({"prts", "方舟", "明日方舟"}, PrtsHandle(), draw_config.PRTS_FLAG, reload_time=4), Game({"prts", "方舟", "明日方舟"}, PrtsHandle(), draw_config.PRTS_FLAG, reload_time=4),
Game(
{"ba","碧蓝档案"},BaHandle(),
draw_config.BA_FLAG,
max_count=200,
),
) )
+10 -1
View File
@@ -87,6 +87,12 @@ class OnmyojiConfig(BaseModel, extra=Extra.ignore):
ONMYOJI_SR: float = 0.2 ONMYOJI_SR: float = 0.2
ONMYOJI_R: float = 0.7875 ONMYOJI_R: float = 0.7875
#碧蓝档案
class BaConfig(BaseModel, extra=Extra.ignore):
BA_THREE_P: float = 0.025
BA_TWO_P: float = 0.185
BA_ONE_P: float = 0.79
BA_G_TWO_P: float = 0.975
class Config(BaseModel, extra=Extra.ignore): class Config(BaseModel, extra=Extra.ignore):
# 开关 # 开关
@@ -98,6 +104,7 @@ class Config(BaseModel, extra=Extra.ignore):
AZUR_FLAG: bool = AConfig.get_config("draw_card", "AZUR_FLAG") AZUR_FLAG: bool = AConfig.get_config("draw_card", "AZUR_FLAG")
FGO_FLAG: bool = AConfig.get_config("draw_card", "FGO_FLAG") FGO_FLAG: bool = AConfig.get_config("draw_card", "FGO_FLAG")
ONMYOJI_FLAG: bool = AConfig.get_config("draw_card", "ONMYOJI_FLAG") ONMYOJI_FLAG: bool = AConfig.get_config("draw_card", "ONMYOJI_FLAG")
BA_FLAG: bool = AConfig.get_config("draw_card", "BA_FLAG")
# 其他配置 # 其他配置
PCR_TAI: bool = AConfig.get_config("draw_card", "PCR_TAI") PCR_TAI: bool = AConfig.get_config("draw_card", "PCR_TAI")
@@ -112,6 +119,7 @@ class Config(BaseModel, extra=Extra.ignore):
azur: AzurConfig = AzurConfig() azur: AzurConfig = AzurConfig()
fgo: FgoConfig = FgoConfig() fgo: FgoConfig = FgoConfig()
onmyoji: OnmyojiConfig = OnmyojiConfig() onmyoji: OnmyojiConfig = OnmyojiConfig()
ba: BaConfig = BaConfig()
driver = nonebot.get_driver() driver = nonebot.get_driver()
@@ -133,8 +141,9 @@ for game_flag, game_name in zip(
"FGO_FLAG", "FGO_FLAG",
"ONMYOJI_FLAG", "ONMYOJI_FLAG",
"PCR_TAI", "PCR_TAI",
"BA_FLAG"
], ],
["明日方舟", "原神", "赛马娘", "坎公骑冠剑", "公主连结", "碧蓝航线", "命运-冠位指定(FGO)", "阴阳师", "pcr台服卡池"], ["明日方舟", "原神", "赛马娘", "坎公骑冠剑", "公主连结", "碧蓝航线", "命运-冠位指定(FGO)", "阴阳师", "pcr台服卡池","碧蓝档案"],
): ):
AConfig.add_plugin_config( AConfig.add_plugin_config(
"draw_card", "draw_card",
+1 -1
View File
@@ -293,7 +293,7 @@ class AzurHandle(BaseHandle[AzurChar]):
type_ = ship.xpath("./tbody/tr/td[2]/p/small/text()")[0] # 舰船类型 type_ = ship.xpath("./tbody/tr/td[2]/p/small/text()")[0] # 舰船类型
try: try:
p = float(str(ship.xpath(".//sup/text()")[0]).strip("%")) p = float(str(ship.xpath(".//sup/text()")[0]).strip("%"))
except IndexError: except (IndexError, ValueError):
p = 0 p = 0
star = self.parse_star( star = self.parse_star(
ship.xpath("./tbody/tr/td[1]/div/div/div/a/img/@alt")[0] ship.xpath("./tbody/tr/td[1]/div/div/div/a/img/@alt")[0]
+150
View File
@@ -0,0 +1,150 @@
import random
from lxml import etree
from typing import List, Tuple
from PIL import ImageDraw
from urllib.parse import unquote
from nonebot.log import logger
from .base_handle import BaseHandle, BaseData
from ..config import draw_config
from ..util import remove_prohibited_str, cn2py, load_font
from utils.image_utils import BuildImage
class BaChar(BaseData):
pass
class BaHandle(BaseHandle[BaChar]):
def __init__(self):
super().__init__("ba", "碧蓝档案")
self.max_star = 3
self.config = draw_config.ba
self.ALL_CHAR: List[BaChar] = []
def get_card(self, mode: int = 1) -> BaChar:
if mode == 2:
star = self.get_star(
[3, 2], [self.config.BA_THREE_P, self.config.BA_G_TWO_P]
)
else:
star = self.get_star(
[3, 2, 1],
[self.config.BA_THREE_P, self.config.BA_TWO_P, self.config.BA_ONE_P],
)
chars = [x for x in self.ALL_CHAR if x.star == star and not x.limited]
return random.choice(chars)
def get_cards(self, count: int, **kwargs) -> List[Tuple[BaChar, int]]:
card_list = []
card_count = 0 # 保底计算
for i in range(count):
card_count += 1
# 十连保底
if card_count == 10:
card = self.get_card(2)
card_count = 0
else:
card = self.get_card(1)
if card.star > self.max_star - 2:
card_count = 0
card_list.append((card, i + 1))
return card_list
def generate_card_img(self, card: BaChar) -> BuildImage:
sep_w = 5
sep_h = 5
star_h = 15
img_w = 90
img_h = 100
font_h = 20
bar_h = 20
bar_w = 90
bg = BuildImage(img_w + sep_w * 2, img_h + font_h + sep_h * 2, color="#EFF2F5")
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
img = BuildImage(img_w, img_h, background=img_path)
bar = BuildImage(bar_w, bar_h, color="#6495ED")
bg.paste(img, (sep_w, sep_h), alpha=True)
bg.paste(bar, (sep_w, img_h - bar_h + sep_h), alpha=True)
if (card.star == 1):
star_path = str(self.img_path / "star-1.png")
star_w = 15
elif (card.star == 2):
star_path = str(self.img_path / "star-2.png")
star_w = 30
else:
star_path = str(self.img_path / "star-3.png")
star_w = 45
star = BuildImage(star_w, star_h, background=star_path)
bg.paste(star, (img_w // 2 - 15 * (card.star - 1) // 2, img_h - star_h), alpha=True)
text = card.name[:5] + "..." if len(card.name) > 6 else card.name
font = load_font(fontsize=14)
text_w, text_h = font.getsize(text)
draw = ImageDraw.Draw(bg.markImg)
draw.text(
(sep_w + (img_w - text_w) / 2, sep_h + img_h + (font_h - text_h) / 2),
text,
font=font,
fill="gray",
)
return bg
def _init_data(self):
self.ALL_CHAR = [
BaChar(
name=value["名称"],
star=int(value["星级"]),
limited=True if "(" in key else False,
)
for key, value in self.load_data().items()
]
def title2star(self, title: int):
if title == 'Star-3.png':
return 3
elif title == 'Star-2.png':
return 2
else:
return 1
async def _update_info(self):
info = {}
url = "https://wiki.biligame.com/bluearchive/学生筛选"
result = await self.get_url(url)
if not result:
logger.warning(f"更新 {self.game_name_cn} 出错")
return
else:
dom = etree.HTML(result, etree.HTMLParser())
char_list = dom.xpath("//div[@class='filters']/table[2]/tbody/tr")
for char in char_list:
try:
name = char.xpath("./td[2]/a/div/text()")[0]
avatar = char.xpath("./td[1]/div/div/a/img/@data-src")[0]
star_pic = char.xpath("./td[4]/img/@alt")[0]
except IndexError:
continue
member_dict = {
"头像": unquote(str(avatar)),
"名称": remove_prohibited_str(name),
"星级": self.title2star(star_pic),
}
info[member_dict["名称"]] = member_dict
self.dump_data(info)
logger.info(f"{self.game_name_cn} 更新成功")
# 下载头像
for value in info.values():
await self.download_img(value["头像"], value["名称"])
# 下载星星
await self.download_img(
"https://patchwiki.biligame.com/images/bluearchive/thumb/e/e0/82nj2x9sxko473g7782r14fztd4zyky.png/15px-Star-1.png",
"star-1",
)
await self.download_img(
"https://patchwiki.biligame.com/images/bluearchive/thumb/0/0b/msaff2g0zk6nlyl1rrn7n1ri4yobcqc.png/30px-Star-2.png",
"star-2",
)
await self.download_img(
"https://patchwiki.biligame.com/images/bluearchive/thumb/8/8a/577yv79x1rwxk8efdccpblo0lozl158.png/46px-Star-3.png",
"star-3"
)
+51 -29
View File
@@ -3,7 +3,6 @@ import random
import dateparser import dateparser
from lxml import etree from lxml import etree
from PIL import ImageDraw from PIL import ImageDraw
from bs4 import BeautifulSoup
from datetime import datetime from datetime import datetime
from urllib.parse import unquote from urllib.parse import unquote
from typing import List, Optional, Tuple from typing import List, Optional, Tuple
@@ -32,8 +31,9 @@ class Operator(BaseData):
class PrtsHandle(BaseHandle[Operator]): class PrtsHandle(BaseHandle[Operator]):
def __init__(self): def __init__(self):
super().__init__("prts", "明日方舟", "#eff2f5") super().__init__(game_name="prts", game_name_cn="明日方舟")
self.max_star = 6 self.max_star = 6
self.game_card_color = "#eff2f5"
self.config = draw_config.prts self.config = draw_config.prts
self.ALL_OPERATOR: List[Operator] = [] self.ALL_OPERATOR: List[Operator] = []
@@ -41,8 +41,8 @@ class PrtsHandle(BaseHandle[Operator]):
def get_card(self, add: float) -> Operator: def get_card(self, add: float) -> Operator:
star = self.get_star( star = self.get_star(
[6, 5, 4, 3], star_list=[6, 5, 4, 3],
[ probability_list=[
self.config.PRTS_SIX_P + add, self.config.PRTS_SIX_P + add,
self.config.PRTS_FIVE_P, self.config.PRTS_FIVE_P,
self.config.PRTS_FOUR_P, self.config.PRTS_FOUR_P,
@@ -53,7 +53,7 @@ class PrtsHandle(BaseHandle[Operator]):
all_operators = [ all_operators = [
x x
for x in self.ALL_OPERATOR for x in self.ALL_OPERATOR
if x.star == star and not any([x.limited, x.event_only, x.recruit_only]) if x.star == star and not any([x.limited, x.recruit_only, x.event_only])
] ]
acquire_operator = None acquire_operator = None
@@ -74,7 +74,7 @@ class PrtsHandle(BaseHandle[Operator]):
acquire_operator = random.choice(all_operators) acquire_operator = random.choice(all_operators)
return acquire_operator return acquire_operator
def get_cards(self, count: int) -> List[Tuple[Operator, int]]: def get_cards(self, count: int, **kwargs) -> List[Tuple[Operator, int]]:
card_list = [] # 获取所有角色 card_list = [] # 获取所有角色
add = 0.0 add = 0.0
count_idx = 0 count_idx = 0
@@ -109,7 +109,8 @@ class PrtsHandle(BaseHandle[Operator]):
def _draw(self, count: int, **kwargs) -> Message: def _draw(self, count: int, **kwargs) -> Message:
index2card = self.get_cards(count) index2card = self.get_cards(count)
cards = [card[0] for card in self.get_cards(count)] """这里cards修复了抽卡图文不符的bug"""
cards = [card[0] for card in index2card]
up_list = [x.name for x in self.UP_EVENT.up_char] if self.UP_EVENT else [] up_list = [x.name for x in self.UP_EVENT.up_char] if self.UP_EVENT else []
result = self.format_result(index2card, up_list=up_list) result = self.format_result(index2card, up_list=up_list)
pool_info = self.format_pool_info() pool_info = self.format_pool_info()
@@ -162,7 +163,11 @@ class PrtsHandle(BaseHandle[Operator]):
def load_up_char(self): def load_up_char(self):
try: try:
data = self.load_data(f"draw_card_up/{self.game_name}_up_char.json") data = self.load_data(f"draw_card_up/{self.game_name}_up_char.json")
self.UP_EVENT = UpEvent.parse_obj(data.get("char", {})) """这里的 waring 有点模糊,更新游戏信息时没有up池的情况下也会报错,所以细分了一下"""
if not data:
logger.warning(f"当前无UP池或 {self.game_name}_up_char.json 文件不存在")
else:
self.UP_EVENT = UpEvent.parse_obj(data.get("char", {}))
except ValidationError: except ValidationError:
logger.warning(f"{self.game_name}_up_char 解析出错") logger.warning(f"{self.game_name}_up_char 解析出错")
@@ -185,14 +190,15 @@ class PrtsHandle(BaseHandle[Operator]):
avatar = char.xpath("./td[1]/div/div/div/a/img/@srcset")[0] avatar = char.xpath("./td[1]/div/div/div/a/img/@srcset")[0]
name = char.xpath("./td[2]/a/text()")[0] name = char.xpath("./td[2]/a/text()")[0]
star = char.xpath("./td[5]/text()")[0] star = char.xpath("./td[5]/text()")[0]
sources = str(char.xpath("./td[8]/text()")[0]).split("\n") """这里sources修好了干员获取标签有问题的bug,如三星只能抽到卡缇就是这个原因"""
sources = [_.strip('\n') for _ in char.xpath("./td[8]/text()")]
except IndexError: except IndexError:
continue continue
member_dict = { member_dict = {
"头像": unquote(str(avatar).split(" ")[-2]), "头像": unquote(str(avatar).split(" ")[-2]),
"名称": remove_prohibited_str(str(name).strip()), "名称": remove_prohibited_str(str(name).strip()),
"星级": int(str(star).strip()), "星级": int(str(star).strip()),
"获取途径": [s for s in sources if s], "获取途径": sources,
} }
info[member_dict["名称"]] = member_dict info[member_dict["名称"]] = member_dict
self.dump_data(info) self.dump_data(info)
@@ -208,6 +214,7 @@ class PrtsHandle(BaseHandle[Operator]):
await self.update_up_char() await self.update_up_char()
async def update_up_char(self): async def update_up_char(self):
"""重载卡池"""
announcement_url = "https://ak.hypergryph.com/news.html" announcement_url = "https://ak.hypergryph.com/news.html"
result = await self.get_url(announcement_url) result = await self.get_url(announcement_url)
if not result: if not result:
@@ -221,41 +228,53 @@ class PrtsHandle(BaseHandle[Operator]):
end_time = None end_time = None
up_chars = [] up_chars = []
pool_img = "" pool_img = ""
title = "" for activity_url in activity_urls[:10]: # 减少响应时间, 10个就够了
for activity_url in activity_urls:
activity_url = f"https://ak.hypergryph.com{activity_url}" activity_url = f"https://ak.hypergryph.com{activity_url}"
result = await self.get_url(activity_url) result = await self.get_url(activity_url)
if not result: if not result:
logger.warning(f"{self.game_name_cn}获取公告 {activity_url} 出错") logger.warning(f"{self.game_name_cn}获取公告 {activity_url} 出错")
continue continue
soup = BeautifulSoup(result, "lxml")
contents = soup.find_all("p") """因为鹰角的前端太自由了,这里重写了匹配规则以尽可能避免因为前端乱七八糟而导致的重载失败"""
dom = etree.HTML(result, etree.HTMLParser())
contents = dom.xpath(
"//div[@class='article-content']/p/text() | //div[@class='article-content']/p/span/text() | //div[@class='article-content']/div[@class='media-wrap image-wrap']/img/@src"
)
title = ""
time = ""
chars: List[str] = []
for index, content in enumerate(contents): for index, content in enumerate(contents):
if re.search("(.*)(寻访|复刻).*?开启", content.text): if re.search("(.*)(寻访|复刻).*?开启", content):
title = content.text title = re.split(r"[【】]", content)
if "【" in title and "】" in title: title = "".join(title[1:-1]) if "-" in title else title[1]
title = re.split(r"[【】]", title)[1] lines = [contents[index-2+_] for _ in range(8)] # 从 -2 开始是因为xpath获取的时间有的会在寻访开启这一句之前
lines = [str(contents[index + i + 1].text) for i in range(5)] lines.append("") # 防止IndexError,加个空字符串
time = "" for idx, line in enumerate(lines):
chars: List[str] = []
for line in lines:
match = re.search( match = re.search(
r"(\d{1,2}月\d{1,2}日.*?-.*?\d{1,2}月\d{1,2}日.*?$)", line r"(\d{1,2}月\d{1,2}日.*?-.*?\d{1,2}月\d{1,2}日.*?$)", line
) )
if match: if match:
time = match.group(1) time = match.group(1)
if "★" in line: """因为 <p> 的诡异排版,所以有了下面的一段"""
chars.append(line) if ("★★" in line and "%" in line) or ("★★" in line and "%" in lines[idx + 1]):
chars.append(line) if ("★★" in line and "%" in line) else chars.append(line + lines[idx + 1])
if not time: if not time:
continue continue
start, end = time.replace("月", "/").replace("日", "").split("-")[:2] start, end = time.replace("月", "/").replace("日", " ").split("-")[:2] # 日替换为空格是因为有日后面不接空格的情况,导致 split 出问题
start_time = dateparser.parse(start) start_time = dateparser.parse(start)
end_time = dateparser.parse(end) end_time = dateparser.parse(end)
pool_img = content.find_previous("img")["src"] pool_img = contents[index-2]
r"""两类格式:用/分割,用\分割;★+(概率)+名字,★+名字+(概率)"""
for char in chars: for char in chars:
star = char.split("(")[0].count("★") star = char.split("(")[0].count("★")
name = re.split(r"[:(]", char)[1] name = re.split(r"[:(]", char)[1] if "★(" not in char else re.split("):", char)[1] # 有的括号在前面有的在后面
names = name.split("/") if "/" in name else [name] if "\\" in name:
names = name.split("\\")
elif "/" in name:
names = name.split("/")
else:
names = [name] # 既有用/分割的,又有用\分割的
names = [name.replace("[限定]", "").strip() for name in names] names = [name.replace("[限定]", "").strip() for name in names]
if "权值" in char: if "权值" in char:
match = re.search(r"(在.*?以.*?(\d+).*?倍权值.*?)", char) match = re.search(r"(在.*?以.*?(\d+).*?倍权值.*?)", char)
@@ -269,7 +288,10 @@ class PrtsHandle(BaseHandle[Operator]):
up_chars.append( up_chars.append(
UpChar(name=name, star=star, limited=False, zoom=zoom) UpChar(name=name, star=star, limited=False, zoom=zoom)
) )
break if start_time <= datetime.now() <= end_time: # 跳过过时的卡池
break # 这里break会导致个问题:如果一个公告里有两个池子,会漏掉下面的池子,比如 5.19 的定向寻访。但目前我也没啥好想法解决
chars: List[str] = [] # 查找下一个卡池之前清空 chars
up_chars = [] # 查找下一个卡池之前清空 up_chars
if title and start_time and end_time: if title and start_time and end_time:
if start_time <= datetime.now() <= end_time: if start_time <= datetime.now() <= end_time:
self.UP_EVENT = UpEvent( self.UP_EVENT = UpEvent(
+24 -37
View File
@@ -1,58 +1,34 @@
from httpx import AsyncClient
from datetime import datetime from datetime import datetime
from nonebot.log import logger from nonebot.log import logger
from nonebot.adapters.onebot.v11 import Bot from nonebot.adapters.onebot.v11 import Bot
from configs.config import NICKNAME from configs.config import NICKNAME
from utils.http_utils import AsyncHttpx
# 获取所有 Epic Game Store 促销游戏 # 获取所有 Epic Game Store 促销游戏
# 方法参考:RSSHub /epicgames 路由 # 方法参考:RSSHub /epicgames 路由
# https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js # https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js
async def get_epic_game(): async def get_epic_game():
# 现在没用 graphql 辣
"""prv_graphql Code
epic_url = "https://www.epicgames.com/store/backend/graphql-proxy"
headers = {
"Referer": "https://www.epicgames.com/store/zh-CN/",
"Content-Type": "application/json; charset=utf-8",
}
data = {
"query": "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, $keywords: String, $locale: String, $namespace: String, $sortBy: String, $sortDir: String, $start: Int, $tag: String, $withPrice: Boolean = false, $withPromotions: Boolean = false) {\n Catalog {\n searchStore(allowCountries: $allowCountries, category: $category, count: $count, country: $country, keywords: $keywords, locale: $locale, namespace: $namespace, sortBy: $sortBy, sortDir: $sortDir, start: $start, tag: $tag) {\n elements {\n title\n id\n namespace\n description\n effectiveDate\n keyImages {\n type\n url\n }\n seller {\n id\n name\n }\n productSlug\n urlSlug\n url\n items {\n id\n namespace\n }\n customAttributes {\n key\n value\n }\n categories {\n path\n }\n price(country: $country) @include(if: $withPrice) {\n totalPrice {\n discountPrice\n originalPrice\n voucherDiscount\n discount\n currencyCode\n currencyInfo {\n decimals\n }\n fmtPrice(locale: $locale) {\n originalPrice\n discountPrice\n intermediatePrice\n }\n }\n lineOffers {\n appliedRules {\n id\n endDate\n discountSetting {\n discountType\n }\n }\n }\n }\n promotions(category: $category) @include(if: $withPromotions) {\n promotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n upcomingPromotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n }\n }\n paging {\n count\n total\n }\n }\n }\n}\n",
"variables": {
"allowCountries": "CN",
"category": "freegames",
"count": 1000,
"country": "CN",
"locale": "zh-CN",
"sortBy": "effectiveDate",
"sortDir": "asc",
"withPrice": True,
"withPromotions": True,
},
}
"""
epic_url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN" epic_url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN"
headers = { headers = {
"Referer": "https://www.epicgames.com/store/zh-CN/", "Referer": "https://www.epicgames.com/store/zh-CN/",
"Content-Type": "application/json; charset=utf-8", "Content-Type": "application/json; charset=utf-8",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36",
} }
async with AsyncClient(headers=headers) as client: try:
try: res = await AsyncHttpx.get(epic_url, headers=headers, timeout=10)
res = await client.get(epic_url, timeout=10.0) res_json = res.json()
res_json = res.json() games = res_json["data"]["Catalog"]["searchStore"]["elements"]
games = res_json["data"]["Catalog"]["searchStore"]["elements"] return games
return games except Exception as e:
except Exception as e: logger.error(f"Epic 访问接口错误 {type(e)}:{e}")
logger.error(str(e)) return None
return None
# 获取 Epic Game Store 免费游戏信息 # 获取 Epic Game Store 免费游戏信息
# 处理免费游戏的信息方法借鉴 pip 包 epicstore_api 示例 # 处理免费游戏的信息方法借鉴 pip 包 epicstore_api 示例
# https://github.com/SD4RK/epicstore_api/blob/master/examples/free_games_example.py # https://github.com/SD4RK/epicstore_api/blob/master/examples/free_games_example.py
async def get_epic_free(bot: Bot, Type_Event: str): async def get_epic_free(bot: Bot, type_event: str):
games = await get_epic_game() games = await get_epic_game()
if not games: if not games:
return "Epic 可能又抽风啦,请稍后再试(", 404 return "Epic 可能又抽风啦,请稍后再试(", 404
@@ -81,7 +57,7 @@ async def get_epic_free(bot: Bot, Type_Event: str):
end_date = datetime.fromisoformat(end_date_iso).strftime( end_date = datetime.fromisoformat(end_date_iso).strftime(
"%b.%d %H:%M" "%b.%d %H:%M"
) )
if Type_Event == "Group": if type_event == "Group":
_message = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format( _message = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format(
game_corp, game_name, game_price, start_date, end_date game_corp, game_name, game_price, start_date, end_date
) )
@@ -101,8 +77,19 @@ async def get_epic_free(bot: Bot, Type_Event: str):
msg_list.append(msg) msg_list.append(msg)
else: else:
for image in game["keyImages"]: for image in game["keyImages"]:
if image["type"] == "Thumbnail": if (
image.get("url")
and not game_thumbnail
and image["type"]
in [
"Thumbnail",
"VaultOpened",
"DieselStoreFrontWide",
"OfferImageWide",
]
):
game_thumbnail = image["url"] game_thumbnail = image["url"]
break
for pair in game["customAttributes"]: for pair in game["customAttributes"]:
if pair["key"] == "developerName": if pair["key"] == "developerName":
game_dev = pair["value"] game_dev = pair["value"]
@@ -127,7 +114,7 @@ async def get_epic_free(bot: Bot, Type_Event: str):
game_url = "https://www.epicgames.com/store/zh-CN/p/{}".format( game_url = "https://www.epicgames.com/store/zh-CN/p/{}".format(
game_url_part game_url_part
) )
if Type_Event == "Group": if type_event == "Group":
_message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format( _message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format(
game_thumbnail, game_thumbnail,
game_name, game_name,
+11 -9
View File
@@ -9,6 +9,7 @@ from nonebot.adapters.onebot.v11 import GroupMessageEvent
from configs.config import Config from configs.config import Config
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from services.log import logger from services.log import logger
from configs.config import NICKNAME
__zx_plugin_name__ = "复读" __zx_plugin_name__ = "复读"
@@ -74,15 +75,15 @@ class Fudu:
_fudu_list = Fudu() _fudu_list = Fudu()
fudu = on_message(permission=GROUP, priority=9) fudu = on_message(permission=GROUP, priority=999)
@fudu.handle() @fudu.handle()
async def _(event: GroupMessageEvent): async def _(event: GroupMessageEvent):
if event.is_tome(): if event.is_tome():
return return
if get_message_text(event.json()): if msg := get_message_text(event.json()):
if get_message_text(event.json()).find("@可爱的小真寻") != -1: if msg.startswith(f"@可爱的{NICKNAME}"):
await fudu.finish("复制粘贴的虚空艾特?", at_sender=True) await fudu.finish("复制粘贴的虚空艾特?", at_sender=True)
img = get_message_img(event.json()) img = get_message_img(event.json())
msg = get_message_text(event.json()) msg = get_message_text(event.json())
@@ -105,20 +106,21 @@ async def _(event: GroupMessageEvent):
"fudu", "FUDU_PROBABILITY" "fudu", "FUDU_PROBABILITY"
) and not _fudu_list.is_repeater(event.group_id): ) and not _fudu_list.is_repeater(event.group_id):
if random.random() < 0.2: if random.random() < 0.2:
await fudu.finish("[[_task|fudu]]打断施法!") if msg.endswith("打断施法!"):
await fudu.finish("[[_task|fudu]]打断" + msg)
else:
await fudu.finish("[[_task|fudu]]打断施法!")
_fudu_list.set_repeater(event.group_id) _fudu_list.set_repeater(event.group_id)
if img and msg: if img and msg:
rst = msg + image(f"compare_{event.group_id}_img.jpg", "temp") rst = msg + image(TEMP_PATH / f"compare_{event.group_id}_img.jpg")
elif img: elif img:
rst = image(f"compare_{event.group_id}_img.jpg", "temp") rst = image(TEMP_PATH / f"compare_{event.group_id}_img.jpg")
elif msg: elif msg:
rst = msg rst = msg
else: else:
rst = "" rst = ""
if rst: if rst:
if rst.endswith("打断施法!"): await fudu.finish("[[_task|fudu]]" + rst)
rst = "打断" + rst
await fudu.send("[[_task|fudu]]" + rst)
async def get_fudu_img_hash(url, group_id): async def get_fudu_img_hash(url, group_id):
+1 -1
View File
@@ -35,7 +35,7 @@ Config.add_plugin_config(
default_value=True, default_value=True,
) )
almanac = on_command("原神黄历", priority=5, block=True) almanac = on_command("原神黄历", priority=15, block=True)
ALC_PATH = IMAGE_PATH / "genshin" / "alc" ALC_PATH = IMAGE_PATH / "genshin" / "alc"
+1 -1
View File
@@ -30,7 +30,7 @@ class Map:
ratio: float = 1, ratio: float = 1,
): ):
""" """
参数: 参数:
:param resource_name: 资源名称 :param resource_name: 资源名称
:param center_point: 中心点 :param center_point: 中心点
:param deviation: 坐标误差 :param deviation: 坐标误差
@@ -1,6 +1,6 @@
from pathlib import Path
from typing import Tuple, Optional, List from typing import Tuple, Optional, List
from configs.path_config import IMAGE_PATH, TEXT_PATH from configs.path_config import IMAGE_PATH, TEXT_PATH
from PIL.Image import UnidentifiedImageError
from utils.message_builder import image from utils.message_builder import image
from services.log import logger from services.log import logger
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
@@ -137,7 +137,7 @@ async def download_resource_data(semaphore: Semaphore):
asyncio.ensure_future( asyncio.ensure_future(
download_image( download_image(
img_url, img_url,
f"{icon_path}/{id_}.png", icon_path / f"{id_}.png",
semaphore, semaphore,
True, True,
) )
@@ -179,7 +179,7 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
map_url = _map_data["url"] map_url = _map_data["url"]
await download_image( await download_image(
map_url, map_url,
f"{map_path}/{idx}.png", map_path / f"{idx}.png",
semaphore, semaphore,
force_flag=flag, force_flag=flag,
) )
@@ -228,15 +228,14 @@ async def download_resource_type():
except (TimeoutError, ConnectTimeout): except (TimeoutError, ConnectTimeout):
logger.warning("下载原神资源类型数据超时....") logger.warning("下载原神资源类型数据超时....")
except Exception as e: except Exception as e:
logger.error(f"载原神资源类型数据超时 {type(e)}:{e}") logger.error(f"载原神资源类型数据错误 {type(e)}:{e}")
# 初始化资源图标 # 初始化资源图标
def gen_icon(icon: str): def gen_icon(icon: Path):
A = BuildImage(0, 0, background=f"{icon_path}/box.png") A = BuildImage(0, 0, background=f"{icon_path}/box.png")
B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png") B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png")
icon_ = icon_path / f"{icon}" icon_img = BuildImage(115, 115, background=icon)
icon_img = BuildImage(115, 115, background=icon_)
icon_img.circle() icon_img.circle()
B.paste(icon_img, (17, 10), True) B.paste(icon_img, (17, 10), True)
B.paste(A, alpha=True) B.paste(A, alpha=True)
@@ -247,22 +246,22 @@ def gen_icon(icon: str):
# 下载图片 # 下载图片
async def download_image( async def download_image(
img_url: str, img_url: str,
path: str, path: Path,
semaphore: Semaphore, semaphore: Semaphore,
gen_flag: bool = False, gen_flag: bool = False,
force_flag: bool = False, force_flag: bool = False,
): ):
async with semaphore: async with semaphore:
try: try:
if not os.path.exists(path) or not is_valid or force_flag: if not path.exists() or not is_valid(path) or force_flag:
if await AsyncHttpx.download_file(img_url, path, timeout=10): if await AsyncHttpx.download_file(img_url, path, timeout=10):
logger.info(f"下载原神资源图标:{img_url}") logger.info(f"下载原神资源图标:{img_url}")
if gen_flag: if gen_flag:
gen_icon(path) gen_icon(path)
else: else:
logger.info(f"下载原神资源图标:{img_url} 失败,等待下次更新...") logger.info(f"下载原神资源图标:{img_url} 失败,等待下次更新...")
except UnidentifiedImageError: except Exception as e:
logger.warning(f"原神图片打开错误..已删除,等待下次更新... file: {path}") logger.warning(f"原神图片错误..已删除,等待下次更新... file: {path} {type(e)}:{e}")
if os.path.exists(path): if os.path.exists(path):
os.remove(path) os.remove(path)
+46 -46
View File
@@ -25,9 +25,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def add_uid(cls, user_qq: int, uid: int): async def add_uid(cls, user_qq: int, uid: int):
""" """
说明: 说明:
添加一个uid 添加一个uid
参数: 参数:
:param user_qq: 用户qq :param user_qq: 用户qq
:param uid: 原神uid :param uid: 原神uid
""" """
@@ -44,9 +44,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def set_mys_id(cls, uid: int, mys_id: int) -> bool: async def set_mys_id(cls, uid: int, mys_id: int) -> bool:
""" """
说明: 说明:
设置米游社id 设置米游社id
参数: 参数:
:param uid: 原神uid :param uid: 原神uid
:param mys_id: 米游社id :param mys_id: 米游社id
""" """
@@ -60,9 +60,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def set_bind_group(cls, uid: int, bind_group) -> bool: async def set_bind_group(cls, uid: int, bind_group) -> bool:
""" """
说明: 说明:
绑定group_id,除私聊外的提醒将在此群发送 绑定group_id,除私聊外的提醒将在此群发送
参数: 参数:
:param uid: uid :param uid: uid
:param bind_group: 群号 :param bind_group: 群号
""" """
@@ -76,9 +76,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_bind_group(cls, uid: int) -> Optional[int]: async def get_bind_group(cls, uid: int) -> Optional[int]:
""" """
说明: 说明:
获取用户绑定的群聊 获取用户绑定的群聊
参数: 参数:
:param uid: uid :param uid: uid
""" """
user = await cls.query.where(cls.uid == uid).gino.first() user = await cls.query.where(cls.uid == uid).gino.first()
@@ -89,9 +89,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def set_cookie(cls, uid: int, cookie: str) -> bool: async def set_cookie(cls, uid: int, cookie: str) -> bool:
""" """
说明: 说明:
设置cookie 设置cookie
参数: 参数:
:param uid: 原神uid :param uid: 原神uid
:param cookie: 米游社id :param cookie: 米游社id
""" """
@@ -105,9 +105,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def set_resin_remind(cls, uid: int, flag: bool) -> bool: async def set_resin_remind(cls, uid: int, flag: bool) -> bool:
""" """
说明: 说明:
设置体力提醒 设置体力提醒
参数: 参数:
:param uid: 原神uid :param uid: 原神uid
:param flag: 开关状态 :param flag: 开关状态
""" """
@@ -121,9 +121,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def set_user_resin_recovery_time(cls, uid: int, date: datetime): async def set_user_resin_recovery_time(cls, uid: int, date: datetime):
""" """
说明: 说明:
设置体力完成时间 设置体力完成时间
参数: 参数:
:param uid: uid :param uid: uid
:param date: 提醒日期 :param date: 提醒日期
""" """
@@ -134,9 +134,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_user_resin_recovery_time(cls, uid: int) -> Optional[datetime]: async def get_user_resin_recovery_time(cls, uid: int) -> Optional[datetime]:
""" """
说明: 说明:
获取体力完成时间 获取体力完成时间
参数: 参数:
:param uid: uid :param uid: uid
""" """
u = await cls.query.where(cls.uid == uid).gino.first() u = await cls.query.where(cls.uid == uid).gino.first()
@@ -147,7 +147,7 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_all_resin_remind_user(cls) -> List["Genshin"]: async def get_all_resin_remind_user(cls) -> List["Genshin"]:
""" """
说明: 说明:
获取所有开启体力提醒的用户 获取所有开启体力提醒的用户
""" """
return await cls.query.where(cls.resin_remind == True).gino.all() return await cls.query.where(cls.resin_remind == True).gino.all()
@@ -155,9 +155,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def clear_resin_remind_time(cls, uid: int) -> bool: async def clear_resin_remind_time(cls, uid: int) -> bool:
""" """
说明: 说明:
清空提醒日期 清空提醒日期
参数: 参数:
:param uid: uid :param uid: uid
""" """
user = await cls.query.where(cls.uid == uid).gino.first() user = await cls.query.where(cls.uid == uid).gino.first()
@@ -169,9 +169,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def set_auto_sign(cls, uid: int, flag: bool) -> bool: async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
""" """
说明: 说明:
设置米游社/原神自动签到 设置米游社/原神自动签到
参数: 参数:
:param uid: 原神uid :param uid: 原神uid
:param flag: 开关状态 :param flag: 开关状态
""" """
@@ -185,7 +185,7 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_all_auto_sign_user(cls) -> List["Genshin"]: async def get_all_auto_sign_user(cls) -> List["Genshin"]:
""" """
说明: 说明:
获取所有开启自动签到的用户 获取所有开启自动签到的用户
""" """
return await cls.query.where(cls.auto_sign == True).gino.all() return await cls.query.where(cls.auto_sign == True).gino.all()
@@ -193,7 +193,7 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_all_sign_user(cls) -> List["Genshin"]: async def get_all_sign_user(cls) -> List["Genshin"]:
""" """
说明: 说明:
获取 原神 所有今日签到用户 获取 原神 所有今日签到用户
""" """
return await cls.query.where(cls.auto_sign_time != None).gino.all() return await cls.query.where(cls.auto_sign_time != None).gino.all()
@@ -201,9 +201,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def clear_sign_time(cls, uid: int) -> bool: async def clear_sign_time(cls, uid: int) -> bool:
""" """
说明: 说明:
清空签到日期 清空签到日期
参数: 参数:
:param uid: uid :param uid: uid
""" """
user = await cls.query.where(cls.uid == uid).gino.first() user = await cls.query.where(cls.uid == uid).gino.first()
@@ -215,9 +215,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def random_sign_time(cls, uid: int) -> Optional[datetime]: async def random_sign_time(cls, uid: int) -> Optional[datetime]:
""" """
说明: 说明:
随机签到时间 随机签到时间
说明: 说明:
:param uid: uid :param uid: uid
""" """
query = cls.query.where(cls.uid == uid).with_for_update() query = cls.query.where(cls.uid == uid).with_for_update()
@@ -245,9 +245,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_query_cookie(cls, uid: int) -> Optional[str]: async def get_query_cookie(cls, uid: int) -> Optional[str]:
""" """
说明: 说明:
获取查询角色信息cookie 获取查询角色信息cookie
参数: 参数:
:param uid: 原神uid :param uid: 原神uid
""" """
# 查找用户今日是否已经查找过,防止重复 # 查找用户今日是否已经查找过,防止重复
@@ -265,9 +265,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_user_cookie(cls, uid: int, flag: bool = False) -> Optional[str]: async def get_user_cookie(cls, uid: int, flag: bool = False) -> Optional[str]:
""" """
说明: 说明:
获取用户cookie 获取用户cookie
参数: 参数:
:param uid:原神uid :param uid:原神uid
:param flag:必须使用自己的cookie :param flag:必须使用自己的cookie
""" """
@@ -279,9 +279,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_user_by_qq(cls, user_qq: int) -> Optional["Genshin"]: async def get_user_by_qq(cls, user_qq: int) -> Optional["Genshin"]:
""" """
说明: 说明:
通过qq获取用户对象 通过qq获取用户对象
参数: 参数:
:param user_qq: qq :param user_qq: qq
""" """
return await cls.query.where(cls.user_qq == user_qq).gino.first() return await cls.query.where(cls.user_qq == user_qq).gino.first()
@@ -289,9 +289,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_user_by_uid(cls, uid: int) -> Optional["Genshin"]: async def get_user_by_uid(cls, uid: int) -> Optional["Genshin"]:
""" """
说明: 说明:
通过uid获取用户对象 通过uid获取用户对象
参数: 参数:
:param uid: qq :param uid: qq
""" """
return await cls.query.where(cls.uid == uid).gino.first() return await cls.query.where(cls.uid == uid).gino.first()
@@ -299,9 +299,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def get_user_uid(cls, user_qq: int) -> Optional[int]: async def get_user_uid(cls, user_qq: int) -> Optional[int]:
""" """
说明: 说明:
获取用户uid 获取用户uid
参数: 参数:
:param user_qq:用户qq :param user_qq:用户qq
""" """
return await cls._get_user_data(user_qq, None, "uid") return await cls._get_user_data(user_qq, None, "uid")
@@ -311,7 +311,7 @@ class Genshin(db.Model):
""" """
说嘛: 说嘛:
获取用户米游社id 获取用户米游社id
参数: 参数:
:param uid:原神id :param uid:原神id
""" """
return await cls._get_user_data(None, uid, "mys_id") return await cls._get_user_data(None, uid, "mys_id")
@@ -319,9 +319,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def delete_user_cookie(cls, uid: int): async def delete_user_cookie(cls, uid: int):
""" """
说明: 说明:
删除用户cookie 删除用户cookie
参数: 参数:
:param uid: 原神uid :param uid: 原神uid
""" """
query = cls.query.where(cls.uid == uid).with_for_update() query = cls.query.where(cls.uid == uid).with_for_update()
@@ -332,9 +332,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def delete_user(cls, user_qq: int): async def delete_user(cls, user_qq: int):
""" """
说明: 说明:
删除用户数据 删除用户数据
参数: 参数:
:param user_qq: 用户qq :param user_qq: 用户qq
""" """
query = cls.query.where(cls.user_qq == user_qq).with_for_update() query = cls.query.where(cls.user_qq == user_qq).with_for_update()
@@ -347,9 +347,9 @@ class Genshin(db.Model):
@classmethod @classmethod
async def _add_query_uid(cls, uid: int, cookie_uid: int): async def _add_query_uid(cls, uid: int, cookie_uid: int):
""" """
说明: 说明:
添加每日查询重复uid的cookie 添加每日查询重复uid的cookie
参数: 参数:
:param uid: 原神uid :param uid: 原神uid
:param cookie_uid: cookie的uid :param cookie_uid: cookie的uid
""" """
@@ -362,9 +362,9 @@ class Genshin(db.Model):
cls, user_qq: Optional[int], uid: Optional[int], type_: str cls, user_qq: Optional[int], uid: Optional[int], type_: str
) -> Optional[Union[int, str]]: ) -> Optional[Union[int, str]]:
""" """
说明: 说明:
获取用户数据 获取用户数据
参数: 参数:
:param user_qq: 用户qq :param user_qq: 用户qq
:param uid: uid :param uid: uid
:param type_: 数据类型 :param type_: 数据类型
@@ -128,7 +128,7 @@ async def get_character(
) -> Optional[dict]: ) -> Optional[dict]:
try: try:
req = await AsyncHttpx.post( req = await AsyncHttpx.post(
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/character", url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character",
headers={ headers={
"Accept": "application/json, text/plain, */*", "Accept": "application/json, text/plain, */*",
"DS": get_ds( "DS": get_ds(
@@ -182,7 +182,7 @@ def parsed_data(
role_data = { role_data = {
"active_day_number": data["stats"]["active_day_number"], # 活跃天数 "active_day_number": data["stats"]["active_day_number"], # 活跃天数
"achievement_number": data["stats"]["achievement_number"], # 达成成就数量 "achievement_number": data["stats"]["achievement_number"], # 达成成就数量
"win_rate": data["stats"]["win_rate"], # "win_rate": data["stats"]["win_rate"],
"anemoculus_number": data["stats"]["anemoculus_number"], # 风神瞳已收集 "anemoculus_number": data["stats"]["anemoculus_number"], # 风神瞳已收集
"geoculus_number": data["stats"]["geoculus_number"], # 岩神瞳已收集 "geoculus_number": data["stats"]["geoculus_number"], # 岩神瞳已收集
"avatar_number": data["stats"]["avatar_number"], # 获得角色数量 "avatar_number": data["stats"]["avatar_number"], # 获得角色数量
@@ -232,7 +232,7 @@ async def get_mys_data(uid: str, mys_id: Optional[str]) -> Optional[List[Dict]]:
if mys_id: if mys_id:
try: try:
req = await AsyncHttpx.get( req = await AsyncHttpx.get(
url=f"https://api-takumi.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}", url=f"https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
headers={ headers={
"DS": get_ds(f"uid={mys_id}"), "DS": get_ds(f"uid={mys_id}"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"), "x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
@@ -300,6 +300,8 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2") region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2")
height = 0 height = 0
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]: for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]:
if not world_data_dict.get(country):
continue
x = BuildImage(790, 250, color="#3A4467") x = BuildImage(790, 250, color="#3A4467")
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png") logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
tmp_bk = BuildImage(770, 230, color="#606779") tmp_bk = BuildImage(770, 230, color="#606779")
@@ -328,18 +330,19 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
f"{world_data_dict['层岩巨渊']['exploration_percentage'] / 10}%", f"{world_data_dict['层岩巨渊']['exploration_percentage'] / 10}%",
fill=(255, 255, 255), fill=(255, 255, 255),
) )
content_bk.text((300, 85), "地下矿区探索", fill=(239, 211, 114)) if world_data_dict.get('层岩巨渊·地下矿区'):
content_bk.text( content_bk.text((300, 85), "地下矿区探索", fill=(239, 211, 114))
(570, 85), content_bk.text(
f"{world_data_dict['层岩巨渊·地下矿区']['exploration_percentage'] / 10}%", (570, 85),
fill=(255, 255, 255), f"{world_data_dict['层岩巨渊·地下矿区']['exploration_percentage'] / 10}%",
) fill=(255, 255, 255),
content_bk.text((300, 150), "流明石触媒", fill=(239, 211, 114)) )
content_bk.text( content_bk.text((300, 150), "流明石触媒", fill=(239, 211, 114))
(570, 150), content_bk.text(
f"LV.{world_data_dict['层岩巨渊·地下矿区']['offerings'][0]['level']}", (570, 150),
fill=(255, 255, 255), f"LV.{world_data_dict['层岩巨渊·地下矿区']['offerings'][0]['level']}",
) fill=(255, 255, 255),
)
elif country in ["龙脊雪山"]: elif country in ["龙脊雪山"]:
content_bk.text((300, 40), "探索", fill=(239, 211, 114)) content_bk.text((300, 40), "探索", fill=(239, 211, 114))
content_bk.text( content_bk.text(
@@ -1,3 +1,5 @@
from nonebot.adapters.onebot.v11 import ActionFailed
from utils.utils import get_bot, scheduler from utils.utils import get_bot, scheduler
from utils.message_builder import at from utils.message_builder import at
from models.group_member_info import GroupInfoUser from models.group_member_info import GroupInfoUser
@@ -84,30 +86,28 @@ async def _():
if await Genshin.get_user_resin_recovery_time(u.uid) > datetime.now( if await Genshin.get_user_resin_recovery_time(u.uid) > datetime.now(
pytz.timezone("Asia/Shanghai") pytz.timezone("Asia/Shanghai")
): ):
date = await Genshin.get_user_resin_recovery_time(u.uid) # date = await Genshin.get_user_resin_recovery_time(u.uid) # 不能要,因为可能在这期间用户使用了树脂
scheduler.add_job( add_job(u.user_qq, u.uid)
_remind, # scheduler.add_job(
"date", # _remind,
run_date=date.replace(microsecond=0), # "date",
id=f"genshin_resin_remind_{u.uid}_{u.user_qq}", # run_date=date.replace(microsecond=0),
args=[u.user_qq, u.uid], # id=f"genshin_resin_remind_{u.uid}_{u.user_qq}",
) # args=[u.user_qq, u.uid],
# )
logger.info( logger.info(
f"genshin_resin_remind add_job:USER:{u.user_qq} UID:{u.uid} " f"genshin_resin_remind add_job:USER:{u.user_qq} UID:{u.uid}启动原神树脂提醒 "
f"{date} 原神树脂提醒"
) )
else: else:
await Genshin.clear_resin_remind_time(u.uid) await Genshin.clear_resin_remind_time(u.uid)
add_job(u.user_qq, u.uid) add_job(u.user_qq, u.uid)
logger.info( logger.info(
f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid} " f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid}启动原神树脂提醒 "
f"{date} 原神树脂提醒"
) )
else: else:
add_job(u.user_qq, u.uid) add_job(u.user_qq, u.uid)
logger.info( logger.info(
f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid} " f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid}启动原神树脂提醒 "
f"{date} 原神树脂提醒"
) )
@@ -142,17 +142,19 @@ async def _remind(user_id: int, uid: str):
now = datetime.now(pytz.timezone("Asia/Shanghai")) now = datetime.now(pytz.timezone("Asia/Shanghai"))
next_time = None next_time = None
if code == 200: if code == 200:
current_resin = data["current_resin"] # 当前树脂 current_resin = int(data["current_resin"]) # 当前树脂
max_resin = data["max_resin"] # 最大树脂 max_resin = int(data["max_resin"]) # 最大树脂
msg = f"你的已经存了 {current_resin} 个树脂了!不要忘记刷掉!" msg = f"你的已经存了 {current_resin} 个树脂了!不要忘记刷掉!"
# resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间 # resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间
if current_resin < max_resin: if current_resin < max_resin:
user_manager.remove(uid) user_manager.remove(uid)
user_manager.remove_overflow(uid) user_manager.remove_overflow(uid)
if max_resin - 40 < current_resin <= max_resin - 20: if current_resin < max_resin - 40:
next_time = now + timedelta(minutes=(max_resin - 20 - current_resin + 1) * 8, seconds=10) next_time = now + timedelta(minutes=(max_resin - 40 - current_resin) * 8)
elif current_resin < max_resin: elif max_resin - 40 <= current_resin < max_resin - 20:
next_time = now + timedelta(minutes=(max_resin - current_resin) * 8, seconds=10) next_time = now + timedelta(minutes=(max_resin - 20 - current_resin) * 8)
elif max_resin - 20 <= current_resin < max_resin:
next_time = now + timedelta(minutes=(max_resin - current_resin) * 8)
elif current_resin == max_resin: elif current_resin == max_resin:
custom_overflow_resin = Config.get_config("resin_remind", "CUSTOM_RESIN_OVERFLOW_REMIND") custom_overflow_resin = Config.get_config("resin_remind", "CUSTOM_RESIN_OVERFLOW_REMIND")
if user_manager.is_overflow(uid) and custom_overflow_resin: if user_manager.is_overflow(uid) and custom_overflow_resin:
@@ -162,6 +164,7 @@ async def _remind(user_id: int, uid: str):
msg = f"你的树脂都溢出 {custom_overflow_resin} 个了!浪费可耻!" msg = f"你的树脂都溢出 {custom_overflow_resin} 个了!浪费可耻!"
else: else:
next_time = now + timedelta(minutes=40 * 8 + random.randint(5, 50)) next_time = now + timedelta(minutes=40 * 8 + random.randint(5, 50))
if not user_manager.exists(uid) and current_resin >= max_resin - 40: if not user_manager.exists(uid) and current_resin >= max_resin - 40:
if current_resin == max_resin: if current_resin == max_resin:
user_manager.append(uid) user_manager.append(uid)
@@ -178,10 +181,14 @@ async def _remind(user_id: int, uid: str):
group_list = await GroupInfoUser.get_user_all_group(user_id) group_list = await GroupInfoUser.get_user_all_group(user_id)
if group_list: if group_list:
group_id = group_list[0] group_id = group_list[0]
await bot.send_group_msg( try:
group_id=group_id, await bot.send_group_msg(
message=at(user_id) + msg group_id=group_id,
) message=at(user_id) + msg
)
except ActionFailed as e:
logger.error(f"树脂提醒推送发生错误 {type(e)}:{e}")
if not next_time: if not next_time:
if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"): if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"):
await Genshin.set_resin_remind(int(uid), False) await Genshin.set_resin_remind(int(uid), False)
@@ -192,10 +199,13 @@ async def _remind(user_id: int, uid: str):
user_manager.remove_error_count(uid) user_manager.remove_error_count(uid)
await Genshin.set_user_resin_recovery_time(int(uid), next_time) await Genshin.set_user_resin_recovery_time(int(uid), next_time)
scheduler.add_job( scheduler.add_job(
_remind,
_remind, _remind,
"date", "date",
run_date=next_time, run_date=next_time,
id=f"genshin_resin_remind_{uid}_{user_id}", id=f"genshin_resin_remind_{uid}_{user_id}",
args=[user_id, uid], args=[user_id, uid],
) )
logger.info(
f"genshin_resin_remind add_job:USER:{user_id} UID:{uid} "
f"{next_time} 原神树脂提醒"
)
+2 -2
View File
@@ -1,6 +1,7 @@
from nonebot import on_command, on_notice from nonebot import on_command, on_notice
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
ActionFailed,
GroupMessageEvent, GroupMessageEvent,
PokeNotifyEvent, PokeNotifyEvent,
Message Message
@@ -24,7 +25,6 @@ from nonebot.rule import to_me
from datetime import datetime, timedelta from datetime import datetime, timedelta
from configs.config import NICKNAME from configs.config import NICKNAME
from apscheduler.jobstores.base import JobLookupError from apscheduler.jobstores.base import JobLookupError
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.params import CommandArg from nonebot.params import CommandArg
import random import random
import time import time
@@ -124,7 +124,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
redbag_data[event.group_id]["amount"] redbag_data[event.group_id]["amount"]
- redbag_data[event.group_id]["open_amount"] - redbag_data[event.group_id]["open_amount"]
) )
await return_gold(event.user_id, event.group_id, amount) await return_gold(redbag_data[event.group_id]["user_id"], event.group_id, amount)
await gold_redbag.send( await gold_redbag.send(
f'{redbag_data[event.group_id]["nickname"]}的红包过时未开完,退还{amount}金币...' f'{redbag_data[event.group_id]["nickname"]}的红包过时未开完,退还{amount}金币...'
) )
+7 -6
View File
@@ -61,22 +61,23 @@ async def generate_open_redbag_pic(user_id: int, send_user_nickname: str, amount
async def _generate_open_redbag_pic(user_id: int, send_user_nickname: str, amount: int, text: str): async def _generate_open_redbag_pic(user_id: int, send_user_nickname: str, amount: int, text: str):
send_user_nickname += '的红包' send_user_nickname += '的红包'
amount = str(amount) amount = str(amount)
head = BuildImage(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_12.png') random_redbag = random.choice(os.listdir(f"{IMAGE_PATH}/prts/redbag_1"))
head = BuildImage(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_1/{random_redbag}')
size = BuildImage(0, 0, font_size=50).getsize(send_user_nickname) size = BuildImage(0, 0, font_size=50).getsize(send_user_nickname)
# QQ头像 # QQ头像
ava_bk = BuildImage(100 + size[0], 66, color='white', font_size=50) ava_bk = BuildImage(100 + size[0], 66, is_alpha=True, font_size=50)
ava = BuildImage(66, 66, background=BytesIO(await get_user_avatar(user_id))) ava = BuildImage(66, 66, is_alpha=True, background=BytesIO(await get_user_avatar(user_id)))
ava_bk.paste(ava) ava_bk.paste(ava)
ava_bk.text((100, 7), send_user_nickname) ava_bk.text((100, 7), send_user_nickname)
# ava_bk.show() # ava_bk.show()
ava_bk_w, ava_bk_h = ava_bk.size ava_bk_w, ava_bk_h = ava_bk.size
head.paste(ava_bk, (int((1000 - ava_bk_w) / 2), 300)) head.paste(ava_bk, (int((1000 - ava_bk_w) / 2), 300), alpha=True)
# 金额 # 金额
size = BuildImage(0, 0, font_size=150).getsize(amount) size = BuildImage(0, 0, font_size=150).getsize(amount)
price = BuildImage(size[0], size[1], font_size=150) price = BuildImage(size[0], size[1], is_alpha=True, font_size=150)
price.text((0, 0), amount, fill=(209, 171, 108)) price.text((0, 0), amount, fill=(209, 171, 108))
# 金币中文 # 金币中文
head.paste(price, (int((1000 - size[0]) / 2) - 50, 460)) head.paste(price, (int((1000 - size[0]) / 2) - 50, 460), alpha=True)
head.text((int((1000 - size[0]) / 2 + size[0]) - 50, 500 + size[1] - 70), '金币', fill=(209, 171, 108)) head.text((int((1000 - size[0]) / 2 + size[0]) - 50, 500 + size[1] - 70), '金币', fill=(209, 171, 108))
# 剩余数量和金额 # 剩余数量和金额
head.text((350, 900), text, (198, 198, 198)) head.text((350, 900), text, (198, 198, 198))
+6 -6
View File
@@ -18,9 +18,9 @@ class RedbagUser(db.Model):
@classmethod @classmethod
async def add_redbag_data(cls, user_qq: int, group_id: int, itype: str, money: int): async def add_redbag_data(cls, user_qq: int, group_id: int, itype: str, money: int):
""" """
说明: 说明:
添加收发红包数据 添加收发红包数据
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
:param itype: 收或发 :param itype: 收或发
@@ -45,9 +45,9 @@ class RedbagUser(db.Model):
@classmethod @classmethod
async def ensure(cls, user_qq: int, group_id: int) -> bool: async def ensure(cls, user_qq: int, group_id: int) -> bool:
""" """
说明: 说明:
获取用户对象 获取用户对象
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
""" """
@@ -61,9 +61,9 @@ class RedbagUser(db.Model):
@classmethod @classmethod
async def get_user_all(cls, group_id: int = None) -> List["RedbagUser"]: async def get_user_all(cls, group_id: int = None) -> List["RedbagUser"]:
""" """
说明: 说明:
获取所有用户对象 获取所有用户对象
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
if not group_id: if not group_id:
@@ -65,8 +65,8 @@ async def arg_handle(
if int(img_id) > max_id or int(img_id) < 0: if int(img_id) > max_id or int(img_id) < 0:
await delete_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True) await delete_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True)
try: try:
if (TEMP_PATH / "delete.jpg").exists(): if (TEMP_PATH / f"{event.user_id}_delete.jpg").exists():
(TEMP_PATH / "delete.jpg").unlink() (TEMP_PATH / f"{event.user_id}_delete.jpg").unlink()
logger.info(f"删除{cn2py(state['path'])}图片 {img_id}.jpg 成功") logger.info(f"删除{cn2py(state['path'])}图片 {img_id}.jpg 成功")
except Exception as e: except Exception as e:
logger.warning(f"删除图片 delete.jpg 失败 e{e}") logger.warning(f"删除图片 delete.jpg 失败 e{e}")
@@ -36,7 +36,7 @@ __plugin_settings__ = {
"limit_superuser": False, "limit_superuser": False,
"cmd": ["发送图片"] + Config.get_config("image_management", "IMAGE_DIR_LIST"), "cmd": ["发送图片"] + Config.get_config("image_management", "IMAGE_DIR_LIST"),
} }
__plugin_resources__ = {"pa": IMAGE_PATH} __plugin_resources__ = {"pa": IMAGE_PATH / "pa"}
Config.add_plugin_config( Config.add_plugin_config(
"_task", "_task",
+27 -26
View File
@@ -1,16 +1,14 @@
from nonebot import on_message, on_command from nonebot import on_message, on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, ActionFailed
from nonebot.adapters.onebot.v11.permission import GROUP from nonebot.adapters.onebot.v11.permission import GROUP
from utils.utils import is_number, get_message_img from utils.utils import is_number, get_message_img, get_message_text
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11.exception import ActionFailed
from configs.path_config import DATA_PATH, TEMP_PATH from configs.path_config import DATA_PATH, TEMP_PATH
from utils.image_utils import get_img_hash from utils.image_utils import get_img_hash
from services.log import logger from services.log import logger
from configs.config import NICKNAME, Config from configs.config import NICKNAME, Config
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from nonebot.params import CommandArg, Command from nonebot.params import CommandArg, Command
from typing import Tuple from typing import Tuple, Dict, Any
import time import time
try: try:
@@ -57,7 +55,7 @@ mute_setting = on_command(
) )
def get_data(): def get_data() -> Dict[Any, Any]:
try: try:
with open(DATA_PATH / "group_mute_data.json", "r", encoding="utf8") as f: with open(DATA_PATH / "group_mute_data.json", "r", encoding="utf8") as f:
data = json.load(f) data = json.load(f)
@@ -72,10 +70,8 @@ def save_data():
json.dump(mute_data, f, indent=4) json.dump(mute_data, f, indent=4)
async def download_img_and_hash(url, group_id): async def download_img_and_hash(url, group_id) -> str:
if await AsyncHttpx.download_file( if await AsyncHttpx.download_file(url, TEMP_PATH / f"mute_{group_id}_img.jpg"):
url, TEMP_PATH / f"mute_{group_id}_img.jpg"
):
return str(get_img_hash(TEMP_PATH / f"mute_{group_id}_img.jpg")) return str(get_img_hash(TEMP_PATH / f"mute_{group_id}_img.jpg"))
return "" return ""
@@ -85,9 +81,9 @@ mute_data = get_data()
@mute.handle() @mute.handle()
async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): async def _(bot: Bot, event: GroupMessageEvent):
group_id = str(event.group_id) group_id = str(event.group_id)
msg = arg.extract_plain_text().strip() msg = get_message_text(event.json())
img_list = get_message_img(event.json()) img_list = get_message_img(event.json())
img_hash = "" img_hash = ""
for img in img_list: for img in img_list:
@@ -102,8 +98,6 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
if not mute_dict.get(event.user_id): if not mute_dict.get(event.user_id):
mute_dict[event.user_id] = {"time": time.time(), "count": 1, "msg": msg} mute_dict[event.user_id] = {"time": time.time(), "count": 1, "msg": msg}
else: else:
if cmd or not msg:
return
if msg and msg.find(mute_dict[event.user_id]["msg"]) != -1: if msg and msg.find(mute_dict[event.user_id]["msg"]) != -1:
mute_dict[event.user_id]["count"] += 1 mute_dict[event.user_id]["count"] += 1
else: else:
@@ -123,7 +117,7 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
await bot.set_group_ban( await bot.set_group_ban(
group_id=event.group_id, group_id=event.group_id,
user_id=event.user_id, user_id=event.user_id,
duration=mute_data[group_id]["duration"], duration=mute_data[group_id]["duration"] * 60,
) )
await mute.send(f"检测到恶意刷屏,{NICKNAME}要把你关进小黑屋!", at_sender=True) await mute.send(f"检测到恶意刷屏,{NICKNAME}要把你关进小黑屋!", at_sender=True)
mute_dict[event.user_id]["count"] = 0 mute_dict[event.user_id]["count"] = 0
@@ -136,31 +130,38 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
@mute_setting.handle() @mute_setting.handle()
async def _(event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): async def _(
event: GroupMessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
):
global mute_data
group_id = str(event.group_id) group_id = str(event.group_id)
if not mute_data.get(group_id): if not mute_data.get(group_id):
mute_data[group_id] = {"count": 10, "time": 7, "duration": 0} mute_data[group_id] = {
"count": Config.get_config("mute", "MUTE_DEFAULT_COUNT"),
"time": Config.get_config("mute", "MUTE_DEFAULT_TIME"),
"duration": Config.get_config("mute", "MUTE_DEFAULT_DURATION"),
}
msg = arg.extract_plain_text().strip() msg = arg.extract_plain_text().strip()
if cmd[0] == "刷屏检测设置": if cmd[0] == "刷屏检测设置":
await mute_setting.finish( await mute_setting.finish(
f'最大次数:{mute_data[group_id]["count"]} 次\n' f'最大次数:{mute_data[group_id]["count"]} 次\n'
f'规定时间:{mute_data[group_id]["time"]} 秒\n' f'规定时间:{mute_data[group_id]["time"]} 秒\n'
f'禁言时长:{mute_data[group_id]["duration"] / 60} 分钟\n' f'禁言时长:{mute_data[group_id]["duration"]:.2f} 分钟\n'
f"【在规定时间内发送相同消息超过最大次数则禁言\n当禁言时长为0时关闭此功能】" f"【在规定时间内发送相同消息超过最大次数则禁言\n当禁言时长为0时关闭此功能】"
) )
if not is_number(msg): if not is_number(msg):
await mute.finish("设置的参数必须是数字啊!", at_sender=True) await mute.finish("设置的参数必须是数字啊!", at_sender=True)
if cmd[0] == "设置检测时间": if cmd[0] == "设置刷屏检测时间":
mute_data[group_id]["time"] = int(msg) mute_data[group_id]["time"] = int(msg)
msg += "秒" msg += "秒"
if cmd[0] == "设置检测次数": if cmd[0] == "设置刷屏检测次数":
mute_data[group_id]["count"] = int(msg) mute_data[group_id]["count"] = int(msg)
msg += " 次" msg += " 次"
if cmd[0] == "设置禁言时长": if cmd[0] == "设置刷屏禁言时长":
mute_data[group_id]["duration"] = int(msg) * 60 mute_data[group_id]["duration"] = int(msg)
msg += " 分钟" msg += " 分钟"
await mute_setting.send(f'刷屏检测:{cmd[0]}为 {msg}') await mute_setting.send(f"刷屏检测:{cmd[0]}为 {msg}")
logger.info( logger.info(f"USER {event.user_id} GROUP {group_id} {cmd[0]}:{msg}")
f'USER {event.user_id} GROUP {group_id} {cmd[0]}:{msg}'
)
save_data() save_data()
+9 -10
View File
@@ -1,4 +1,4 @@
from typing import Type from typing import Type, Tuple, Any
from nonebot import on_command from nonebot import on_command
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from utils.utils import scheduler, is_number from utils.utils import scheduler, is_number
@@ -9,7 +9,7 @@ from nonebot.permission import SUPERUSER
import random import random
from nonebot.plugin import MatcherGroup from nonebot.plugin import MatcherGroup
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from nonebot.params import CommandArg from nonebot.params import CommandArg, RegexGroup
from .open_cases_c import ( from .open_cases_c import (
open_case, open_case,
total_open_statistics, total_open_statistics,
@@ -145,12 +145,12 @@ async def _(event: GroupMessageEvent):
) )
open_shilian: Type[Matcher] = cases_matcher_group.on_regex("(.*)连开箱(.*?)") open_shilian: Type[Matcher] = cases_matcher_group.on_regex("(.*)连开箱(.*)?")
@open_shilian.handle() @open_shilian.handle()
async def _(event: GroupMessageEvent, state: T_State): async def _(event: GroupMessageEvent, state: T_State, reg_group: Tuple[Any, ...] = RegexGroup()):
num = state["_matched_groups"][0].strip() num, case_name = reg_group
if is_number(num) or num_dict.get(num): if is_number(num) or num_dict.get(num):
try: try:
num = num_dict[num] num = num_dict[num]
@@ -162,7 +162,6 @@ async def _(event: GroupMessageEvent, state: T_State):
await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True) await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True)
else: else:
await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True) await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True)
case_name = state["_matched_groups"][1].strip()
case_name = case_name.replace("武器箱", "").strip() case_name = case_name.replace("武器箱", "").strip()
if not case_name: if not case_name:
case_name = random.choice(cases_name) case_name = random.choice(cases_name)
@@ -212,16 +211,16 @@ update_price = on_command("更新开箱价格", priority=1, permission=SUPERUSER
@update_price.handle() @update_price.handle()
async def _( event: MessageEvent): async def _(event: MessageEvent, arg: Message = CommandArg()):
await update_price.send(await util_get_buff_price(str(event.get_message()))) await update_price.send(await util_get_buff_price(arg.extract_plain_text().strip() or "狂牙大行动"))
update_img = on_command("更新开箱图片", priority=1, permission=SUPERUSER, block=True) update_img = on_command("更新开箱图片", priority=1, permission=SUPERUSER, block=True)
@update_img.handle() @update_img.handle()
async def _(event: MessageEvent): async def _(event: MessageEvent, arg: Message = CommandArg()):
await update_img.send(await util_get_buff_img(str(event.get_message()))) await update_img.send(await util_get_buff_img(arg.extract_plain_text().strip() or "狂牙大行动"))
# 重置开箱 # 重置开箱
+1 -1
View File
@@ -31,7 +31,7 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
async with db.transaction(): async with db.transaction():
user = await OpenCasesUser.ensure(user_qq, group, for_update=True) user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
# 一天次数上限 # 一天次数上限
if user.today_open_total == int( if user.today_open_total > int(
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT") Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ int(impression) + int(impression)
/ Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT") / Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
+1 -1
View File
@@ -7,7 +7,7 @@ from .models.open_cases_user import OpenCasesUser
from services.log import logger from services.log import logger
from utils.utils import get_bot, cn2py from utils.utils import get_bot, cn2py
from asyncio.exceptions import TimeoutError from asyncio.exceptions import TimeoutError
from nonebot.adapters.onebot.v11.exception import ActionFailed from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import Config from configs.config import Config
from utils.manager import group_manager from utils.manager import group_manager
from .config import * from .config import *
+16 -24
View File
@@ -1,11 +1,9 @@
from nonebot import on_message from nonebot import on_message
from services.log import logger from services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent, ActionFailed
from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
from nonebot.adapters.onebot.v11.permission import GROUP from nonebot.adapters.onebot.v11.permission import GROUP
from bilibili_api import video
from utils.message_builder import image from utils.message_builder import image
from nonebot.adapters.onebot.v11.exception import ActionFailed
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
from utils.browser import get_browser from utils.browser import get_browser
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
@@ -15,10 +13,8 @@ from utils.user_agent import get_user_agent
import aiohttp import aiohttp
import asyncio import asyncio
import time import time
from bilibili_api import settings
import ujson as json import ujson as json
from bilireq import video
__zx_plugin_name__ = "B站转发解析" __zx_plugin_name__ = "B站转发解析"
__plugin_usage__ = """ __plugin_usage__ = """
usage: usage:
@@ -38,9 +34,6 @@ Config.add_plugin_config(
) )
if get_local_proxy():
settings.proxy = get_local_proxy()
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False) parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
_tmp = {} _tmp = {}
@@ -63,18 +56,11 @@ async def _(event: GroupMessageEvent):
) as session: ) as session:
async with session.get( async with session.get(
data["meta"]["detail_1"]["qqdocurl"], data["meta"]["detail_1"]["qqdocurl"],
proxy=get_local_proxy(),
timeout=7, timeout=7,
) as response: ) as response:
url = str(response.url).split("?")[0] url = str(response.url).split("?")[0]
bvid = url.split("/")[-1] bvid = url.split("/")[-1]
vd_info = await video.Video(bvid=bvid).get_info() vd_info = await video.get_video_base_info(bvid)
# response = await AsyncHttpx.get(
# data["meta"]["detail_1"]["qqdocurl"], timeout=7
# )
# url = str(response.url).split("?")[0]
# bvid = url.split("/")[-1]
# vd_info = await video.Video(bvid=bvid).get_info()
# 转发专栏 # 转发专栏
if ( if (
data.get("meta") data.get("meta")
@@ -121,20 +107,26 @@ async def _(event: GroupMessageEvent):
if len(msg[index + 2 :]) >= 10: if len(msg[index + 2 :]) >= 10:
msg = msg[index : index + 12] msg = msg[index : index + 12]
url = f"https://www.bilibili.com/video/{msg}" url = f"https://www.bilibili.com/video/{msg}"
vd_info = await video.Video(bvid=msg).get_info() vd_info = await video.get_video_base_info(msg)
elif "av" in msg: elif "av" in msg:
index = msg.find("av") index = msg.find("av")
if len(msg[index + 2 :]) >= 9: if len(msg[index + 2 :]) >= 9:
msg = msg[index + 2 : index + 11] msg = msg[index + 2 : index + 11]
if is_number(msg): if is_number(msg):
url = f"https://www.bilibili.com/video/{msg}" url = f"https://www.bilibili.com/video/{msg}"
vd_info = await video.Video(aid=int(msg)).get_info() vd_info = await video.get_video_base_info(msg)
elif "https://b23.tv" in msg: elif "https://b23.tv" in msg:
url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13] url = "https://" + msg[msg.find("b23.tv"): msg.find("b23.tv") + 14]
res = await AsyncHttpx.get(url, timeout=7) async with aiohttp.ClientSession(
url = str(res.url).split("?")[0] headers=get_user_agent()
bvid = url.split("/")[-1] ) as session:
vd_info = await video.Video(bvid=bvid).get_info() async with session.get(
url,
timeout=7,
) as response:
url = str(response.url).split("?")[0]
bvid = url.split("/")[-1]
vd_info = await video.get_video_base_info(bvid)
if vd_info: if vd_info:
if ( if (
url in _tmp.keys() and time.time() - _tmp[url] > 30 url in _tmp.keys() and time.time() - _tmp[url] > 30
+117 -100
View File
@@ -1,100 +1,117 @@
from asyncio.exceptions import TimeoutError from nonebot import on_command
from nonebot import on_command from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent from nonebot.typing import T_State
from nonebot.typing import T_State
from configs.path_config import TEMP_PATH from configs.config import Config
from services.log import logger from utils.utils import is_number, change_pixiv_image_links
from utils.message_builder import image from utils.message_builder import image
from utils.utils import is_number from services.log import logger
from utils.manager import withdraw_message_manager from asyncio.exceptions import TimeoutError
from utils.http_utils import AsyncHttpx from configs.path_config import IMAGE_PATH
from nonebot.params import CommandArg, Arg from utils.manager import withdraw_message_manager
from utils.http_utils import AsyncHttpx
try: from nonebot.params import CommandArg, Arg
import ujson as json
except ModuleNotFoundError:
import json __zx_plugin_name__ = "pid搜索"
__plugin_usage__ = """
usage:
__zx_plugin_name__ = "pid搜索" 通过 pid 搜索图片
__plugin_usage__ = """ 指令:
usage: p搜 [pid]
通过 pid 搜索图片 """.strip()
指令: __plugin_des__ = "通过 pid 搜索图片"
p搜 [pid] __plugin_cmd__ = ["p搜 [pid]"]
""".strip() __plugin_version__ = 0.1
__plugin_des__ = "通过 pid 搜索图片" __plugin_author__ = "HibiKier"
__plugin_cmd__ = ["p搜 [pid]"] __plugin_settings__ = {
__plugin_version__ = 0.1 "level": 5,
__plugin_author__ = "HibiKier" "default_status": True,
__plugin_settings__ = { "limit_superuser": False,
"level": 5, "cmd": ["p搜"],
"default_status": True, }
"limit_superuser": False,
"cmd": ["p搜"], pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block=True)
}
pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block=True) @pid_search.handle()
async def _h(event: MessageEvent, state: T_State, arg: Message = CommandArg()):
url = "https://api.fantasyzone.cc/tu/search.php" pid = arg.extract_plain_text().strip()
if pid:
state["pid"] = pid
@pid_search.handle()
async def _(state: T_State, arg: Message = CommandArg()):
pid = arg.extract_plain_text().strip() headers = {
if pid: "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
state["pid"] = pid " rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Referer": "https://www.pixiv.net",
}
@pid_search.got("pid", prompt="需要查询的图片PID是?")
async def _(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
if pid in ["取消", "算了"]: @pid_search.got("pid", prompt="需要查询的图片PID是?")
await pid_search.finish("已取消操作...") async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
if is_number(pid): url = Config.get_config("hibiapi", "HIBIAPI") + "/api/pixiv/"
await pid_search.reject_arg("pid", "笨蛋,重新输入数!字!") if pid in ["取消", "算了"]:
params = { await pid_search.finish("已取消操作...")
"id": pid, if not is_number(pid):
"p": 1, await pid_search.reject_arg("pid", "笨蛋,重新输入数!字!")
} for _ in range(3):
for _ in range(3): try:
try: data = (
data = (await AsyncHttpx.get(url, params=params, timeout=5)).json() await AsyncHttpx.get(
except TimeoutError: url,
pass params={"id": pid},
except Exception as e: timeout=5,
await pid_search.finish(f"发生了一些错误..{type(e)}:{e}") )
else: ).json()
if not data["width"] and not data["height"]: except TimeoutError:
await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True) pass
pid = data["id"] except Exception as e:
title = data["title"] await pid_search.finish(f"发生了一些错误..{type(e)}:{e}")
author = data["userName"] else:
author_id = data["userId"] if data.get("error"):
img_url = data["url"] await pid_search.finish(data["error"]["user_message"], at_sender=True)
if not await AsyncHttpx.download_file( data = data["illust"]
img_url, TEMP_PATH / f"pid_search_{event.user_id}.png" if not data["width"] and not data["height"]:
): await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True)
await pid_search.finish("图片下载失败了....", at_sender=True) pid = data["id"]
tmp = "" title = data["title"]
if isinstance(event, GroupMessageEvent): author = data["user"]["name"]
tmp = "\n【注】将在30后撤回......" author_id = data["user"]["id"]
msg_id = await pid_search.send( image_list = []
Message( try:
f"title:{title}\n" image_list.append(data["meta_single_page"]["original_image_url"])
f"pid:{pid}\n" except KeyError:
f"author:{author}\n" for image_url in data["meta_pages"]:
f"author_id:{author_id}\n" image_list.append(image_url["image_urls"]["original"])
f'{image(TEMP_PATH / f"pid_search_{event.user_id}.png")}' for i, img_url in enumerate(image_list):
f"{tmp}" img_url = change_pixiv_image_links(img_url)
) if not await AsyncHttpx.download_file(
) img_url,
logger.info( IMAGE_PATH / "temp" / f"pid_search_{event.user_id}_{i}.png",
f"(USER {event.user_id}, " headers=headers,
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" ):
f" 查询图片 PID:{pid}" await pid_search.send("图片下载失败了....", at_sender=True)
) tmp = ""
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
withdraw_message_manager.append((msg_id, 30)) tmp = "\n【注】将在30后撤回......"
break msg_id = await pid_search.send(
else: Message(
await pid_search.finish("图片下载失败了....", at_sender=True) f"title:{title}\n"
f"pid:{pid}\n"
f"author:{author}\n"
f"author_id:{author_id}\n"
f'{image(f"pid_search_{event.user_id}_{i}.png", "temp")}'
f"{tmp}"
)
)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询图片 PID:{pid}"
)
if isinstance(event, GroupMessageEvent):
withdraw_message_manager.append((msg_id, 30))
break
else:
await pid_search.finish("图片下载失败了....", at_sender=True)
+5 -4
View File
@@ -4,7 +4,7 @@ from asyncio.locks import Semaphore
from asyncio.exceptions import TimeoutError from asyncio.exceptions import TimeoutError
from ._model.pixiv import Pixiv from ._model.pixiv import Pixiv
from typing import List, Optional from typing import List, Optional
from utils.utils import change_pixiv_image_links from utils.utils import change_pixiv_image_links, change_img_md5
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from services.log import logger from services.log import logger
@@ -20,9 +20,9 @@ try:
except ModuleNotFoundError: except ModuleNotFoundError:
import json import json
if str(platform.system()).lower() == "windows": # if str(platform.system()).lower() == "windows":
policy = asyncio.WindowsSelectorEventLoopPolicy() # policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy) # asyncio.set_event_loop_policy(policy)
headers = { headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;" "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
@@ -238,6 +238,7 @@ async def get_image(img_url: str, user_id: int) -> Optional[str]:
TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg", "wb" TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg", "wb"
) as f: ) as f:
await f.write(response.content) await f.write(response.content)
change_img_md5(TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg")
return TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg" return TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg"
except TimeoutError: except TimeoutError:
logger.warning(f"PIX:{img_url} 图片下载超时...") logger.warning(f"PIX:{img_url} 图片下载超时...")
@@ -38,9 +38,9 @@ class OmegaPixivIllusts(db.Model):
updated_at: datetime, updated_at: datetime,
): ):
""" """
说明: 说明:
添加图片信息 添加图片信息
参数: 参数:
:param pid: pid :param pid: pid
:param title: 标题 :param title: 标题
:param width: 宽度 :param width: 宽度
@@ -78,9 +78,9 @@ class OmegaPixivIllusts(db.Model):
num: int = 100 num: int = 100
) -> List[Optional["OmegaPixivIllusts"]]: ) -> List[Optional["OmegaPixivIllusts"]]:
""" """
说明: 说明:
查找符合条件的图片 查找符合条件的图片
参数: 参数:
:param keywords: 关键词 :param keywords: 关键词
:param uid: 画师uid :param uid: 画师uid
:param pid: 图片pid :param pid: 图片pid
@@ -104,9 +104,9 @@ class OmegaPixivIllusts(db.Model):
@classmethod @classmethod
async def check_exists(cls, pid: int) -> bool: async def check_exists(cls, pid: int) -> bool:
""" """
说明: 说明:
检测pid是否已存在 检测pid是否已存在
参数: 参数:
:param pid: 图片PID :param pid: 图片PID
""" """
query = await cls.query.where(cls.pid == pid).gino.all() query = await cls.query.where(cls.pid == pid).gino.all()
@@ -115,9 +115,9 @@ class OmegaPixivIllusts(db.Model):
@classmethod @classmethod
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int, int": async def get_keyword_num(cls, tags: List[str] = None) -> "int, int, int":
""" """
说明: 说明:
获取相关关键词(keyword, tag)在图库中的数量 获取相关关键词(keyword, tag)在图库中的数量
参数: 参数:
:param tags: 关键词/Tag :param tags: 关键词/Tag
""" """
setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count')) setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count'))
@@ -133,21 +133,20 @@ class OmegaPixivIllusts(db.Model):
@classmethod @classmethod
async def get_all_pid(cls) -> List[int]: async def get_all_pid(cls) -> List[int]:
""" """
说明: 说明:
获取所有图片PID 获取所有图片PID
""" """
data = await cls.select('pid').gino.all() data = await cls.select('pid').gino.all()
return [x[0] for x in data] return [x[0] for x in data]
@classmethod # async def test(cls, nsfw_tag: int = 1):
async def test(cls, nsfw_tag: int = 1): # if nsfw_tag is not None:
if nsfw_tag is not None: # query = cls.query.where(cls.nsfw_tag == nsfw_tag)
query = cls.query.where(cls.nsfw_tag == nsfw_tag) # else:
else: # query = cls.query
query = cls.query # query = query.where((cls.width - cls.height) < 50)
query = query.where((cls.width - cls.height) < 50) # for x in await query.gino.all():
for x in await query.gino.all(): # print(x.pid)
print(x.pid)
+11 -11
View File
@@ -38,9 +38,9 @@ class Pixiv(db.Model):
tags: str, tags: str,
): ):
""" """
说明: 说明:
添加图片信息 添加图片信息
参数: 参数:
:param pid: pid :param pid: pid
:param title: 标题 :param title: 标题
:param width: 宽度 :param width: 宽度
@@ -74,9 +74,9 @@ class Pixiv(db.Model):
@classmethod @classmethod
async def remove_image_data(cls, pid: int, img_p: str) -> bool: async def remove_image_data(cls, pid: int, img_p: str) -> bool:
""" """
说明: 说明:
删除图片数据 删除图片数据
参数: 参数:
:param pid: 图片pid :param pid: 图片pid
:param img_p: 图片pid的张数,如:p0,p1 :param img_p: 图片pid的张数,如:p0,p1
""" """
@@ -94,7 +94,7 @@ class Pixiv(db.Model):
@classmethod @classmethod
async def get_all_pid(cls) -> List[int]: async def get_all_pid(cls) -> List[int]:
""" """
说明: 说明:
获取所有PID 获取所有PID
""" """
query = await cls.query.select("pid").gino.first() query = await cls.query.select("pid").gino.first()
@@ -112,9 +112,9 @@ class Pixiv(db.Model):
num: int = 100 num: int = 100
) -> List[Optional["Pixiv"]]: ) -> List[Optional["Pixiv"]]:
""" """
说明: 说明:
查找符合条件的图片 查找符合条件的图片
参数: 参数:
:param keywords: 关键词 :param keywords: 关键词
:param uid: 画师uid :param uid: 画师uid
:param pid: 图片pid :param pid: 图片pid
@@ -140,9 +140,9 @@ class Pixiv(db.Model):
@classmethod @classmethod
async def check_exists(cls, pid: int, img_p: str) -> bool: async def check_exists(cls, pid: int, img_p: str) -> bool:
""" """
说明: 说明:
检测pid是否已存在 检测pid是否已存在
参数: 参数:
:param pid: 图片PID :param pid: 图片PID
:param img_p: 张数 :param img_p: 张数
""" """
@@ -154,9 +154,9 @@ class Pixiv(db.Model):
@classmethod @classmethod
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int": async def get_keyword_num(cls, tags: List[str] = None) -> "int, int":
""" """
说明: 说明:
获取相关关键词(keyword, tag)在图库中的数量 获取相关关键词(keyword, tag)在图库中的数量
参数: 参数:
:param tags: 关键词/Tag :param tags: 关键词/Tag
""" """
setattr(Pixiv, 'count', db.func.count(cls.pid).label('count')) setattr(Pixiv, 'count', db.func.count(cls.pid).label('count'))
@@ -19,9 +19,9 @@ class PixivKeywordUser(db.Model):
cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str] cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str]
) -> bool: ) -> bool:
""" """
说明: 说明:
添加搜图的关键词 添加搜图的关键词
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
:param keyword: 关键词 :param keyword: 关键词
@@ -38,9 +38,9 @@ class PixivKeywordUser(db.Model):
@classmethod @classmethod
async def delete_keyword(cls, keyword: str) -> bool: async def delete_keyword(cls, keyword: str) -> bool:
""" """
说明: 说明:
删除关键词 删除关键词
参数: 参数:
:param keyword: 关键词 :param keyword: 关键词
""" """
if await cls._check_keyword_exists(keyword): if await cls._check_keyword_exists(keyword):
@@ -53,9 +53,9 @@ class PixivKeywordUser(db.Model):
@classmethod @classmethod
async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int": async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int":
""" """
说明: 说明:
通过或禁用关键词 通过或禁用关键词
参数: 参数:
:param keyword: 关键词 :param keyword: 关键词
:param is_pass: 通过状态 :param is_pass: 通过状态
""" """
@@ -71,7 +71,7 @@ class PixivKeywordUser(db.Model):
@classmethod @classmethod
async def get_all_user_dict(cls) -> dict: async def get_all_user_dict(cls) -> dict:
""" """
说明: 说明:
获取关键词数据库各个用户贡献的关键词字典 获取关键词数据库各个用户贡献的关键词字典
""" """
tmp = {} tmp = {}
@@ -85,7 +85,7 @@ class PixivKeywordUser(db.Model):
@classmethod @classmethod
async def get_current_keyword(cls) -> "List[str], List[str]": async def get_current_keyword(cls) -> "List[str], List[str]":
""" """
说明: 说明:
获取当前通过与未通过的关键词 获取当前通过与未通过的关键词
""" """
pass_keyword = [] pass_keyword = []
@@ -101,7 +101,7 @@ class PixivKeywordUser(db.Model):
@classmethod @classmethod
async def get_black_pid(cls) -> List[str]: async def get_black_pid(cls) -> List[str]:
""" """
说明: 说明:
获取黑名单PID 获取黑名单PID
""" """
black_pid = [] black_pid = []
@@ -113,9 +113,9 @@ class PixivKeywordUser(db.Model):
@classmethod @classmethod
async def _check_keyword_exists(cls, keyword: str) -> bool: async def _check_keyword_exists(cls, keyword: str) -> bool:
""" """
说明: 说明:
检测关键词是否已存在 检测关键词是否已存在
参数: 参数:
:param keyword: 关键词 :param keyword: 关键词
""" """
current_keyword = [] current_keyword = []
+21 -6
View File
@@ -18,7 +18,13 @@ usage:
查看 pix 好康图库 查看 pix 好康图库
指令: 指令:
pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取 pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取
pid [uid]: 通过uid获取图片
pix pid[pid]: 查看图库中指定pid图片 pix pid[pid]: 查看图库中指定pid图片
示例:pix 萝莉 白丝
示例:pix 萝莉 白丝 10 (10为数量)
示例:pix #02 (当tag只有1个tag且为数字时,使用#标记,否则将被判定为数量)
示例:pix 34582394 (查询指定uid图片)
示例:pix pid:12323423 (查询指定pid图片)
""".strip() """.strip()
__plugin_superuser_usage__ = """ __plugin_superuser_usage__ = """
usage: usage:
@@ -49,7 +55,9 @@ __plugin_configs__ = {
"value": None, "value": None,
"help": "单次发送的图片数量达到指定值时转发为合并消息", "help": "单次发送的图片数量达到指定值时转发为合并消息",
"default_value": None, "default_value": None,
} },
"ALLOW_GROUP_SETU": {"value": False, "help": "允许非超级用户使用-s参数", "default_value": False},
"ALLOW_GROUP_R18": {"value": False, "help": "允许非超级用户使用-r参数", "default_value": False},
} }
@@ -80,11 +88,17 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
nsfw_tag = 2 nsfw_tag = 2
else: else:
nsfw_tag = 0 nsfw_tag = 0
if nsfw_tag != 0 and str(event.user_id) not in bot.config.superusers: if str(event.user_id) not in bot.config.superusers:
await pix.finish("你不能看这些噢,这些都是是留给管理员看的...") if (nsfw_tag == 1 and not Config.get_config("pix", "ALLOW_GROUP_SETU")) or (
if n := len(x) == 1 and is_number(x[0]): nsfw_tag == 2 and not Config.get_config("pix", "ALLOW_GROUP_R18")
num = int(x[-1]) ):
keyword = "" await pix.finish("你不能看这些噢,这些都是是留给管理员看的...")
if (n := len(x)) == 1:
if is_number(x[0]) and int(x[0]) < 100:
num = int(x[0])
keyword = ""
elif x[0].startswith("#"):
keyword = x[0][1:]
elif n > 1: elif n > 1:
if is_number(x[-1]): if is_number(x[-1]):
num = int(x[-1]) num = int(x[-1])
@@ -118,6 +132,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
all_image = await OmegaPixivIllusts.query_images( all_image = await OmegaPixivIllusts.query_images(
pid=int(pid), nsfw_tag=nsfw_tag pid=int(pid), nsfw_tag=nsfw_tag
) )
num = len(all_image)
else: else:
tmp = await Pixiv.query_images( tmp = await Pixiv.query_images(
x, r18=1 if nsfw_tag == 2 else 0, num=pix_num x, r18=1 if nsfw_tag == 2 else 0, num=pix_num
+1 -1
View File
@@ -184,7 +184,7 @@ async def _():
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}") logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
omega_pixiv_illusts = None omega_pixiv_illusts = None
for file in os.listdir("."): for file in os.listdir("."):
if "omega_pixiv_illusts" in file and ".sql" in file: if "omega_pixiv_artwork" in file and ".sql" in file:
omega_pixiv_illusts = Path() / file omega_pixiv_illusts = Path() / file
if omega_pixiv_illusts: if omega_pixiv_illusts:
with open(omega_pixiv_illusts, "r", encoding="utf8") as f: with open(omega_pixiv_illusts, "r", encoding="utf8") as f:
+12 -6
View File
@@ -1,11 +1,10 @@
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message, NetworkError
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot import on_command from nonebot import on_command
from utils.utils import is_number from utils.utils import is_number
from .data_source import get_pixiv_urls, download_pixiv_imgs, search_pixiv_urls from .data_source import get_pixiv_urls, download_pixiv_imgs, search_pixiv_urls
from services.log import logger from services.log import logger
from nonebot.adapters.onebot.v11.exception import NetworkError
from asyncio.exceptions import TimeoutError from asyncio.exceptions import TimeoutError
from utils.message_builder import custom_forward_msg from utils.message_builder import custom_forward_msg
from configs.config import Config from configs.config import Config
@@ -18,7 +17,7 @@ __zx_plugin_name__ = "P站排行/搜图"
__plugin_usage__ = """ __plugin_usage__ = """
usage: usage:
P站排行: P站排行:
可选参数: 可选参数:
类型: 类型:
1. 日排行 1. 日排行
2. 周排行 2. 周排行
@@ -44,6 +43,8 @@ usage:
搜图 樱岛麻衣 搜图 樱岛麻衣
搜图 樱岛麻衣 5 搜图 樱岛麻衣 5
搜图 樱岛麻衣 5 r18 搜图 樱岛麻衣 5 r18
搜图 樱岛麻衣#1000users 5
【多个关键词用#分割】
【默认为 热度排序】 【默认为 热度排序】
【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】 【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】
""".strip() """.strip()
@@ -69,6 +70,11 @@ __plugin_configs__ = {
"value": 20, "value": 20,
"help": "作品最大页数限制,超过的作品会被略过", "help": "作品最大页数限制,超过的作品会被略过",
"default_value": 20 "default_value": 20
},
"ALLOW_GROUP_R18": {
"value": False,
"help": "允许群聊中使用 r18 参数",
"default_value": False
} }
} }
Config.add_plugin_config( Config.add_plugin_config(
@@ -152,7 +158,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip() msg = arg.extract_plain_text().strip()
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
if "r18" in msg.lower(): if "r18" in msg.lower() and not Config.get_config("pixiv_rank_search", "ALLOW_GROUP_R18"):
await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True) await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True)
r18 = 0 if "r18" in msg else 1 r18 = 0 if "r18" in msg else 1
msg = msg.replace("r18", "").strip().split() msg = msg.replace("r18", "").strip().split()
@@ -161,8 +167,8 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
info_list = None info_list = None
num = 10 num = 10
page = 1 page = 1
if (n := len(msg)) == 1: if (n := len(msg)) > 0:
keyword = msg[0] keyword = msg[0].replace("#"," ")
if n > 1: if n > 1:
if not is_number(msg[1]): if not is_number(msg[1]):
await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True) await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True)
+6 -4
View File
@@ -1,5 +1,6 @@
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from utils.message_builder import image from utils.message_builder import image
from utils.utils import change_img_md5
from asyncio.exceptions import TimeoutError from asyncio.exceptions import TimeoutError
from configs.config import Config from configs.config import Config
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
@@ -8,10 +9,10 @@ from services.log import logger
from pathlib import Path from pathlib import Path
import platform import platform
if platform.system() == "Windows": # if platform.system() == "Windows":
import asyncio # import asyncio
#
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
headers = { headers = {
@@ -143,6 +144,7 @@ async def download_pixiv_imgs(
file, file,
timeout=Config.get_config("pixiv_rank_search", "TIMEOUT"), timeout=Config.get_config("pixiv_rank_search", "TIMEOUT"),
): ):
change_img_md5(file)
if forward_msg_index is not None: if forward_msg_index is not None:
result += image( result += image(
f"{user_id}_{forward_msg_index}_{index}_pixiv.jpg", f"{user_id}_{forward_msg_index}_{index}_pixiv.jpg",
+4 -4
View File
@@ -62,12 +62,12 @@ async def _poke_event(event: PokeNotifyEvent):
rst = "气死我了!" rst = "气死我了!"
await poke_.finish(rst + random.choice(poke__reply), at_sender=True) await poke_.finish(rst + random.choice(poke__reply), at_sender=True)
rand = random.random() rand = random.random()
if rand <= 0.3: path = random.choice(["luoli", "meitu"])
path = random.choice(["luoli", "meitu"]) if rand <= 0.3 and len(os.listdir(IMAGE_PATH / "image_management" / path)) > 0:
index = random.randint(0, len(os.listdir(IMAGE_PATH / "image_management" / path))) index = random.randint(0, len(os.listdir(IMAGE_PATH / "image_management" / path)) - 1)
result = f"id:{index}" + image(f"{index}.jpg", "image_management/" + path) result = f"id:{index}" + image(f"{index}.jpg", "image_management/" + path)
await poke_.send(result) await poke_.send(result)
logger.info(f"USER {event.user_id} 戳了戳我 回复: {result} \n {result}") logger.info(f"USER {event.user_id} 戳了戳我 回复: {result} {result}")
elif 0.3 < rand < 0.6: elif 0.3 < rand < 0.6:
voice = random.choice(os.listdir(RECORD_PATH / "dinggong")) voice = random.choice(os.listdir(RECORD_PATH / "dinggong"))
result = record(voice, "dinggong") result = record(voice, "dinggong")
+8 -8
View File
@@ -23,9 +23,9 @@ class RussianUser(db.Model):
@classmethod @classmethod
async def ensure(cls, user_qq: int, group_id: int) -> "RussianUser": async def ensure(cls, user_qq: int, group_id: int) -> "RussianUser":
""" """
说明: 说明:
获取用户对象 获取用户对象
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
""" """
@@ -39,9 +39,9 @@ class RussianUser(db.Model):
@classmethod @classmethod
async def add_count(cls, user_qq: int, group_id: int, itype: str) -> bool: async def add_count(cls, user_qq: int, group_id: int, itype: str) -> bool:
""" """
说明: 说明:
添加用户输赢次数 添加用户输赢次数
说明: 说明:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
:param itype: 输或赢 'win' or 'lose' :param itype: 输或赢 'win' or 'lose'
@@ -87,9 +87,9 @@ class RussianUser(db.Model):
@classmethod @classmethod
async def money(cls, user_qq: int, group_id: int, itype: str, count: int) -> bool: async def money(cls, user_qq: int, group_id: int, itype: str, count: int) -> bool:
""" """
说明: 说明:
添加用户输赢金钱 添加用户输赢金钱
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param group_id: 群号 :param group_id: 群号
:param itype: 输或赢 'win' or 'lose' :param itype: 输或赢 'win' or 'lose'
@@ -120,9 +120,9 @@ class RussianUser(db.Model):
@classmethod @classmethod
async def get_all_user(cls, group_id: int) -> List["RussianUser"]: async def get_all_user(cls, group_id: int) -> List["RussianUser"]:
""" """
说明: 说明:
获取该群所有用户对象 获取该群所有用户对象
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
users = await cls.query.where((cls.group_id == group_id)).gino.all() users = await cls.query.where((cls.group_id == group_id)).gino.all()
+2
View File
@@ -49,6 +49,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State, key_word: str = ArgSt
Config.get_config("search_anime", "SEARCH_ANIME_MAX_INFO"), Config.get_config("search_anime", "SEARCH_ANIME_MAX_INFO"),
) )
if anime_report: if anime_report:
if isinstance(anime_report, str):
await search_anime.finish(anime_report)
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
mes_list = custom_forward_msg(anime_report, bot.self_id) mes_list = custom_forward_msg(anime_report, bot.self_id)
await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list) await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
+4 -4
View File
@@ -3,18 +3,18 @@ import feedparser
from urllib import parse from urllib import parse
from services.log import logger from services.log import logger
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from typing import List from typing import List, Union
import time import time
async def from_anime_get_info(key_word: str, max_: int) -> List[str]: async def from_anime_get_info(key_word: str, max_: int) -> Union[str, List[str]]:
s_time = time.time() s_time = time.time()
repass = ""
url = "https://share.dmhy.org/topics/rss/rss.xml?keyword=" + parse.quote(key_word) url = "https://share.dmhy.org/topics/rss/rss.xml?keyword=" + parse.quote(key_word)
try: try:
repass = await get_repass(url, max_) repass = await get_repass(url, max_)
except Exception as e: except Exception as e:
logger.error("Timeout! {}".format(e)) logger.error(f"发生了一些错误 {type(e)}:{e}")
return "发生了一些错误!"
repass.insert(0, f"搜索 {key_word} 结果(耗时 {int(time.time() - s_time)} 秒):\n") repass.insert(0, f"搜索 {key_word} 结果(耗时 {int(time.time() - s_time)} 秒):\n")
return repass return repass
+16 -9
View File
@@ -1,3 +1,4 @@
from services import logger
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from configs.config import Config from configs.config import Config
from configs.path_config import TEMP_PATH from configs.path_config import TEMP_PATH
@@ -25,7 +26,7 @@ async def get_saucenao_image(url: str) -> Union[str, List[str]]:
} }
data = (await AsyncHttpx.post(API_URL_SAUCENAO, params=params)).json() data = (await AsyncHttpx.post(API_URL_SAUCENAO, params=params)).json()
if data["header"]["status"] != 0: if data["header"]["status"] != 0:
return "Saucenao识图失败.." return f"Saucenao识图失败..status:{data['header']['status']}"
data = data["results"] data = data["results"]
data = ( data = (
data data
@@ -39,12 +40,18 @@ async def get_saucenao_image(url: str) -> Union[str, List[str]]:
): ):
msg_list.append(image(TEMP_PATH / f"saucenao_search_{index}.jpg")) msg_list.append(image(TEMP_PATH / f"saucenao_search_{index}.jpg"))
for info in data: for info in data:
similarity = info["header"]["similarity"] try:
tmp = f"相似度:{similarity}%\n" similarity = info["header"]["similarity"]
for x in info["data"].keys(): tmp = f"相似度:{similarity}%\n"
if x != "ext_urls": for x in info["data"].keys():
tmp += f"{x}:{info['data'][x]}\n" if x != "ext_urls":
if "source" not in info["data"].keys(): tmp += f"{x}:{info['data'][x]}\n"
tmp += f'source:{info["data"]["ext_urls"][0]}\n' try:
msg_list.append(tmp[:-1]) if "source" not in info["data"].keys():
tmp += f'source:{info["data"]["ext_urls"][0]}\n'
except KeyError:
tmp += f'source:{info["header"]["thumbnail"]}\n'
msg_list.append(tmp[:-1])
except Exception as e:
logger.warning(f"识图获取图片信息发生错误 {type(e)}:{e}")
return msg_list return msg_list

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