Compare commits

...
181 Commits
Author SHA1 Message Date
HibiKier 6cb4099a2e Update README.md 2022-04-10 22:57:36 +08:00
HibiKier e75a4966b2 Update __init__.py 2022-04-10 22:57:05 +08:00
HibiKier d55cba49bd Update data_source.py 2022-04-10 22:31:07 +08:00
HibiKier 0215abac30 update v0.1.4.7 2022-04-10 22:19:50 +08:00
HibiKier 2dcac5f009 Update README.md 2022-04-09 18:09:22 +08:00
HibiKier 0d8c64f7d1 Merge pull request #144 from AkashiCoin/main
fix: 更新问题,戳一戳图片路径问题
2022-04-09 18:08:49 +08:00
AkashiCoin 55626645fb fix: 更新问题,戳一戳图片路径问题 2022-04-09 14:56:30 +08:00
HibiKier f7925fa259 update genshin.query_role 2022-04-08 01:09:29 +08:00
HibiKier c814ae08b1 Update README.md 2022-04-06 18:52:01 +08:00
HibiKier 24666368f7 Merge pull request #143 from yajiwa/main
update search_type
2022-04-06 18:50:59 +08:00
yajiwa a77e85b62d fix bug 2022-04-06 13:17:08 +08:00
yajiwa 6319c7fce1 fix 2022-04-05 22:38:43 +08:00
yajiwa a45b95d5d4 update search_type 2022-04-05 22:15:47 +08:00
HibiKier 188f6f0f99 Update README.md 2022-04-05 19:42:20 +08:00
HibiKier a72f126d8f fix web_ui api 2022-04-05 13:14:29 +08:00
HibiKier 33eb1b83a8 Update README.md 2022-04-04 23:52:24 +08:00
HibiKier 2d9ebe2e6d Merge pull request #141 from yajiwa/main
Update word_bank plus
2022-04-04 23:50:34 +08:00
yajiwa 262b098dec Merge branch 'HibiKier:main' into main 2022-04-04 22:04:27 +08:00
HibiKier 79d88065aa Update README.md 2022-04-04 20:56:02 +08:00
HibiKier 0f59895c3b update v0.1.4.5 2022-04-04 20:33:37 +08:00
yajiwa 610d588e34 Merge branch 'zhenxun_yajiwa' 2022-04-03 20:17:08 +08:00
yajiwa f99abb2f98 fix config 2022-04-03 20:11:00 +08:00
yajiwa b2b7560d05 Update word_bank_plus 2022-04-03 20:05:18 +08:00
yajiwa 07c16e5238 Merge pull request #1 from yajiwa/zhenxun_yajiwa
Update Modify the entry
2022-04-01 23:56:57 +08:00
yajiwa 1741ea7d26 Update Modify the entry 2022-04-01 23:54:40 +08:00
HibiKier b5ce4fab31 Merge pull request #135 from Sakuracio/main
fix GB18030 to UTF-8.
2022-03-28 00:04:32 +08:00
MangataAkihi 062e4c2062 fix GB18030 to UTF-8. 2022-03-26 23:43:21 +08:00
MangataAkihi 0adb66a8bf fix GB18030 to UTF-8. 2022-03-26 23:43:06 +08:00
HibiKier 2aad517112 fix statistics_handle 2022-03-21 18:43:06 +08:00
HibiKier 14d1512b1e update v0.1.4.4 2022-03-18 20:55:05 +08:00
HibiKier 3f533516af Update README.md 2022-03-07 20:46:48 +08:00
HibiKier f1354308fd Update set_admin_permissions.py 2022-03-07 20:46:13 +08:00
HibiKier c06248e46b Update README.md 2022-03-06 18:00:58 +08:00
HibiKier 9c8eaed938 Update pid_search.py 2022-03-06 18:00:35 +08:00
HibiKier 2081302e32 Update README.md 2022-03-06 17:04:34 +08:00
HibiKier 678fc19f2d Update __init__.py 2022-03-06 17:02:59 +08:00
HibiKier adc2757e8e Merge pull request #128 from Sakuracio/main
去除背景图上的(白点?
2022-03-03 21:18:43 +08:00
Sakuracio 82a1261371 去除背景图上的(白点? 2022-03-03 00:38:54 +08:00
HibiKier 067da9dc57 update 0.1.4.3 2022-03-03 00:18:59 +08:00
HibiKier 0eb9f9fc6f Update README.md 2022-03-01 21:02:36 +08:00
HibiKier aee1340714 Update README.md 2022-03-01 21:02:18 +08:00
HibiKier a72a9bd8cb Update __version__ 2022-03-01 21:01:52 +08:00
HibiKier 7250410653 Update __version__ 2022-03-01 20:59:52 +08:00
HibiKier 12f55800b0 x 2022-03-01 20:26:11 +08:00
HibiKier 53b375b4b2 Add files via upload 2022-02-27 18:26:39 +08:00
HibiKier fba27abe29 Update pyproject.toml 2022-02-27 17:56:56 +08:00
HibiKier 4caa3dec04 Update poetry.lock 2022-02-27 17:56:26 +08:00
HibiKier 516b0f5ccb Add files via upload 2022-02-27 17:34:19 +08:00
HibiKier b5098be08e Update __version__ 2022-02-27 17:32:40 +08:00
HibiKier 5b08a4650c Update README.md 2022-02-27 17:31:51 +08:00
HibiKier eb02157b94 Add files via upload 2022-02-27 17:30:26 +08:00
HibiKier 222e1719a4 Delete plugins/draw_card directory 2022-02-27 17:29:57 +08:00
HibiKier 3c8983e753 Update task_hook.py 2022-02-26 00:11:26 +08:00
HibiKier 1fe41dd823 Update __version__ 2022-02-25 23:21:03 +08:00
HibiKier e8df59203c Update README.md 2022-02-25 23:17:42 +08:00
HibiKier 0f6690606b Update README.md 2022-02-25 22:50:24 +08:00
HibiKier a0115309dd Merge pull request #124 from Nova-Noir/main
Fixed error in custom_welcome_msg and message_builder
2022-02-24 16:12:39 +08:00
HibiKier ca18d45786 Update message_builder.py 2022-02-24 16:12:25 +08:00
NovaNo1r 76df21036a Fixed error in custom_welcome_msg and message_builder 2022-02-23 21:45:53 -08:00
HibiKier c674d581b7 Update README.md 2022-02-23 13:52:10 +08:00
HibiKier fc53c3c487 Update _data_source.py 2022-02-23 13:51:19 +08:00
HibiKier 7a4e31df80 Update __init__.py 2022-02-23 13:49:57 +08:00
HibiKier f1d308d559 Update __init__.py 2022-02-23 13:49:21 +08:00
HibiKier b7914bac05 Update README.md 2022-02-21 19:05:42 +08:00
HibiKier 8c40d88cc4 Update .gitignore 2022-02-21 18:20:43 +08:00
HibiKier b4ed6dcb5d Delete server_ip.py 2022-02-21 18:18:30 +08:00
HibiKier 0d3bd8a89c fix bug 2022-02-21 15:59:17 +08:00
HibiKier 87f0189abd Update README.md 2022-02-20 11:39:00 +08:00
HibiKier 1c17ac1f9d Update __init__.py 2022-02-20 11:06:32 +08:00
HibiKier f038763041 fix bug 2022-02-20 11:06:04 +08:00
HibiKier eaf6d54757 Update README.md 2022-02-19 23:24:21 +08:00
HibiKier d7368c83bc Update query_resource.py 2022-02-19 20:12:51 +08:00
HibiKier 4011620da1 Update README.md 2022-02-19 20:06:53 +08:00
HibiKier 6e0b91531e Update __version__ 2022-02-19 20:05:36 +08:00
HibiKier b8ca1d68aa Update update_info.json 2022-02-19 20:04:19 +08:00
HibiKier 2b9cda40a0 Update query_resource.py 2022-02-19 20:03:40 +08:00
HibiKier d8983bdcbf Update README.md 2022-02-19 18:32:09 +08:00
HibiKier 14bce52f2f Update README.md 2022-02-19 18:31:41 +08:00
HibiKier a7b0f7da68 Update README.md 2022-02-19 18:29:40 +08:00
HibiKier 7dd68cf1ef fit nonebot.beta2 2022-02-19 18:20:19 +08:00
HibiKier ab443a21ec Merge pull request #122 from AkashiCoin/main
fix: 修复远古时期残留的epic推送问题
2022-02-19 15:54:59 +08:00
HibiKier ed7e8a8a4c Merge pull request #109 from SAGIRI-kawaii/main
优化BuildImage.circle()锯齿问题
2022-02-19 15:54:14 +08:00
HibiKier a1435e2fc4 Merge branch 'main' into main 2022-02-19 15:53:47 +08:00
AkashiCoin 44a80f89da fix: 修复远古时期残留的epic推送问题 2022-02-19 14:57:23 +08:00
HibiKier 164f6af30c Merge pull request #119 from evlic/fixEPIC
epic restful 替换
2022-02-18 16:22:16 +08:00
evlic 9093a79101 epic restful 替换 2022-02-16 13:31:24 +08:00
HibiKier 14cce89a18 Update README.md 2022-02-11 13:16:48 +08:00
HibiKier 4bce20a0a9 Update data_source.py 2022-02-11 13:16:10 +08:00
HibiKier f32d8b4eff Update __version__ 2022-02-10 11:58:22 +08:00
HibiKier 685f2b8c53 Update README.md 2022-02-10 11:57:41 +08:00
HibiKier 1e63ca2549 Update buy.py 2022-02-10 11:55:36 +08:00
HibiKier c1bc4eff2b Update README.md 2022-02-09 23:02:14 +08:00
HibiKier bc903d3813 Update __init__.py 2022-02-09 22:28:49 +08:00
HibiKier 80fc17b610 Update __version__ 2022-02-09 21:44:09 +08:00
HibiKier 0efb2bbc60 update v0.1 2022-02-09 20:05:49 +08:00
SAGIRI-kawaii 95ad533b87 优化BuildImage.circle()锯齿问题 2022-01-24 23:52:57 +08:00
HibiKier b6e3240df9 Update README.md 2022-01-16 19:22:03 +08:00
HibiKier 5ae41e1d38 Update __init__.py 2022-01-16 18:37:14 +08:00
HibiKier 8022ae1fb1 Update README.md 2022-01-16 15:20:48 +08:00
HibiKier 0163fc1d88 Update draw_image.py 2022-01-16 15:16:19 +08:00
HibiKier 5d9ab40e35 Update __version__ 2022-01-16 15:00:16 +08:00
HibiKier b1ca7930bb Update README.md 2022-01-16 14:54:31 +08:00
HibiKier 40111261ed Update README.md 2022-01-16 14:54:16 +08:00
HibiKier 4cb91b47e6 update v0.0.9.0 2022-01-16 14:52:50 +08:00
HibiKier 30b56583bd update v0.0.8.0 2022-01-05 22:32:59 +08:00
HibiKier 5e5168f804 fix genshin 2021-12-26 22:14:01 +08:00
HibiKier 4a8122829e Update README.md 2021-12-24 10:23:35 +08:00
HibiKier 52ba2cf89a Merge pull request #99 from yzyyz1387/fix_zx
支持国际疫情数据查询
2021-12-24 10:22:45 +08:00
HibiKier 58957cdf44 Update other_than.py 2021-12-24 10:20:57 +08:00
HibiKier 71f860a500 Update other_than.py 2021-12-24 10:10:48 +08:00
HibiKier 9b4cde819e Update __init__.py 2021-12-24 10:09:53 +08:00
yzyyz1387 99637de1de International information inquiry is supported 2021-12-24 04:08:07 +08:00
yzyyz1387 19dbd3f2b0 International information inquiry is supported 2021-12-24 04:06:56 +08:00
yzyyz1387 7567794f74 International information inquiry is supported 2021-12-24 04:05:44 +08:00
yzyyz1387 df0d15c1b3 International information inquiry is supported 2021-12-24 04:03:26 +08:00
HibiKier 9a84c02bb5 Merge pull request #97 from BalconyJH/patch-1
Update __version__
2021-12-22 12:07:53 +08:00
BalconyJH e623c4f30f Update __version__ 2021-12-21 22:52:45 +08:00
HibiKier 3fd7acffb2 Update README.md 2021-12-20 20:41:54 +08:00
HibiKier 71f8c16c26 Merge pull request #96 from noahzark/patch-1
只有当真的发布新动态/视频的时候才获取并推送
2021-12-20 20:40:42 +08:00
Feliciano Long b64699c4ab 只有当真的发布新动态/视频的时候才获取并推送
1. 当up删除动态的时候,老动态会变成新的,此时不应该重复推送老动态
2. 2021-12-20 b站服务器不稳定,动态列表刷新混乱,造成重复推送
2021-12-20 17:48:05 +08:00
HibiKier 786d62bb2f Update README.md 2021-12-16 20:52:55 +08:00
HibiKier ac48d3d542 Update README.md 2021-12-16 19:23:30 +08:00
HibiKier c4d9523ec2 Update set_admin_permissions.py 2021-12-16 19:22:46 +08:00
HibiKier cb6549c297 Update prts_handle.py 2021-12-16 11:31:15 +08:00
HibiKier 29816ada2a Update README.md 2021-12-16 11:29:12 +08:00
HibiKier dd12bdc028 Update README.md 2021-12-16 11:17:27 +08:00
HibiKier 2a52c0711b Update README.md 2021-12-16 11:17:04 +08:00
HibiKier 2653f67193 update 0.0.7.0 2021-12-16 11:16:28 +08:00
HibiKier b892617824 Update group_user_checkin.py 2021-12-07 12:20:14 +08:00
HibiKier a6fb05c91d Update README.md 2021-12-01 16:25:44 +08:00
HibiKier ccfb9403c8 Update update_info.json 2021-12-01 16:21:58 +08:00
HibiKier 66fa194c7f Update data_source.py 2021-12-01 16:21:29 +08:00
HibiKier 65d8fae9ca Update http_utils.py 2021-12-01 15:20:32 +08:00
HibiKier 58acb14859 Update requirements.txt 2021-12-01 14:53:45 +08:00
HibiKier b63c05a509 Update requirements.txt 2021-12-01 14:17:11 +08:00
HibiKi 2a1a2ee8c5 update 0.0.6.5 2021-12-01 14:03:34 +08:00
HibiKier 8c4b515093 Update update_info.json 2021-12-01 10:53:15 +08:00
HibiKier 6d43989a4d Update update_info.json 2021-12-01 10:52:28 +08:00
HibiKier fb1f15bcb4 Update update_game_simple_info.py 2021-11-29 21:30:06 +08:00
HibiKier 81ad585a18 Update update_game_requests_info.py 2021-11-29 21:29:48 +08:00
HibiKier eb3bd2b4a6 Update update_game_info.py 2021-11-29 21:29:29 +08:00
HibiKier e401914790 Update README.md 2021-11-29 13:11:34 +08:00
HibiKier fef5dadaba Update __version__ 2021-11-29 13:10:43 +08:00
HibiKi c1348d08ed update 0.0.6.4 2021-11-29 13:09:47 +08:00
HibiKier fbd7c568d9 Update pix_update.py 2021-11-24 18:26:52 +08:00
HibiKier 2941774913 Update __init__.py 2021-11-24 18:26:38 +08:00
HibiKier b96d910401 Update __version__ 2021-11-24 14:40:53 +08:00
HibiKier 9275d0782b Update README.md 2021-11-24 14:40:39 +08:00
HibiKier 7acc6cf6af Update data_source.py 2021-11-24 14:33:10 +08:00
HibiKier d380a9aacc Update data_source.py 2021-11-24 14:32:46 +08:00
HibiKier 495377da13 Update README.md 2021-11-24 10:25:00 +08:00
HibiKier 218eed4068 Add files via upload 2021-11-24 10:24:40 +08:00
HibiKier 1e9c99dec1 Delete plugins/search_image directory 2021-11-24 10:07:47 +08:00
HibiKier 0326bc2831 Update __init__.py 2021-11-24 09:56:50 +08:00
HibiKier aed770a761 Update README.md 2021-11-23 21:48:11 +08:00
HibiKi 3de487fb24 update 0.0.6.2 2021-11-23 21:44:59 +08:00
HibiKier c802dfda22 Update README.md 2021-11-19 15:47:10 +08:00
HibiKier 3a4378e4c6 Update __init__.py 2021-11-18 14:41:54 +08:00
HibiKier 955a1f8a7f Update __init__.py 2021-11-18 14:41:13 +08:00
HibiKier ab69e5c477 Create README.md 2021-11-17 11:34:40 +08:00
HibiKier 55e42e8334 Update README.md 2021-11-17 11:33:26 +08:00
HibiKier a0f59bc2c2 Update README.md 2021-11-14 17:27:26 +08:00
HibiKier 66dabd0c8a Update plugins_manager.py 2021-11-14 17:25:45 +08:00
HibiKier 915d585e3a Merge pull request #77 from AkashiCoin/main
修复有免费游戏时不能获取免费游戏的问题
2021-11-13 16:12:49 +08:00
HibiKier 979080d281 Merge branch 'main' into main 2021-11-13 16:12:41 +08:00
HibiKier 335f76c532 Update data_source.py 2021-11-12 16:13:16 +08:00
AkashiCoin b50b934a12 Update data_source.py 2021-11-10 22:26:57 +08:00
AkashiCoin 6a1684d277 Update __init__.py 2021-11-10 22:26:29 +08:00
HibiKier 4926e4d69c Update pix_update.py 2021-11-10 21:33:10 +08:00
HibiKier b29a26551a Update README.md 2021-11-10 21:32:54 +08:00
HibiKier d1c1d93ab7 fix 2021-11-10 21:27:49 +08:00
HibiKier 907df4253c Update __version__ 2021-11-10 20:06:44 +08:00
HibiKier 658152fdc9 Update jitang.py 2021-11-10 16:45:19 +08:00
HibiKier 1a68ede632 Update README.md 2021-11-09 18:05:36 +08:00
HibiKier b70851b810 Update __init__.py 2021-11-09 18:04:33 +08:00
HibiKier 17506691a8 Update __init__.py 2021-11-07 20:45:34 +08:00
HibiKier 37a651da4e Update README.md 2021-11-05 16:52:33 +08:00
HibiKier c535a32230 Update update_info.json 2021-11-05 16:51:28 +08:00
HibiKier bb54781209 Add files via upload 2021-11-05 16:50:40 +08:00
HibiKier dcb538a3a9 Update data_source.py 2021-11-05 16:48:28 +08:00
HibiKier 185f7d9c31 Update README.md 2021-11-04 16:52:44 +08:00
844 changed files with 26015 additions and 18798 deletions
+147
View File
@@ -0,0 +1,147 @@
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
test.py
server_ip.py
member_activity_handle.py
Yu-Gi-Oh/
black_word/
csgo/
fantasy_card/
+229 -362
View File
@@ -1,4 +1,4 @@
<div align=center><img width="320" height="320" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/zhenxun.jpg"/></div> <div align=center><img width="320" height="320" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/logo.png"/></div>
![maven](https://img.shields.io/badge/python-3.8%2B-blue) ![maven](https://img.shields.io/badge/python-3.8%2B-blue)
![maven](https://img.shields.io/badge/nonebot-2.0.0-yellow) ![maven](https://img.shields.io/badge/nonebot-2.0.0-yellow)
@@ -18,13 +18,38 @@
## 声明 ## 声明
此项目仅用于学习交流,请勿用于非法用途 此项目仅用于学习交流,请勿用于非法用途
## Gitee
# [Gitee](https://gitee.com/two_Dimension/zhenxun_bot)
## 未完成的文档 ## 未完成的文档
[传送门](https://hibikier.github.io/zhenxun_bot/) # [传送门](https://hibikier.github.io/zhenxun_bot/)
## 真寻的帮助 ## 真寻的帮助
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令' 请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
## 普通帮助图片
![x](https://github.com/HibiKier/zhenxun_bot/blob/0.0.8.2/docs_image/3238573864-836268675-E2FFBB2AC143EAF4DDDF150438508721.png)
## Web UI
[zhenxun_bot_webui](https://github.com/HibiKier/zhenxun_bot_webui)
## 一键安装脚本
[zhenxun_bot-deploy](https://github.com/AkashiCoin/zhenxun_bot-deploy)
## 提供符合真寻标准的插件仓库
[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
## 来点优点?
* 实现了许多功能,且提供了大量功能管理命令
* 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改
* 方便增删插件,原生nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
* 提供了cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`__plugin_cd_limit__`
* __..... 更多详细请通过`传送门`查看文档!__
## 功能列表 ## 功能列表
<details> <details>
@@ -47,9 +72,13 @@
- [x] 商店/我的金币/购买道具/使用道具 - [x] 商店/我的金币/购买道具/使用道具
- [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw)) - [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
- [x] 我有一个朋友想问问..(借鉴pcrbot插件) - [x] 我有一个朋友想问问..(借鉴pcrbot插件)
- [x] 原神黄历 (使用[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件) - [x] 原神黄历
- [x] 原神今日素材 - [x] 原神今日素材
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件) - [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 原神便笺查询
- [x] 原神玩家查询
- [x] 原神树脂提醒
- [x] 原神签到/自动签到
- [x] 金币红包 - [x] 金币红包
- [x] 微博热搜 - [x] 微博热搜
- [x] B站主播/UP/番剧订阅 - [x] B站主播/UP/番剧订阅
@@ -85,6 +114,8 @@
- [x] 通过PID获取图片 - [x] 通过PID获取图片
- [x] 功能统计可视化 - [x] 功能统计可视化
- [x] 关于
### 已实现的管理员功能 ### 已实现的管理员功能
- [x] 更新群组成员信息 - [x] 更新群组成员信息
- [x] 95%的群功能开关 - [x] 95%的群功能开关
@@ -96,6 +127,8 @@
- [x] 移动图片 (同上) - [x] 移动图片 (同上)
- [x] 删除图片 (同上) - [x] 删除图片 (同上)
- [x] 群内B站订阅 - [x] 群内B站订阅
- [x] 群词条
- [x] 休息吧/醒来
### 已实现的超级用户功能 ### 已实现的超级用户功能
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员) - [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
@@ -121,6 +154,12 @@
- [x] 功能开关(更多设置) - [x] 功能开关(更多设置)
- [x] 功能状态 - [x] 功能状态
- [x] b了 - [x] b了
- [x] 执行sql
- [x] 重载配置
- [x] 清理临时数据
- [x] 增删群认证
- [x] 同意/拒绝好友/群聊请求
- [x] 配置重载
#### 超级用户的被动技能 #### 超级用户的被动技能
- [x] 邀请入群提醒(别人邀请真寻入群) - [x] 邀请入群提醒(别人邀请真寻入群)
@@ -145,138 +184,20 @@
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限 - [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
- [x] 群权限系统 - [x] 群权限系统
- [x] 定时更新权限 - [x] 定时更新权限
- [x] 自动配置重载
</details> </details>
## 功能具体指令 ## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
<details>
<summary>功能具体指令说明</summary>
### 常用功能
** [*]:表示该参数可有多个 [?]:表示参数可选 **
| 功能 | 指令 | 说明
| ----------------------| :--------------------------------------:| :------------------------:
| 签到 | 签到/我的签到/好感度排行/好感度总榜/好感度总榜\[显示我/屏蔽我] | 普通的签到插件,可以获得好感度和金币<br>好感度影响开箱次数和涩图触发概率,金币用于购买道具,俄罗斯轮盘赌注以及金币红包<br>好感度总榜,显示所有群的群员好感度排行,可通过命令好感度总榜\[显示我/屏蔽我] 来设置是否隐藏
| 发送图片 | 美图/壁纸/萝莉 \[id]?(默认随机)/\[num]张图\[keyword] | 发送指定文件夹下的图片<br>示例:萝莉->发送img文件夹下luoli文件夹下的图片<br>在线搜索一些不色的图,示例:3张图米浴
| 色图 | 色图/色图xx/n张色图/n张xx的色图/查色图(查询本地色图信息)/色图r【n<10】 | 色图r返回10张r18色图(仅私聊),并限制每日次数(默认5次)<br>其他示例:色图 真寻 <br>5张真寻的色图
| 黑白草图 | 黑白草图/黑白图 \[文字] \[图片] | 整活生成器,示例:黑白图 我喜欢真寻 \[图片]
| coser | coser/cos/括丝 | coser图片,说实话挺失望的,太色了
| 骂我 | 骂我 | 就是发送钉宫的语音罢了
| 戳一戳 | 戳一戳 | 随机发送钉宫语音 or 美图 or 萝莉图 or 文本
| 模拟开箱 | 开箱 \[武器箱名称](默认随机)/N连开箱 \[武器箱名称](默认随机)/我的开箱/群开箱统计/我的金色 | 当不指定武器箱时默认随机,此功能需要先在/open_cases/config.py中编写指定武器箱数据,然后提前爬取价格,使用超级用户命令更新cookie后,再使用命令更新xx武器箱【注:未设置爬取频率,可能会被禁用api(请谨慎!!用小号!!)】
| 鲁迅说过 | 鲁迅说过 \[文本] | 示例:鲁迅说过 真寻世界第一可爱
| 假消息 | 假消息 \[网址] \[标题] \[内容]? \[图片]? | 构造虚假的分享消息
| 商店系统 | 商店/我的金币/购买道具 \[名称或序号] \[数量](默认1)/使用道具 \[名称或序号] | 示例:<br>购买道具 1 3<br>购买道具 好感度双倍加持卡Ⅰ 3<br>使用道具 1<br>使用道具 好感度双倍加持卡Ⅰ
| 抽卡系统 | 原神/明日方舟/赛马娘/坎公骑冠剑/碧蓝航线/阴阳师/公主连结(pcr)/FGO N抽/一井 | 详细帮助请查看: [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw) <br>示例:原神90抽
| 我有一个朋友 | 我有一个朋友他说/想问问/\[文本] | 会将文本中的(他,她,它)替换成 '我'<br>示例:我有一个朋友想问问他喜不喜欢真寻
| 昵称系统 | 以后叫我\[昵称]/以后请叫我\[昵称]/我是谁/我叫什么 | 此昵称会替换与真寻聊天中 '你' 的名称(群名片),群与群与私聊的昵称相互独立
| 原神黄历 | 原神黄历 | 查看今日原神黄历,含有每日10:25的定时任务
| 原神材料 | 今日素材 | 发送可莉特调的截图
| 丘丘语翻译 | 丘丘翻译/丘丘一下/丘丘语翻译 | 示例:丘丘一下 mimi
| 原神资源查询 | 原神资源查询 \[资源名称] \[路线]?/\[资源名称]在哪/哪里有\[资源名称]/原神资源列表 | 如果资源名称末尾添加‘路线’的话将生成残缺缺缺版的优先路径<br>示例:嘟嘟莲在哪<br>原神资源查询嘟嘟莲路线
| 俄罗斯轮盘 | 装弹\[子弹数] \[金额](默认200)/开枪/结算/我的战绩/胜场排行/败场排行/欧洲人排行/慈善家排行 | 紧张刺激的群内小游戏,使用每日签到的金币作为赌注,具体玩法请发送 真寻帮助 俄罗斯轮盘
| 红包系统 | 塞红包\[金额] \[数量](默认5)/抢/开/戳一戳/退回 | 仿微信明日方舟红包的样式(pil拼图大师!),每个红包金额随机生成,最多会是红包总金额的1/3,退回用于退回一分钟后还未开完的红包
| 金币排行 | 金币排行 | 字面意思
|网易云热评 | 到点了/12点了/网易云热评/网易云评论 | 防下塔
| 古诗 | 念诗/念首诗/来首诗 | 突然文艺起来了
|微博热搜 | 微博热搜/微博热搜[序号]? | 快捷热搜查询方式
| pil对图片的操作 | 修改尺寸/等比压缩/旋转图片/水平翻转/铅笔滤镜/模糊效果/锐化效果/高斯模糊/边缘检测/底色替换 | 选项较多,请直接发送 真寻图片帮助
| BUFF皮肤底价查询 | 查询皮肤 \[武器名称] \[皮肤名称] | 网络不友好的话会经常超时<br>示例:查询皮肤 沙漠之鹰 印花集
| 天气查询 | \[城市]天气 | 非常常见的插件,第一个入门插件
| 疫情查询 | 疫情/查询疫情 \[城市名或省份名] | 示例:疫情杭州
| bt磁力搜索 | bt \[关键词] \[页数]?(默认第1页) | 该功能仅仅提供给私聊,因为可以搜到一些色色的东西,示例:bt钢铁侠 5
| 上车 | 略 | 直接查看真寻帮助 上车,每日限制次数(默认5)
| 以图识番 | 识番 \[图片] | 以图搜翻,图片越清晰越完整正确率越高
| 以图搜图 | 识图 (asc)? \[图片] | 参数asc更换搜索引擎为ascii2d,默认为saucenao
| 点歌 | 点歌 \[歌名] | 网易云点歌小助手
| 搜番 | 搜番 \[关键字] | 群聊只返回5个结果,私聊返回20个结果
| epic白嫖游戏通知 | epic | 通知你又到了白嫖游戏的时候,可以不玩,不能没有
| P站排行榜 | p站排行 \[排行类型参数]? \[数量]? \[日期]?| 9种不同排行榜,r18类型仅可私聊,通过参数选择,查看真寻帮助p站排行<br>示例:p站排行榜 1 9 2018-4-25
| 搜图 | 搜图 \[关键词] \[数量]? \[排序方式]? \[r18]?| r18仅可私聊,查看真寻帮助搜图
| 通过PID搜索图片 | p搜 [pid] | 在群内使用此功能会在30秒内撤回
| 翻译 | 英翻/日翻/韩翻/翻韩/翻日/翻英 \[文本] | 三种语言互相翻译
| 获取b站视频封面 | b封面 [链接/av/bv/cv/直播id] | 快捷的封面获取方式
| 群欢迎消息 | 群欢迎消息/查看群欢迎消息/查看当前群欢迎消息 | 查看给真寻设置的群欢迎消息
| 自我介绍 | 自我介绍 | 没错,一份正经的真寻自我介绍
| 我的权限 | 我的权限 | 真寻内部定义的一套权限系统
| 我的信息 | 我的信息 | 唯一的作用就是看看什么时候加入群
| 撤回 | 撤回 \[消息位置]?(默认为最新一条消息) | 按顺序撤回发送的消息,示例:撤回 1
| 滴滴滴- | 滴滴滴- \[文本] | 用于用户联系真寻的超级用户
|功能调用统计可视化 | 功能调用统计(自记录以来的功能调用统计)<br>周功能调用统计 [plugin_name]<br>月功能调用统计 [plugin_name]| 当plugin_name为空时为7天或30内的所有功能统计
| pix | pix/PIX [tags/uid/pid:pid] [num] | 无参数时随机查看pix图库的图片(无r18),num数量默认=1,tags:查看相关tags图片,uid:查找相关画师图片,pid:pid:指定查看pid图片<br>示例:pix原神 3<br>pix23493844<br>pixpid:29429933
| 添加pix关键词/uid/pid | 添加pix关键词/uid/pid *[关键词/uid/pid]| 添加关键词或uid或pid用于下次搜索,关键词搜索相关tag,uid会收录作者下收藏符合标准的作品,pid收录单张作品<br>示例:添加pix关键词 原神<br> 添加pixuid 123441<br>添加pixpid 2748937|
| 查看pix图库 | 查看pix图库 [tags] | 查看已收录的tag相关图片数量<br>示例:查看pix图库 原神 莫娜
|显示pix关键词 | 显示pix关键词 | 查看已收录的所有关键词/UID/PID
| b了 | b了 [at] | 使真寻完全忽略一个用户的所有信息
| B站订阅 | 添加订阅 [主播/UP/番剧] [id/链接/番名] / 删除订阅 [id] / 查看订阅 | 可以通过直接间链接或主播间id添加订阅主播开播提醒,动态和投稿,可以通过番名,番剧的id,或者番剧链接添加番剧订阅(是番剧id,md开头,不是集数id,ep开头的)更新, 可以通过UP个人id或UP主页链接订阅UP动态和投稿
### 管理员功能
**群主与群管理员默认5级权限**
| 功能 | 权限等级 | 指令 | 说明
| -------------| --------------| :--------------------------------------:| :------------------------:
| 更新群组成员信息 | 1 | 更新群组成员信息/更新群组成员列表 | 存储群员的基本信息,虽然有自动更新,但备个命令以防万一
| 群功能开关 | 2 | 开启/关闭\[指令名]功能 | 群帮助中左边带有√的功能都可以通过此命令开启或关闭,示例:开启色图
| 查看群被动技能 | 2 | 群通知状态 | 详细请查看被动技能列表
| 被动技能开关 | 2 | 开启/关闭被动技能 | 有时候花里胡哨通知也会很烦人
| 自定义群欢迎消息 | 2 | 自定义群欢迎消息 \[文本] \[图片] | 文本和图片至少需要一个,在文本内添加"\[at]"字符串可以用来设置艾特进群的新群员
| 黑名单 | 5 | .ban/.unban \[at] \[小时]? \[分钟]?| 不提供具体时间的话则ban掉永久,且权限低的用户无法unban高权限用户的ban,同级权限也无法进行ban/unban <br>示例:.ban@笨蛋 1 50
| 刷屏检测相关 | 5 | 刷屏检测设置/设置检测时间 \[文本]/设置检测次数 \[文本]/设置禁言时长 \[分钟]| 非常讨厌刷屏的人,打算给他们一点教训
| 上传图片 | 6 | 上传图片 \[图库] \[图片]... | 上传图片至指定图库,虽然并不打算开放给群员,但还是写了,支持批量图片<br>示例:上传图片 美图 \[图片]..
| 删除图片 | 6 | 删除图片 [图库] \[图片id] | 通过指定本地图片id来删除指定图库的图片<br>示例:删除图片 美图 1
| 移动图片 | 6 | 移动图片 \[移出的图库] \[移入的图库] \[图片id] | 移动指定图库中的图片到指定的新图库中,移入的图片id更改为移入图库的最后一位,移除的图库中原本图片的id又最后一位图片替代<br>示例:移动图片 美图 萝莉 22
|B站订阅 | 5 | 功能同上,就是在群中有权限限制 | 略
### 超级用户功能
| 功能 | 指令 | 说明
| ----------------------| :--------------------------------------:| :------------------------:
| 权限增删 | 添加/删除权限 \[at] \[level]<br>添加/删除权限 [qq] [group] [level] | 用于添加或修改权限等级,且该权限不会被自动更新取消
| 所有群组/好友 | 所有群组/好友 | 查看真寻添加的群组与好友
| 广播 | 广播- [文本] | 广播所有群组
| 更新色图 | 更新色图 | 更新群友搜索色图时保存的url
| 回复 | /t | 命令较多,请查看/t帮助,省略群号则私聊用户(必须要有用户的好友)
| 更新cookie | 更新cookie \[cookie] | 用于更新开箱数据和查询buff皮肤
| 开启广播通知 | 开启/关闭广播通知 \[群号] | 用于开启/关闭是否对某些群进行广播(上边的广播方法)
| 退群 | 退群 \[群号] | 用于退出某一些群
| 检查系统状态 | 自检 | 略
| 更新好友/群组信息| 更新好友/群组信息 | 包含自动更新,被t出群等等有更好的可视信息
| 重载卡池 | 略 | 重载抽卡的游戏卡池,请查看 \[nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw)
| 添加商品 | 添加商品 \[名称]-\[价格]-\[描述]-\[折扣](小数)?-\[限时时间](分钟)? | 为真寻的商店添加一点点道具<br>示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60
| 删除商品 | 删除商品 \[名称或序号] | 在真寻的商店中删除一点东西
| 修改商品 | 修改商品 -name \[名称或序号] -price \[价格] -des \[描述] -discount \[折扣] -time \[限时]| 注意空格,不需要的参数可以不加<br>示例:修改商品 -name 1 -price 900 【修改序号为1的商品的价格为900】
| 节日红包 | 节日红包 \[金额] \[数量] \[祝福语]? \[群号]?... | 群号支持批量,使用空格隔开,不使用群号则对所有群发送节日红包,节日红包有效时间为24小时,祝福语默认为“恭喜发财 大吉大利”<br>示例:节日红包 10000 15 真寻真可爱 123324423 23423423
| 修改群权限 | 修改群权限 \[group] \[level] | 所以说这功能是对内鬼的无奈,默认群权限为5,默认无法使用 色图/coser/p站排行/搜图(这些功能都要9级权限)
|更新原神今日素材| 更新原神今日素材 | 自动更新原神每日素材失败时可以手动触发
|更新原神资源信息| 更新原神资源信息 | 除了每日自动更新的资源外,额外更新大地图
| 清理数据 | 清理数据 | 清理 temp,rar,r18_rar 文件夹的文件数据
|添加pix关键词/uid/pid | 添加pix关键词/uid/pid [keyword/pid:pid/uid:uid] [-f]? | 与普通功能相同,额外可以通过参数 -f 强制通过检测
|删除pix关键词 | 删除pix关键词 *[keyword/uid/pid:pid] | 删除已收录的keyword/uid/pid
|更新pix关键词 | 更新pix关键词 [keyword/pid:pid/uid:uid] [num]?| 更新keyword,uid,pid或指定uid,pid,未指定时,则更新全部,当num未指定时为keyword/uid/pid更新全部<br>示例:更新pix关键词<br>更新pix关键词uid 8<br>更新pix关键词pid:83457477<br>num:倒叙更新数量
|删除pix图片 | 删除pix图片 [*pid] [-b]? | [-b]参数为删除的同时加入黑名单(不再更新),虽然是pid,但是_p也可以<br>示例:删除pix图片3458344 8235234_p1 -b
|显示pix关键词 | 显示pix关键词 | 与普通功能相同,额外显示待收录和黑名单
|pix检测更新 | pix检测更新 [update]? | 检测从未更新过的pid或uid,-update参数将在检测后直接更新未更新过的pid或uid<br>示例:pix检测更新 update
| 检查更新真寻 | 检查更新真寻 | 不再需要麻烦的clone第一步
| 关闭功能 | 关闭[功能] [group/private]/*[群号]? | 关闭色图:维护功能(关闭总开关)<br>关闭色图 g:在群内限制功能<br>关闭色图 p:在私聊限制功能<br>关闭色图 1234678:禁用12345678的色图功能
| 群白名单 | 添加/删除群白名单 *[群号] / 查看群白名单 | 白名单内的群不会受到 维护 限制
| 功能状态 | 功能状态 | 查看功能开关状态
| pix | pix [-s/-r] [keyword] | 可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
| 重载插件配置 |重载插件配置 |用于生效手动修改配文件
|帮助 -super | 帮助[功能] -super | 显示该插件的超级用户帮助
</details>
## 部署 ## 简单部署
``` ```
# 配置gocq # 配置gocq
在 https://github.com/Mrs4s/go-cqhttp 下载Releases最新版本,运行后选择反向代理, 在 https://github.com/Mrs4s/go-cqhttp 下载Releases最新版本,运行后选择反向代理,
后将gocq的配置文件config.yml中的universal改为universal: ws://127.0.0.1:8080/cqhttp/ws 后将gocq的配置文件config.yml中的universal改为universal: ws://127.0.0.1:8080/onebot/v11/ws
# 获取代码 # 获取代码
git clone https://github.com/HibiKier/zhenxun_bot.git git clone https://github.com/HibiKier/zhenxun_bot.git
@@ -285,17 +206,18 @@ git clone https://github.com/HibiKier/zhenxun_bot.git
cd zhenxun_bot cd zhenxun_bot
# 安装依赖 # 安装依赖
pip install -r requirements.txt pip install poetry # 安装 poetry
poetry install # 安装依赖
# 进行基础配置 # 进行基础配置
####请查看 配置 部分#### ####请查看 配置 部分####
# 开始运行 # 开始运行
poetry shell # 进入虚拟环境
python bot.py python bot.py
``` ```
## 配置 ## 简单配置
在 configs/config.py 中的 USE_CONFIG_FILE,默认为False
``` ```
1.在.env.dev文件中 1.在.env.dev文件中
@@ -303,299 +225,244 @@ python bot.py
SUPERUSERS = [""] # 填写你的QQ SUPERUSERS = [""] # 填写你的QQ
2.在configs/config.py文件中 2.在configs/config.py文件中
必填: * 数据库配置
1. API KEY
2.数据库配置
在./configs/config.py中配置基本配置(除API KEY ,数据库和代理外都含有默认值) 3.在configs/config.yaml文件中 # 该文件需要启动一次后生成
在./configs/path_config.py配置路径(含有默认配置) * 修改插件配置项
``` ```
## 使用Docker
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
#### GitHub:[Sakuracio/zxenv](https://github.com/Sakuracio/zxenv)
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
## 更新 ## 更新
### 2021/10/15 ### 2022/4/10 \[v0.1.4.7]
* 适配了原神资源查询米游社地图返回的新格式 * 新增消息记录模块
* 丰富处理请求操作提示
* web ui新增配置项修改
* 修复chat_history阻断消息
### 2021/10/8 ### 2022/4/9
* 修复疫情省份查询失效 * fix: 更新问题,戳一戳图片路径问题 [@pull/144](https://github.com/HibiKier/zhenxun_bot/pull/144)
* 修复功能调用统计全局下统计可能发生错误
### 2021/10/4 ### 2022/4/8
* 修复了功能调用统计失效问题 * 修复原神玩家查询
* 当色图库中没有色图时,会在线搜索色图而不是‘没找到符合条件的色图...’
* 快速更新权限再给超级用户发送错误日志
* 修复疫情未加载省份城市无法正常使用
### 2021/10/3 ### 2022/4/6
* 对插件进行分离 * update search_type [@pull/143](https://github.com/HibiKier/zhenxun_bot/pull/143)
* 重写了插件与限制管理器以及帮助获取
* 修改一些插件目录和数据存储目录
* 插件通用配置与限制数据将以ymal文件存储 \[路径:data/configs]
* 所有商店相关操作调用统计合并为商店(包括之前已经保存的数据,会先进行备份)
* 简化了点歌的代码相关
* 修复了碧蓝航线抽卡新框导致报错无法正常初始化
* 修复了P站排行/搜图在PC端无法正常显示
* 添加了插件对超级用户是否限制的配置 ‘limit_superuser’
* 添加命令 ‘重载插件配置’,用于生效手动修改配文件
* 超级用户帮助可以添加 -super 来显示该插件的超级用户帮助,示例:帮助.ban -super
* 原神黄历改为网页截图
* 修改了鲁迅说逻辑结构
* 修改了统计图表样式,改为自定义CreateMat
* 节日红包不再被24小时限制,群内多个节日红包将会覆盖
* 当群权限为-1时,不会对群发送修改权限通知,并屏蔽此群一切命令(包括提醒)
* 修复了红包数量可以过大或为负数,红包数量大于群员数量时会修改为群员数量
* 修复了负数开箱
* 签到最低好感度设置为0.01 [@pull/53](https://github.com/HibiKier/zhenxun_bot/pull/53)
* pip安装新依赖 ruamel.yaml
* 修复功能 EPIC [@pull/58](https://github.com/HibiKier/zhenxun_bot/pull/58)
### 2021/9/10 ### 2022/4/5 \[v0.1.4.6]
* 修复撤回消息有时无法正确获取消息id * 修复web修改插件后帮助图片生成错误
### 2021/9/9 ### 2022/4/4 \[v0.1.4.5]
* 替换coser API * 替换了bt搜索URL
* 修复签到uid可能不默认为0 * 优化使用playwright的相关代码
* 修复签到可能重复的问题 * 原神玩家查询新增层岩巨渊探索
* 修复无订阅时递归出错 * 修复原神便笺角色头像黑框
* 启用了plugins2info_dict, plugins2cd_dict, plugins2exists_dict配置文件,通过USE_CONFIG_FILE=True开启 * 修复同意群聊请求错误
* 修复涩图local_id会被固定为50 * 提供webui方面的api
* 优化图库数量查询 * 新增web-ui(前端简易管理页面插件)插件
* 修复原神大地图过大无法打开报错
* 修复无法显示正确的涩图上限
### 2021/9/7 ### 2022/3/21
* 修改 update_info.json * 修复statistics_handle.py乱码
* 修改 更新信息 图片大小
* 修复 查看订阅 命令 UP和番剧无法正常显示
* 修复订阅推送无法正确推送
* 修复搜图返回列表为空时无法正确回复 [@pull/40](https://github.com/HibiKier/zhenxun_bot/pull/40)
### 2021/9/5 ### 2022/3/18 \[v0.1.4.4]
* 添加配置PIX_IMAGE_SIZE,调整PIX下载图片大小,当设置的图片404时,改为原图
* 新增配置DEFAULT_GROUP_LEVEL,默认群等级
* 新增超级用户功能 super ban,将屏蔽被ban用户的所有消息,指令:b了
* b站转发解析支持纯BV号解析,且五分钟内不会解析相同url
* 俄罗斯轮盘新增 连胜/最高连胜/连败/最高连败 纪录,新增 最高连胜排行榜/最高连败排行榜
* 增加扩展图库 OmegaPixivIllusts,不想自己找图的人福音([Ailitonia](https://github.com/Ailitonia) 佬的高质量精品手筛图库)([传送门](https://github.com/Ailitonia/omega-miya/blob/master/archive_data/db_pixiv.7z) ),可以手动导入图库,也可以将解压文件放在bot.py同级目录重启bot
* 增加配置PIX_OMEGA_PIXIV_RATIO,PIX功能发送PIX图库和扩展图库OmegaPixivIllusts图片的比例,如果没有使用扩展图库OmegaPixivIllusts,请设置为(10, 0)
* 增加配置WITHDRAW_PIX_TIME,用于配置在开关PIX图片在群私聊的自动撤回
* 上传图库cases, 开箱 也可以连抽(未更新过没有价格)
* 新增命令 查看群白名单
* plugins2info_dict新增键"default_status",设置加入新群时功能的默认开关状态
* 增加配置plugins2exists_dict,可自定义是否阻塞某命令同时触发多次
* 增加配置plugins2cd_dict,可自定义为命令添加cd
* 新增B站订阅(直播/番剧/UP)[测试],提供命令:添加订阅 [主播/UP/番剧] [id/链接/番名],删除订阅 [id],查看订阅
* 优化pix和色图的数据库查询
* 触发已关闭的功能的正则时不再触发ai
* 更换coser API
* PIX搜索pid功能在群聊无法搜索PIX图库的r18和OmegaPixivIllusts的r15以及r18,超级用户除外
* PIX单次搜索的图片张数超级用户限制为至多30张,普通用户10张
* PIX超级用户新增-s,-r,可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
* 优化P站排行和搜图,现在需要艾特,改为使用HIBIAPI,在群内时将使用合并消息(群聊搜图会屏蔽R-18)
* win10下playwright相关功能无法使用,但是不再需要删除文件
* 签到大改,优化签到方式与逻辑,改为图片形式发送,有概率额外获得随机道具(好感度有加成)
* 修改撤回功能,改为回复撤回,回复发送撤回
* 更改logging为loguru
* 删除了 发送图片 中的 [N]张图[keyword] 功能
* 修复私聊 关闭[功能] 默认不为 全部 而要添加参数 ‘a’
* 修复0权限用户可以修改禁言检测相关设置
### 2021/8/17 * 修复戳一戳无法功能关闭与ban禁用
* 新增图片搜索 search_image
* 新增配置CHECK_NOTICE_INFO_CD,修改群权限,个人权限检测各种检测的提示消息cd ### 2022/3/7
* 新增功能‘连续上传图片’功能,直到输入‘stop’停止
* 新增功能维护时白名单以及对应命令(白名单中的群聊不受维护限制)
* 新增ALAPI功能,微博热搜,可以通过序号来查看部分热搜内容
* 新增配置NICKNAME,偶尔也想换换名字的说(自我介绍仅当NICKNAME=真寻时生效)
* 提供 更新信息 命令,可以使群员查看更新内容(可开关,与其他功能无异,但不会被统计,该命令图片由自动更新生成)
* 超级用户可以通过私聊来对指定qq进行ban/unban
* 超级用户帮助改为图片形式
* 公开图库删除‘色图’
* 群权限检测,个人权限检测,功能开关检测合并,权限检测顺序:个人权限 > 群权限 > 插件开关 >超级用户禁用某群插件 > 超级用户限制群里插件 > 插件维护检测
* 重写群功能管理,超级用户可对群/私聊分别禁用,也可禁用指定群指定功能,新增命令‘功能状态’,超级用户关闭功能提供参数(默认ALL):group/g(群聊),private/p(私聊)
* 超级用户不会被任何权限等检测阻挡
* 不会重复复读,复读消息只会发送一次
* b站转发解析支持b23.tv,www.bilibili.com链接,cv专栏(playwright截图,压缩倍率0.5,较慢且文字可能不清晰,后优化)
* 我有一个朋友功能,当艾特一个对象时,‘朋友’改为艾特对象的群名片或昵称
* 修复‘上传/删除/移动图片’目录不正确
* 修复天气功能,当城市名在‘天气’后时报错
* 修复配置INITIAL_SETU_PROBABILITY不生效
### 2021/8/10 * 优化增删权限插件
* 重复的好友请求和邀群提示在5分钟内不会重复提示 ### 2022/3/6
* 疫情会优先检查城市,城市省份市区重名时请添加‘市’
* 添加命令‘原神资源查找’,‘设置cookie’
* 添加配置AUTO_UPDATE_ZHENXUN,是否自动更新真寻,默认True
* 添加配置MAX_RUSSIAN_BET_GOLD,俄罗斯轮盘赌注最大金额,默认1000
* 检查更新真寻定时任务时间改为12 : 00
* 添加功能能不能好好说话(nbnhhsh)
* 添加功能随机roll,无参为数字,有参为随机参数
* 添加linux重启脚本以及重启命令‘重启’(建议首次生成restart.sh先查看命令是否正确)
* 修复管理员功能的权限检测
* 修复丢人爬开关
### 2021/8/6 * 修复树脂提醒无法开启
* 修复p搜图片路径错误
* 天气查询会优先遍历城市 ### 2022/3/3 \[v0.1.4.3]
* 添加自动更新真寻命令
##### 如果你的版本为 2021/8/4,可以直接复制plugins/check_zhenxun_update后,通过指令来更新真寻 * 修复手动同意群聊请求依旧退出
### 2021/8/4 ### 2022/3/1 \[v0.1.4.2]
* 修改天气与疫情城市数据,改为api获取,丰富疫情的回复消息 * 0.1.4内容
* 原神资源查询,大地图将被压缩至9M,且启动时当大地图存在时不再自动更新地图
* 下载数据库内色图时将直接存储至_setu,不再存储至临时文件
* 重复的好友请求或邀请请求在一定时间不会重复发送提醒
* 添加每日自动清理临时图片定时任务
* 修复金币排行显示
* 修复无法正常关闭戳一戳功能
### 2021/7/30 ### 2022/2/27 \[v0.1.4.1]
* 重构代码,进行优化,添加注释,删除冗余代码,降低代码耦合 * 优化抽卡
* 添加功能:PIX(一套快捷的pixiv存图命令,自建图库存储url等信息?意在获取自己或群友xp的图)
* 添加功能:清理临时图片文件(temp/rar/r18_rar文件夹)
* 添加额外定时任务(5分钟检测一次),解决加入新群时无法及时为管理员提供权限
* 添加配置ALAPI_AI_CHECK,开关AI回复文本检测
* 添加配置IMPORT_DEFAULT_SHOP_GOODS,控制是否导入内置的三个商品(好感度加持卡ⅠⅡⅢ)
* 添加配置ONLY_USE_LOCAL_SETU,仅仅使用本地色图(有的话),提升速度,但无法在线搜索色图和保存链接
* 添加配置WITHDRAW_SETU_TIME,是否需要延迟撤回色图,可配置仅群里,私聊或全部
* 好友请求,入群请求,滴滴滴-,/t,被踢出群提醒,的提示消息更加丰富
* 彻底重写原神资源查找,添加规划路线(路线残缺缺缺缺版,有空补)添加命令‘更新原神资源信息’,强制更新地图等资源
* 优化色图和P站排行/搜图检测用户是否正在触发命令代码
* 当群最后发言大于36小时,也会关闭广播通知
* 功能维护时超级用户依然可以调用(苦了谁都不能苦了自己)
* 修复获取赛马娘UP公告
* 重写 色图/更新色图
* 色图数据存储改为数据库,启动时会更新之前的色图数据(有的话),更新完毕后会删除原数据文件,如果需要保留请提前备份,
* lolicon api改为v2
* 取消r18次数限制
* 单次搜索至多保存100条链接
* 添加定时撤回
* 暂时取消上传/删除色图
*
* 更新建议(不要替换你的data和resources文件夹!)
* 删除configs,plugins,services,utils,models文件夹重新clone
* 删除多余文件夹,resources/img/genshin/seek_god_eye
* 清空resources/img/genshin/genshin_icon文件夹,仅保留box.png和box_alpha.png
* 替换bot.py
### 2021/7/27 ### 2022/2/25 \[v0.1.4]
* 原神今日素材改为单张截图+拼图,更新文件utils/img_utils.py及plugins/genshin/material_remind/__init__.py * PIX提供配置MAX_ONCE_NUM2FORWARD:当单次发送图片超过指定张数且在群聊时,将转为合并消息
* 修复点歌无法正确发送
* 修复我有一个朋友有时文本会包含CQ码
* 修复群欢消息被动控制文本未删除 [@pull/124](https://github.com/HibiKier/zhenxun_bot/pull/124)
* message_builder.image不再提供参数:abspath
### 2021/7/26 ### 2022/2/23
* 修复原神今日素材稻妻城开放后截图不完整的问题 * 插件状态将从已加载插件模块中读取
* 修复b站订阅插件订阅失败问题
* 修复重启命令无法使用
### 2021/7/14 ### 2022/2/21 \[v0.1.3.2]
* 原神今日素材自动更新时间由 00:01 -> 04:01 [#issues7](https://github.com/HibiKier/zhenxun_bot/issues/7) * 群权限为-1时,超级用户发送的命令依旧生效
* 小问题的修复和优化 * 当群权限为-1时,被动技能也将不会发送
* 修复功能开关,b站转发解析,复读 ignore无法使用
* 修复色图下载文件名与路径错误
* 修复被动技能提醒有时无法删除控制文本
### 2021/7/12
* 修复开箱功能单抽出金时存储格式错误导致 ‘我的金色’ 无法正常发送图片 ### 2022/2/20 \[v0.1.3.1]
* 小问题的修复和优化
### 2021/7/6 * 修复pix下载临时文件目录错误
* 修复AI,天气,发送图片ignore导致无法使用
* 修复纯文本被动技能提醒有时无法删除控制文本
* 识番功能 trace.moe 替换为新API(旧API已失效) ### 2022/2/19 \[v0.1.3] (nonebot beta2!)
* 小问题的修复和优化
### 2021/6/30 * 由于nonebot升级版本,提供更新建议(__该次升级将会导致nonebot.beta1以下的插件无法使用__
* 保证services,utils,configs,plugins,basic_plugins,文件夹均为最新
* 根目录有pyproject.toml与poetry.lock
* 执行命令:
* pip3 install poetry
* poetry install
* poetry shell
* playwright install chromium
* python3 bot.py
* 将plugin2name和plugin2level合并为plugin2info
* util改为utils(。。!)
* 修复当用户发送速度极快时开箱会突破每日限制
* 新增功能:通过PID获取图片
* 发送图片新增功能:搜索图片
* 功能统计可视化
* 新增命令:好感度总排行
* 原神每日素材改为从"可莉特调"截图,提供命令‘更新原神每日素材’和定时任务
* 修复月功能统计错误的问题
### 2021/6/24 * 适配nonebot.beta2
* 删除图片搜索 nonebot_plugin_picsearcher
* 替换cos api
* 原神签到树脂提醒新增绑定群里,在某群绑定uid就会在某群发送提醒信息(有好友则私聊,需要重新绑定uid
* 修改update_info.json
* 修复原神资源查询下载数据失败时导致报错
* 优化BuildImage.circle()锯齿问题 [@pull/109](https://github.com/HibiKier/zhenxun_bot/pull/109)
* epic restful 替换 [@pull/119](https://github.com/HibiKier/zhenxun_bot/pull/119)
* fix: 修复远古时期残留的epic推送问题 [@pull/122](https://github.com/HibiKier/zhenxun_bot/pull/122)
* 添加了一些ALAPI:网易云热评,获取b站视频封面,古诗(需要填写ALAPI_TOKEN) ### 2022/2/11
* 如果填写了ALAPI_TOKEN,将会检测备用接口回复的文本是否合规
* 优化了色图,当搜索色图下载失败时,会从本地色图库中发送相关tag色图
* 当网易云点歌繁忙时会尝试多次点歌
### 2021/6/23 * 修复pix不使用反代无法下载图片
* 添加功能:群权限(所以说内鬼都快爬,可以在configs/config.py中修改各个功能的权限等级) ### 2022/2/10 \[v0.1.1]
* 优化了数据统计,将以7天,30天为周期,为将来更方便实现数据可视化
* 更新坎公骑冠剑UP卡池
* 修复赛马娘UP卡池
* 修复一些小问题
### 2021/6/18 * 修复购买道具出错
* 修复p站排行,搜图因网络问题爆炸时没有具体回复 ### 2022/2/9 \[v0.1]
* 更换色图显示方式为 id,title,author,pid
* 修复修改商品后商品顺序改变
* 滴滴滴- 和 /t支持图片回复
* 将/t回复更加简单(可以通过序号),且可以直接发送群
* 修复bt功能无法交互
### 2021/6/17 * 新增原神自动签到和手动签到
* 新增原神树脂提醒
* 新增手动重载Config.yaml命令以及重载配置定时任务(极少部分帮助或配置可能需要重启
* 修改了发送本地图库的matcher,改为on_message
* register_use可以通过返回值发送消息
* 修复修改商品时限制时间出错
* 修复超时商品依旧可以被购买
* 修复p站排行,搜图因网络问题爆炸时没有具体回复 ### 2022/1/16 \[v0.0.9.0]
* 更换色图显示方式为 id,title,author,pid
### 2021/6/15 * Ai提供文本敏感词过滤器
* 修改了‘帮助’功能,具体为‘帮助 指令名’,未指定指令名时则为查看全部功能列表 * 疫情插件适配新版腾讯API
* 修改了色图的存储数据格式 * 修复/t回复带空格切分
* 色图功能搜索的色图改为随机从urls中随机抽取 * 修复原神玩家查询缺少渊下宫和稻妻家园以及角色不完全
* 将商品数据存储入数据库,提供 '增加/删除/修改商品' 指令 * 修复方法 text2image 中 padding 和 font 无法对纯文本生效
* 商店列表图片不再使用固定背景图,改为直接拼图 * 修复签到图片中信息并未使用配置文件中的色图概率
* 增加功能:俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行 * 修改原神大地图合成方式,改为先压缩再合成
* 增加功能:金币红包(节日红包与群红包相互独立) * bag_user弃用字段props(该字段会在下次更新删除),使用新字段property
* 金币排行 * 数据库中所有belonging_group统一修改为group_id
* 重写一个朋友插件 * 商店将registered_use和register_goods更名为register_use何register_goods
* 其他微小调整 * 商品注册提供了kwargs参数提供:
* bot
* event
* 特殊字段
* “send_success_msg”(发送成功的交互信息->即:使用道具 {name} {num} 次成功)
* “_max_num_limit”(该道具单次使用的最多个数,默认1)
### 2021/6/4 ### 2022/1/5 \[v0.0.8.2]
* 重写BT功能
* 进行一些BUG修复和微小调整
* 添加撤回功能[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
* 为色图功能添加额外的 上传色图 和 删除色图方法(影响hash)
### 2021/5/26 * 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币
* 将语录源更换为一言api * 商店插件将作为内置插件移动至basic_plugins
* 商店插件通过export提供了方法,不需要修改商店插件代码添加商品数据和生效方法
* 修改了hook插件顺序,主要以auth_hook为主
* 修改商店图片样式
* 取消每次启动更新城市列表(首次除外),采用定时更新,加快bot启动速度
* 取消每次启动时截取今日素材,采用调用时截取保存,加快bot启动速度
* 更新色图时当图片404时会删除并替换
* 疫情消息回复改为图片
* 修复商店折扣和限时时间无法生效
* 修复原神玩家查询尘歌壶缺少图片
### 2021/12/26
* 修复群词条问题 空格 会被录入导致不断回复
* 修复米游社app替换api导致无法正常查询
### 2021/12/24
* 支持国际疫情数据查询 [@pull/99](https://github.com/HibiKier/zhenxun_bot/pull/99)
### 2021/12/20
* 只有发布小于存储时间的新动态/视频的时候才获取并推送 [@pull/96](https://github.com/HibiKier/zhenxun_bot/pull/96)
### 2021/12/16 \[v0.0.7.0]
* 提供了真寻群聊功能总开关和对应默认配置项,命令:休息吧 醒来
* 新增原神玩家查询,原神便笺查询
* 群功能管理提供全部开启/关闭命令:开启/关闭全部功能
* 提供主要数据自动备份,且提供自定义配置项
* 提供命令:关于,用于介绍Bot之类的
* 新增命令exec,用于执行sql语句
* 签到提供参数 "all",用于签到所有群聊
* Ban提醒提供cd
* 本地图库提供配置项SHOW_ID,用于设置发送图片时是否显示id
* 色图和PIX提供配置项SHOW_INFO,用于设置发送图片时是否显示图片信息
* 所有被动技能提供了进群默认状态配置项
* 修复添加权限第二种添加形式无法正确添加正确的权限
* 修复签到获取好感度卡时金币不会增加
* 修复当红包数量不合法时依旧扣除金币
* 修复金币红包再次使用塞红包时无法正确退回上次未开完的金币
* 修复 滴滴滴- 只包含图片时不会发送至管理员
* 修复添加权限等级错误
* 修复群词条以bot名称为开头时无法正确触发
* 修改了权限插件加载顺序防止小概率优先加载权限插件引起报错
* 本地图库新图库会统一建立在resource/img/image_management文件夹下,如果该文件夹内未找到图库,会从上级目录查找(即:resource/img/)
<br>
__..... 更多更新信息请查看文档__
## Todo ## Todo
- [ ] 提供更多对插件的控制 - [ ] web管理
- [ ] 明日方舟卡片式的签到..(大概)
- [ ] 更多的群管理功能
- [ ] 数据清理控制
- [ ] docker容器
## 感谢 ## 感谢
[Onebot](https://github.com/howmanybots/onebot) [botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
[go-cqhttp](https://github.com/Mrs4s/go-cqhttp) [Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台.
[nonebot2](https://github.com/nonebot/nonebot2) [nonebot / nonebot2](https://github.com/nonebot/nonebot2) :跨平台Python异步机器人框架
[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot) [Angel-Hair / XUN_Bot](https://github.com/Angel-Hair/XUN_Bot) :一个基于NoneBot和酷Q的功能性QQ机器人
[cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins#%E7%94%9F%E6%88%90%E5%99%A8%E6%8F%92%E4%BB%B6) [pcrbot / cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins) :hoshino插件合集
[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw) [MeetWq /nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw) :A simple withdraw plugin for Nonebot2
[nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) [maxesisn / nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) :适用于nonebot2的点歌插件
[nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager) [nonepkg / nonebot-plugin-manager](https://github.com/nonepkg/nonebot-plugin-manager) :Nonebot Plugin Manager base on import hook
[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot) [H-K-Y / Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot) :原神bot,这是一个基于nonebot和HoshinoBot的原神娱乐及信息查询插件
[nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) [NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
[AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) [Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
[omega-miya](https://github.com/Ailitonia/omega-miya) [Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
[KimigaiiWuyi / GenshinUID]("https://github.com/KimigaiiWuyi/GenshinUID") :一个基于HoshinoBot/NoneBot2的原神UID查询插件
+1 -1
View File
@@ -1 +1 @@
__version__: v0.0.5.1 __version__: v0.1.4.7
Regular → Executable
View File
+1 -1
View File
@@ -4,7 +4,7 @@ import nonebot
Config.add_plugin_config( Config.add_plugin_config(
"admin_bot_manage:custom_welcome_message", "admin_bot_manage:custom_welcome_message",
"SET_GROUP_WELCOME_MESSAGE_LEVEL", "SET_GROUP_WELCOME_MESSAGE_LEVEL [LEVEL]",
2, 2,
name="群管理员操作", name="群管理员操作",
help_="设置群欢迎消息权限", help_="设置群欢迎消息权限",
@@ -1,9 +1,9 @@
from typing import List from typing import List
from nonebot.adapters.cqhttp.message import MessageSegment from nonebot.adapters.onebot.v11.message import MessageSegment
from services.log import logger from services.log import logger
from configs.path_config import DATA_PATH from configs.path_config import DATA_PATH
from utils.message_builder import image from utils.message_builder import image
from utils.utils import get_local_proxy, get_bot from utils.utils import get_bot, get_matchers
from pathlib import Path from pathlib import Path
from models.group_member_info import GroupInfoUser from models.group_member_info import GroupInfoUser
from datetime import datetime from datetime import datetime
@@ -11,9 +11,8 @@ from services.db_context import db
from models.level_user import LevelUser from models.level_user import LevelUser
from configs.config import Config from configs.config import Config
from utils.manager import group_manager, plugins2settings_manager, plugins_manager from utils.manager import group_manager, plugins2settings_manager, plugins_manager
from utils.image_utils import CreateImg from utils.image_utils import BuildImage
import aiofiles from utils.http_utils import AsyncHttpx
import aiohttp
import asyncio import asyncio
import time import time
import os import os
@@ -54,8 +53,8 @@ async def custom_group_welcome(
img_result = "" img_result = ""
img = imgs[0] if imgs else "" img = imgs[0] if imgs else ""
result = "" result = ""
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"): if (DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").exists():
os.remove(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg") (DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").unlink()
if not custom_welcome_msg_json.exists(): if not custom_welcome_msg_json.exists():
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True) custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
data = {} data = {}
@@ -73,13 +72,10 @@ async def custom_group_welcome(
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}") logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}")
result += msg result += msg
if img: if img:
async with aiohttp.ClientSession() as session: await AsyncHttpx.download_file(
async with session.get(img, proxy=get_local_proxy()) as response: img, DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg"
async with aiofiles.open( )
DATA_PATH + f"custom_welcome_msg/{group_id}.jpg", "wb" img_result = image(DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg")
) as f:
await f.write(await response.read())
img_result = image(abspath=DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片") logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片")
except Exception as e: except Exception as e:
logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}") logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}")
@@ -100,7 +96,7 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
""" """
if not task_data: if not task_data:
task_data = group_manager.get_task_data() task_data = group_manager.get_task_data()
group_help_file = Path(DATA_PATH) / "group_help" / f"{group_id}.png" group_help_file = DATA_PATH / "group_help" / f"{group_id}.png"
status = cmd[:2] status = cmd[:2]
cmd = cmd[2:] cmd = cmd[2:]
type_ = "plugin" type_ = "plugin"
@@ -113,7 +109,16 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
else: else:
if await group_manager.check_group_task_status(group_id, task): if await group_manager.check_group_task_status(group_id, task):
await group_manager.close_group_task(group_id, task) await group_manager.close_group_task(group_id, task)
if group_help_file.exists():
group_help_file.unlink()
return f"已 {status} 全部被动技能!" return f"已 {status} 全部被动技能!"
if cmd == "全部功能":
for f in plugins2settings_manager.get_data():
if status == "开启":
group_manager.unblock_plugin(f, group_id)
else:
group_manager.block_plugin(f, group_id)
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"
modules = [x for x in task_data.keys() if task_data[x] == cmd] modules = [x for x in task_data.keys() if task_data[x] == cmd]
@@ -138,14 +143,14 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
if not group_manager.get_plugin_status(module, group_id): if not group_manager.get_plugin_status(module, group_id):
return f"功能 {cmd} 正处于关闭状态!不要重复关闭." return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
group_manager.block_plugin(module, group_id) group_manager.block_plugin(module, group_id)
if group_help_file.exists(): if group_help_file.exists():
group_help_file.unlink() group_help_file.unlink()
if is_super: if is_super:
for file in os.listdir(Path(DATA_PATH) / 'group_help'): for file in os.listdir(DATA_PATH / "group_help"):
file = Path(DATA_PATH) / 'group_help' / file file = DATA_PATH / "group_help" / file
file.unlink() file.unlink()
else: else:
_help_image = Path(DATA_PATH) / 'group_help' / f"{group_id}.png" _help_image = DATA_PATH / "group_help" / f"{group_id}.png"
if _help_image.exists(): if _help_image.exists():
_help_image.unlink() _help_image.unlink()
return f"{status} {cmd} 功能!" return f"{status} {cmd} 功能!"
@@ -164,8 +169,8 @@ def set_plugin_status(cmd: str, block_type: str = "all"):
plugins_manager.unblock_plugin(module) plugins_manager.unblock_plugin(module)
else: else:
plugins_manager.block_plugin(module, block_type=block_type) plugins_manager.block_plugin(module, block_type=block_type)
for file in os.listdir(Path(DATA_PATH) / 'group_help'): for file in os.listdir(DATA_PATH / "group_help"):
file = Path(DATA_PATH) / 'group_help' / file file = DATA_PATH / "group_help" / file
file.unlink() file.unlink()
@@ -182,30 +187,34 @@ def _get_plugin_status() -> MessageSegment:
""" """
rst = "\t功能\n" rst = "\t功能\n"
flag_str = "状态".rjust(4) + "\n" flag_str = "状态".rjust(4) + "\n"
for module in plugins_manager.get_data(): tmp_name = []
flag = plugins_manager.get_plugin_block_type(module) for matcher in get_matchers():
flag = flag.upper() + " CLOSE" if flag else "OPEN" if matcher.plugin_name not in tmp_name:
try: tmp_name.append(matcher.plugin_name)
plugin_name = plugins_manager.get(module)["plugin_name"] module = matcher.plugin_name
if ( flag = plugins_manager.get_plugin_block_type(module)
"[Hidden]" in plugin_name flag = flag.upper() + " CLOSE" if flag else "OPEN"
or "[Admin]" in plugin_name try:
or "[Superuser]" in plugin_name plugin_name = plugins_manager.get(module)["plugin_name"]
): if (
continue "[Hidden]" in plugin_name
rst += f"{plugin_name}" or "[Admin]" in plugin_name
except KeyError: or "[Superuser]" in plugin_name
rst += f"{module}" ):
if plugins_manager.get(module)["error"]: continue
rst += "[ERROR]" rst += f"{plugin_name}"
rst += "\n" except KeyError:
flag_str += f"{flag}\n" rst += f"{module}"
if plugins_manager.get(module)["error"]:
rst += "[ERROR]"
rst += "\n"
flag_str += f"{flag}\n"
height = len(rst.split("\n")) * 24 height = len(rst.split("\n")) * 24
a = CreateImg(250, height, font_size=20) a = BuildImage(250, height, font_size=20)
a.text((10, 10), rst) a.text((10, 10), rst)
b = CreateImg(200, height, font_size=20) b = BuildImage(200, height, font_size=20)
b.text((10, 10), flag_str) b.text((10, 10), flag_str)
A = CreateImg(500, height) A = BuildImage(500, height)
A.paste(a) A.paste(a)
A.paste(b, (270, 0)) A.paste(b, (270, 0))
return image(b64=A.pic2bs4()) return image(b64=A.pic2bs4())
@@ -294,3 +303,21 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
user_id=int(list(bot.config.superusers)[0]), message=result[:-1] user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
) )
return True return True
def set_group_bot_status(group_id: int, status: bool) -> str:
"""
设置群聊bot开关状态
:param group_id: 群号
:param status: 状态
"""
if status:
if group_manager.check_group_bot_status(group_id):
return "我还醒着呢!"
group_manager.turn_on_group_bot_status(group_id)
return "呜..醒来了..."
else:
group_manager.shutdown_group_bot_status(group_id)
# for x in group_manager.get_task_data():
# group_manager.close_group_task(group_id, x)
return "那我先睡觉了..."
+37 -38
View File
@@ -1,38 +1,37 @@
from nonebot import on_notice from nonebot import on_notice
from services.log import logger from services.log import logger
from nonebot.adapters.cqhttp import Bot, GroupAdminNoticeEvent from nonebot.adapters.onebot.v11 import GroupAdminNoticeEvent
from nonebot.typing import T_State from models.level_user import LevelUser
from models.level_user import LevelUser from models.group_member_info import GroupInfoUser
from models.group_member_info import GroupInfoUser from configs.config import Config
from configs.config import Config
__zx_plugin_name__ = "群管理员变动监测 [Hidden]"
__zx_plugin_name__ = "群管理员变动监测 [Hidden]" __plugin_version__ = 0.1
__plugin_version__ = 0.1 __plugin_author__ = "HibiKier"
__plugin_author__ = "HibiKier"
admin_notice = on_notice(priority=5)
admin_notice = on_notice(priority=5)
@admin_notice.handle()
@admin_notice.handle() async def _(event: GroupAdminNoticeEvent):
async def _(bot: Bot, event: GroupAdminNoticeEvent, state: T_State): try:
try: nickname = (
nickname = ( await GroupInfoUser.get_member_info(event.user_id, event.group_id)
await GroupInfoUser.get_member_info(event.user_id, event.group_id) ).user_name
).user_name except AttributeError:
except AttributeError: nickname = event.user_id
nickname = event.user_id if event.sub_type == "set":
if event.sub_type == "set": await LevelUser.set_level(
await LevelUser.set_level( event.user_id,
event.user_id, event.group_id,
event.group_id, Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"), )
) logger.info(
logger.info( f"为新晋管理员 {nickname}({event.user_id}) "
f"为新晋管理员 {nickname}({event.user_id}) " f"添加权限等级:{Config.get_config('admin_bot_manage', 'ADMIN_DEFAULT_AUTH')}"
f"添加权限等级:{Config.get_config('admin_bot_manage', 'ADMIN_DEFAULT_AUTH')}" )
) elif event.sub_type == "unset":
elif event.sub_type == "unset": await LevelUser.delete_level(event.user_id, event.group_id)
await LevelUser.delete_level(event.user_id, event.group_id) logger.info(f"将非管理员 {nickname}({event.user_id}) 取消权限等级")
logger.info(f"将非管理员 {nickname}({event.user_id}) 取消权限等级")
+51 -51
View File
@@ -1,51 +1,51 @@
from nonebot import on_command from nonebot import on_command
from utils.utils import get_message_text, get_message_imgs from utils.utils import get_message_img
from nonebot.typing import T_State from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent from nonebot.params import CommandArg
from .data_source import custom_group_welcome from ._data_source import custom_group_welcome
from nonebot.adapters.cqhttp.permission import GROUP from nonebot.adapters.onebot.v11.permission import GROUP
from configs.config import Config from configs.config import Config
from services.log import logger from services.log import logger
__zx_plugin_name__ = "自定义进群欢迎消息 [Admin]" __zx_plugin_name__ = "自定义进群欢迎消息 [Admin]"
__plugin_usage__ = """ __plugin_usage__ = """
usage: usage:
指令: 指令:
自定义进群欢迎消息 ?[文本] ?[图片] 自定义进群欢迎消息 ?[文本] ?[图片]
示例:自定义进群欢迎消息 欢迎新人![图片] 示例:自定义进群欢迎消息 欢迎新人![图片]
Note:可以通过[at]来确认是否艾特新成员 Note:可以通过[at]来确认是否艾特新成员
示例:自定义进群欢迎消息 欢迎你[at] 示例:自定义进群欢迎消息 欢迎你[at]
""".strip() """.strip()
__plugin_des__ = '简易的自定义群欢迎消息' __plugin_des__ = '简易的自定义群欢迎消息'
__plugin_cmd__ = ['自定义群欢迎消息 ?[文本] ?[图片]'] __plugin_cmd__ = ['自定义群欢迎消息 ?[文本] ?[图片]']
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = 'HibiKier' __plugin_author__ = 'HibiKier'
__plugin_settings__ = { __plugin_settings__ = {
"admin_level": Config.get_config("admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"), "admin_level": Config.get_config("admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"),
} }
custom_welcome = on_command( custom_welcome = on_command(
"自定义进群欢迎消息", "自定义进群欢迎消息",
aliases={"自定义欢迎消息", "自定义群欢迎消息", "设置群欢迎消息"}, aliases={"自定义欢迎消息", "自定义群欢迎消息", "设置群欢迎消息"},
permission=GROUP, permission=GROUP,
priority=5, priority=5,
block=True, block=True,
) )
@custom_welcome.handle() @custom_welcome.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
try: try:
msg = get_message_text(event.json()) msg = arg.extract_plain_text().strip()
imgs = get_message_imgs(event.json()) img = get_message_img(event.json())
if not msg and not imgs: if not msg and not img:
await custom_welcome.finish(__plugin_usage__) await custom_welcome.finish(__plugin_usage__)
await custom_welcome.send( await custom_welcome.send(
await custom_group_welcome(msg, imgs, event.user_id, event.group_id), await custom_group_welcome(msg, img, event.user_id, event.group_id),
at_sender=True, at_sender=True,
) )
logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}") logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}")
except Exception as e: except Exception as e:
logger.error(f"自定义进群欢迎消息发生错误 {type(e)}:{e}") logger.error(f"自定义进群欢迎消息发生错误 {type(e)}:{e}")
await custom_welcome.send("发生了一些未知错误...") await custom_welcome.send("发生了一些未知错误...")
+15 -12
View File
@@ -1,5 +1,4 @@
from nonebot.adapters.cqhttp import Bot, Event from nonebot.adapters.onebot.v11 import Event
from nonebot.typing import T_State
from utils.manager import group_manager, plugins2settings_manager from utils.manager import group_manager, plugins2settings_manager
from utils.utils import get_message_text from utils.utils import get_message_text
from services.log import logger from services.log import logger
@@ -7,17 +6,15 @@ from services.log import logger
cmd = [] cmd = []
def switch_rule(bot: Bot, event: Event, state: T_State) -> bool: def switch_rule(event: Event) -> bool:
""" """
检测文本是否是关闭功能命令 检测文本是否是关闭功能命令
:param bot: pass
:param event: pass :param event: pass
:param state: pass
""" """
global cmd
try: try:
if not cmd: if not cmd:
cmd.append('关闭全部被动') cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"]
cmd.append('开启全部被动')
_data = group_manager.get_task_data() _data = group_manager.get_task_data()
for key in _data: for key in _data:
cmd.append(f"开启{_data[key]}") cmd.append(f"开启{_data[key]}")
@@ -27,11 +24,17 @@ def switch_rule(bot: Bot, event: Event, state: T_State) -> bool:
_data = plugins2settings_manager.get_data() _data = plugins2settings_manager.get_data()
for key in _data: for key in _data:
try: try:
for x in _data[key]["cmd"]: if isinstance(_data[key]["cmd"], list):
cmd.append(f"开启{x}") for x in _data[key]["cmd"]:
cmd.append(f"关闭{x}") cmd.append(f"开启{x}")
cmd.append(f"开启 {x}") cmd.append(f"关闭{x}")
cmd.append(f"关闭 {x}") cmd.append(f"开启 {x}")
cmd.append(f"关闭 {x}")
else:
cmd.append(f"开启{key}")
cmd.append(f"关闭{key}")
cmd.append(f"开启 {key}")
cmd.append(f"关闭 {key}")
except KeyError: except KeyError:
pass pass
msg = get_message_text(event.json()).split() msg = get_message_text(event.json()).split()
+124 -107
View File
@@ -1,107 +1,124 @@
from nonebot import on_command, on_message from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent, GROUP
from nonebot.typing import T_State from nonebot import on_command, on_message, on_regex
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP from nonebot.params import RegexGroup
from .data_source import ( from ._data_source import (
change_group_switch, change_group_switch,
set_plugin_status, set_plugin_status,
get_plugin_status, get_plugin_status,
group_current_status, group_current_status,
) set_group_bot_status
from services.log import logger )
from configs.config import NICKNAME, Config from services.log import logger
from utils.utils import get_message_text, is_number from configs.config import NICKNAME, Config
from nonebot.permission import SUPERUSER from utils.utils import get_message_text, is_number
from .rule import switch_rule from nonebot.permission import SUPERUSER
from typing import Tuple, Any
from .rule import switch_rule
__zx_plugin_name__ = "群功能开关 [Admin]"
__plugin_usage__ = """ __zx_plugin_name__ = "群功能开关 [Admin]"
usage:
群内功能与被动技能开关 __plugin_usage__ = """
指令: usage:
开启/关闭[功能] 群内功能与被动技能开关
群被动状态 指令:
开启全部被动 开启/关闭[功能]
关闭全部被动 群被动状态
示例:开启/关闭色图 开启全部被动
""".strip() 关闭全部被动
__plugin_superuser_usage__ = """ 醒来/休息吧
usage: 示例:开启/关闭色图
功能总开关与指定群禁用 """.strip()
指令: __plugin_superuser_usage__ = """
功能状态 usage:
开启/关闭[功能] [group] 功能总开关与指定群禁用
开启/关闭[功能] ['private'/'group'] 指令:
""".strip() 功能状态
__plugin_des__ = "群内功能开关" 开启/关闭[功能] [group]
__plugin_cmd__ = [ 开启/关闭[功能] ['private'/'group']
"开启/关闭[功能]", """.strip()
"群被动状态", __plugin_des__ = "群内功能开关"
"开启全部被动", __plugin_cmd__ = [
"关闭全部被动", "开启/关闭[功能]",
"功能状态 [_superuser]", "群被动状态",
"开启/关闭[功能] [group] [_superuser]", "开启全部被动",
"开启/关闭[功能] ['private'/'group'] [_superuser]", "关闭全部被动",
] "醒来/休息吧",
__plugin_version__ = 0.1 "功能状态 [_superuser]",
__plugin_author__ = "HibiKier" "开启/关闭[功能] [group] [_superuser]",
__plugin_settings__ = { "开启/关闭[功能] ['private'/'group'] [_superuser]",
"admin_level": Config.get_config("admin_bot_manage", "CHANGE_GROUP_SWITCH_LEVEL"), ]
"cmd": ["开启功能", "关闭功能", "开关"] __plugin_version__ = 0.1
} __plugin_author__ = "HibiKier"
__plugin_settings__ = {
switch_rule_matcher = on_message(rule=switch_rule, priority=4, block=True) "admin_level": Config.get_config("admin_bot_manage", "CHANGE_GROUP_SWITCH_LEVEL"),
"cmd": ["开启功能", "关闭功能", "开关"]
plugins_status = on_command("功能状态", permission=SUPERUSER, priority=5, block=True) }
group_task_status = on_command("群被动状态", permission=GROUP, priority=5, block=True) switch_rule_matcher = on_message(rule=switch_rule, priority=4, block=True)
plugins_status = on_command("功能状态", permission=SUPERUSER, priority=5, block=True)
@switch_rule_matcher.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): group_task_status = on_command("群被动状态", permission=GROUP, priority=5, block=True)
_cmd = get_message_text(event.json()).split()[0]
if isinstance(event, GroupMessageEvent): group_status = on_regex("^(休息吧|醒来)$", permission=GROUP, priority=5, block=True)
await switch_rule_matcher.send(await change_group_switch(_cmd, event.group_id))
logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {_cmd}")
else: @switch_rule_matcher.handle()
if str(event.user_id) in bot.config.superusers: async def _(bot: Bot, event: MessageEvent):
block_type = " ".join(get_message_text(event.json()).split()[1:]) _cmd = get_message_text(event.json()).split()[0]
block_type = block_type if block_type else "a" if isinstance(event, GroupMessageEvent):
if is_number(block_type): await switch_rule_matcher.send(await change_group_switch(_cmd, event.group_id))
if not int(block_type) in [ logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {_cmd}")
g["group_id"] else:
for g in await bot.get_group_list(self_id=int(bot.self_id)) if str(event.user_id) in bot.config.superusers:
]: block_type = " ".join(get_message_text(event.json()).split()[1:])
await switch_rule_matcher.finish(f"{NICKNAME}未加入群聊:{block_type}") block_type = block_type if block_type else "a"
await change_group_switch(_cmd, int(block_type), True) if is_number(block_type):
group_name = (await bot.get_group_info(group_id=int(block_type)))[ if not int(block_type) in [
"group_name" g["group_id"]
] for g in await bot.get_group_list()
await switch_rule_matcher.send( ]:
f"已禁用群聊 {group_name}({block_type}) 的 {_cmd[2:]} 功能" await switch_rule_matcher.finish(f"{NICKNAME}未加入群聊:{block_type}")
) await change_group_switch(_cmd, int(block_type), True)
elif block_type in ["all", "private", "group", "a", "p", "g"]: group_name = (await bot.get_group_info(group_id=int(block_type)))[
block_type = "all" if block_type == "a" else block_type "group_name"
block_type = "private" if block_type == "p" else block_type ]
block_type = "group" if block_type == "g" else block_type await switch_rule_matcher.send(
set_plugin_status(_cmd, block_type) f"已禁用群聊 {group_name}({block_type}) 的 {_cmd[2:]} 功能"
if block_type == "all": )
await switch_rule_matcher.send(f"已{_cmd[:2]}功能:{_cmd[2:]}") elif block_type in ["all", "private", "group", "a", "p", "g"]:
elif block_type == "private": block_type = "all" if block_type == "a" else block_type
await switch_rule_matcher.send(f"已在私聊中{_cmd[:2]}功能:{_cmd[2:]}") block_type = "private" if block_type == "p" else block_type
else: block_type = "group" if block_type == "g" else block_type
await switch_rule_matcher.send(f"已在群聊中{_cmd[:2]}功能:{_cmd[2:]}") set_plugin_status(_cmd, block_type)
else: if block_type == "all":
await switch_rule_matcher.finish("格式错误:关闭[功能] [group]/[p/g]") await switch_rule_matcher.send(f"已{_cmd[:2]}功能:{_cmd[2:]}")
logger.info(f"USER {event.user_id} 使用功能管理命令 {_cmd} | {block_type}") elif block_type == "private":
await switch_rule_matcher.send(f"已在私聊中{_cmd[:2]}功能:{_cmd[2:]}")
else:
@plugins_status.handle() await switch_rule_matcher.send(f"已在群聊中{_cmd[:2]}功能:{_cmd[2:]}")
async def _(bot: Bot, event: MessageEvent, state: T_State): else:
await plugins_status.send(await get_plugin_status()) await switch_rule_matcher.finish("格式错误:关闭[功能] [group]/[p/g]")
logger.info(f"USER {event.user_id} 使用功能管理命令 {_cmd} | {block_type}")
@group_task_status.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @plugins_status.handle()
await group_task_status.send(await group_current_status(event.group_id)) async def _():
await plugins_status.send(await get_plugin_status())
@group_task_status.handle()
async def _(event: GroupMessageEvent):
await group_task_status.send(await group_current_status(event.group_id))
@group_status.handle()
async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
cmd = reg_group[0]
if cmd == "休息吧":
msg = set_group_bot_status(event.group_id, False)
else:
msg = set_group_bot_status(event.group_id, True)
await group_status.send(msg)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用总开关命令:{cmd}")
+51 -51
View File
@@ -1,51 +1,51 @@
from utils.utils import scheduler, get_bot from utils.utils import scheduler, get_bot
from .data_source import update_member_info from ._data_source import update_member_info
from services.log import logger from services.log import logger
from models.group_info import GroupInfo from models.group_info import GroupInfo
from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError
__zx_plugin_name__ = '管理方面定时任务 [Hidden]' __zx_plugin_name__ = '管理方面定时任务 [Hidden]'
__plugin_usage__ = '无' __plugin_usage__ = '无'
__plugin_des__ = '成员信息和管理权限的定时更新' __plugin_des__ = '成员信息和管理权限的定时更新'
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = 'HibiKier' __plugin_author__ = 'HibiKier'
# 自动更新群员信息 # 自动更新群员信息
@scheduler.scheduled_job( @scheduler.scheduled_job(
"cron", "cron",
hour=2, hour=2,
minute=1, minute=1,
) )
async def _(): async def _():
bot = get_bot() bot = get_bot()
if bot: if bot:
gl = await bot.get_group_list() gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl] gl = [g["group_id"] for g in gl]
for g in gl: for g in gl:
try: try:
await update_member_info(g) await update_member_info(g)
logger.info(f"更新群组 g:{g} 成功") logger.info(f"更新群组 g:{g} 成功")
except Exception as e: except Exception as e:
logger.error(f"更新群组错误 g:{g} e:{e}") logger.error(f"更新群组错误 g:{g} e:{e}")
# 快速更新群员信息以及管理员权限 # 快速更新群员信息以及管理员权限
@scheduler.scheduled_job( @scheduler.scheduled_job(
"interval", "interval",
minutes=5, minutes=5,
) )
async def _(): async def _():
try: try:
bot = get_bot() bot = get_bot()
if bot: if bot:
gl = await bot.get_group_list() gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl] gl = [g["group_id"] for g in gl]
all_group = [x.group_id for x in await GroupInfo.get_all_group()] all_group = [x.group_id for x in await GroupInfo.get_all_group()]
for g in gl: for g in gl:
if g not in all_group: if g not in all_group:
await update_member_info(g, False) await update_member_info(g, False)
logger.info(f"快速更新群信息以及权限:{g}") logger.info(f"快速更新群信息以及权限:{g}")
except (IndexError, ConnectionDoesNotExistError, UndefinedColumnError): except (IndexError, ConnectionDoesNotExistError, UndefinedColumnError):
pass pass
+40 -41
View File
@@ -1,41 +1,40 @@
from nonebot import on_command, on_notice from nonebot import on_command, on_notice
from nonebot.typing import T_State from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
from nonebot.adapters.cqhttp 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: 更新群组成员的基本信息
更新群组成员的基本信息 指令:
指令: 更新群组成员列表/更新群组成员信息
更新群组成员列表/更新群组成员信息 """.strip()
""".strip() __plugin_des__ = '更新群组成员列表'
__plugin_des__ = '更新群组成员列表' __plugin_cmd__ = ['更新群组成员列表']
__plugin_cmd__ = ['更新群组成员列表'] __plugin_version__ = 0.1
__plugin_version__ = 0.1 __plugin_author__ = 'HibiKier'
__plugin_author__ = 'HibiKier' __plugin_settings__ = {
__plugin_settings__ = { "admin_level": 1,
"admin_level": 1, }
}
refresh_member_group = on_command(
refresh_member_group = on_command( "更新群组成员列表", aliases={"更新群组成员信息"}, permission=GROUP, priority=5, block=True
"更新群组成员列表", aliases={"更新群组成员信息"}, permission=GROUP, priority=5, block=True )
)
@refresh_member_group.handle()
@refresh_member_group.handle() async def _(event: GroupMessageEvent):
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if await update_member_info(event.group_id):
if await update_member_info(event.group_id): await refresh_member_group.finish("更新群员信息成功!", at_sender=True)
await refresh_member_group.finish("更新群员信息成功!", at_sender=True) else:
else: await refresh_member_group.finish("更新群员信息失败!", at_sender=True)
await refresh_member_group.finish("更新群员信息失败!", at_sender=True)
group_increase_handle = on_notice(priority=1, block=False)
group_increase_handle = on_notice(priority=1, block=False)
@group_increase_handle.handle()
@group_increase_handle.handle() async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): if event.user_id == int(bot.self_id):
if event.user_id == int(bot.self_id): await update_member_info(event.group_id)
await update_member_info(event.group_id)
+27 -27
View File
@@ -1,27 +1,27 @@
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 import Bot from nonebot.adapters import Bot
from nonebot.adapters.cqhttp import GroupMessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent
from utils.message_builder import image from utils.message_builder import image
from .data_source import create_help_image, admin_help_image from .data_source import create_help_image, admin_help_image
__zx_plugin_name__ = '管理帮助 [Admin]' __zx_plugin_name__ = '管理帮助 [Admin]'
__plugin_usage__ = '管理员帮助,在群内回复“管理员帮助”' __plugin_usage__ = '管理员帮助,在群内回复“管理员帮助”'
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = 'HibiKier' __plugin_author__ = 'HibiKier'
__plugin_settings__ = { __plugin_settings__ = {
"admin_level": 1, "admin_level": 1,
} }
admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True) admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True)
if admin_help_image.exists(): if admin_help_image.exists():
admin_help_image.unlink() admin_help_image.unlink()
@admin_help.handle() @admin_help.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if not admin_help_image.exists(): if not admin_help_image.exists():
await create_help_image() await create_help_image()
await admin_help.send(image('admin_help_img.png')) await admin_help.send(image('admin_help_img.png'))
+93 -94
View File
@@ -1,94 +1,93 @@
from utils.image_utils import CreateImg from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from services.log import logger from services.log import logger
from utils.utils import get_matchers from utils.utils import get_matchers
from utils.manager import group_manager from utils.manager import group_manager
from nonebot.adapters.cqhttp import Bot from nonebot.adapters.onebot.v11 import Bot
from pathlib import Path from nonebot import Driver
from nonebot import Driver import asyncio
import asyncio import nonebot
import nonebot
driver: Driver = nonebot.get_driver()
driver: Driver = nonebot.get_driver()
background = IMAGE_PATH / "background" / "0.png"
background = Path(IMAGE_PATH) / "background" / "0.png"
admin_help_image = IMAGE_PATH / 'admin_help_img.png'
admin_help_image = Path(IMAGE_PATH) / 'admin_help_img.png'
@driver.on_bot_connect
@driver.on_bot_connect async def init_task(bot: Bot = None):
async def init_task(bot: Bot = None): if not group_manager.get_task_data():
if not group_manager.get_task_data(): await group_manager.init_group_task()
await group_manager.init_group_task() logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.')
logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.')
async def create_help_image():
async def create_help_image(): """
""" 创建管理员帮助图片
创建管理员帮助图片 """
""" await asyncio.get_event_loop().run_in_executor(
await asyncio.get_event_loop().run_in_executor( None, _create_help_image
None, _create_help_image )
)
def _create_help_image():
def _create_help_image(): """
""" 创建管理员帮助图片
创建管理员帮助图片 """
""" _matchers = get_matchers()
_matchers = get_matchers() _plugin_name_list = []
_plugin_name_list = [] width = 0
width = 0 _plugin_level = {}
_plugin_level = {} for matcher in _matchers:
for matcher in _matchers: _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
_plugin = nonebot.plugin.get_plugin(matcher.module) _module = _plugin.module
_module = _plugin.module try:
try: plugin_name = _module.__getattribute__("__zx_plugin_name__")
plugin_name = _module.__getattribute__("__zx_plugin_name__") except AttributeError:
except AttributeError: continue
continue try:
try: if (
if ( "[admin]" in plugin_name.lower()
"[admin]" in plugin_name.lower() and plugin_name not in _plugin_name_list
and plugin_name not in _plugin_name_list and plugin_name != "管理帮助 [Admin]"
and plugin_name != "管理帮助 [Admin]" ):
): _plugin_name_list.append(plugin_name)
_plugin_name_list.append(plugin_name) plugin_settings = _module.__getattribute__("__plugin_settings__")
plugin_settings = _module.__getattribute__("__plugin_settings__") plugin_des = _module.__getattribute__("__plugin_des__")
plugin_des = _module.__getattribute__("__plugin_des__") plugin_cmd = _module.__getattribute__("__plugin_cmd__")
plugin_cmd = _module.__getattribute__("__plugin_cmd__") plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x]
plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x] admin_level = int(plugin_settings["admin_level"])
admin_level = int(plugin_settings["admin_level"]) if _plugin_level.get(admin_level):
if _plugin_level.get(admin_level): _plugin_level[admin_level].append(
_plugin_level[admin_level].append( f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)
f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd) )
) else:
else: _plugin_level[admin_level] = [
_plugin_level[admin_level] = [ f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)
f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd) ]
] x = len(f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)) * 23
x = len(f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)) * 23 width = width if width > x else x
width = width if width > x else x except AttributeError:
except AttributeError: logger.warning(f"获取管理插件 {matcher.plugin_name}: {plugin_name} 设置失败...")
logger.warning(f"获取管理插件 {matcher.module}: {plugin_name} 设置失败...") help_str = "* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" \
help_str = "* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" \ "[权限等级] 管理员帮助:\n\n"
"[权限等级] 管理员帮助:\n\n" x = list(_plugin_level.keys())
x = list(_plugin_level.keys()) x.sort()
x.sort() for level in x:
for level in x: for help_ in _plugin_level[level]:
for help_ in _plugin_level[level]: help_str += f"\t{help_}\n\n"
help_str += f"\t{help_}\n\n" help_str += '-----[被动技能开关]-----\n\n'
help_str += '-----[被动技能开关]-----\n\n' task_data = group_manager.get_task_data()
task_data = group_manager.get_task_data() for i, x in enumerate(task_data.keys()):
for i, x in enumerate(task_data.keys()): help_str += f'{i+1}.开启/关闭{task_data[x]}\n\n'
help_str += f'{i+1}.开启/关闭{task_data[x]}\n\n' height = len(help_str.split("\n")) * 33
height = len(help_str.split("\n")) * 33 A = BuildImage(width, height, font_size=24)
A = CreateImg(width, height, font_size=24) _background = BuildImage(width, height, background=background)
_background = CreateImg(width, height, background=background) A.text((150, 110), help_str)
A.text((150, 110), help_str) A.paste(_background, alpha=True)
A.paste(_background, alpha=True) A.save(admin_help_image)
A.save(admin_help_image) logger.info(f'已成功加载 {len(_plugin_name_list)} 条管理员命令')
logger.info(f'已成功加载 {len(_plugin_name_list)} 条管理员命令')
+249 -195
View File
@@ -1,195 +1,249 @@
from utils.message_builder import image from utils.message_builder import image
from utils.utils import scheduler, get_bot from utils.utils import scheduler, get_bot
from nonebot import on_message 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.cqhttp.exception import ActionFailed from nonebot.adapters.onebot.v11.exception import ActionFailed
from configs.config import NICKNAME from configs.config import NICKNAME, Config
from utils.manager import group_manager from utils.manager import group_manager
from pathlib import Path
__zx_plugin_name__ = "定时任务相关 [Hidden]" import shutil
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier" __zx_plugin_name__ = "定时任务相关 [Hidden]"
__plugin_task__ = {'zwa': '早晚安'} __plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {'zwa': '早晚安'}
x = on_message(priority=9, block=False)
Config.add_plugin_config(
# 早上好 "_task",
@scheduler.scheduled_job( "DEFAULT_ZWA",
"cron", True,
hour=6, help_="被动 早晚安 进群默认开关状态",
minute=1, default_value=True,
) )
async def _():
try: Config.add_plugin_config(
bot = get_bot() "_backup",
gl = await bot.get_group_list() "BACKUP_FLAG",
gl = [g["group_id"] for g in gl] True,
for g in gl: help_="是否开启文件备份",
if await group_manager.check_group_task_status(g, 'zwa'): default_value=True
result = image("zao.jpg", "zhenxun") )
try:
await bot.send_group_msg(group_id=g, message="早上好" + result) Config.add_plugin_config(
except ActionFailed: "_backup",
logger.warning(f"{g} 群被禁言中,无法发送早安") "BACKUP_DIR_OR_FILE",
except Exception as e: ['data/black_word', 'data/configs', 'data/statistics', 'data/word_bank', 'data/manager', 'configs'],
logger.error(f"早晚安错误 e:{e}") name="文件备份",
help_="备份的文件夹或文件",
default_value=[]
# 睡觉了 )
@scheduler.scheduled_job(
"cron",
hour=23, cx = on_message(priority=9, block=False)
minute=59,
)
async def _(): # 早上好
try: @scheduler.scheduled_job(
bot = get_bot() "cron",
gl = await bot.get_group_list() hour=6,
gl = [g["group_id"] for g in gl] minute=1,
for g in gl: )
if await group_manager.check_group_task_status(g, 'zwa'): async def _():
result = image("sleep.jpg", "zhenxun") try:
try: bot = get_bot()
await bot.send_group_msg( gl = await bot.get_group_list()
group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result gl = [g["group_id"] for g in gl]
) for g in gl:
except ActionFailed: result = image("zao.jpg", "zhenxun")
logger.warning(f"{g} 群被禁言中,无法发送晚安") try:
except Exception as e: await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + result)
logger.error(f"早晚安错误 e:{e}") except ActionFailed:
logger.warning(f"{g} 群被禁言中,无法发送早安")
except Exception as e:
# 自动更新群组信息 logger.error(f"早晚安错误 e:{e}")
@scheduler.scheduled_job(
"cron",
hour=3, # 睡觉了
minute=1, @scheduler.scheduled_job(
) "cron",
async def _(): hour=23,
try: minute=59,
bot = get_bot() )
gl = await bot.get_group_list() async def _():
gl = [g["group_id"] for g in gl] try:
for g in gl: bot = get_bot()
group_info = await bot.get_group_info(group_id=g) gl = await bot.get_group_list()
await GroupInfo.add_group_info( gl = [g["group_id"] for g in gl]
group_info["group_id"], for g in gl:
group_info["group_name"], result = image("sleep.jpg", "zhenxun")
group_info["max_member_count"], try:
group_info["member_count"], await bot.send_group_msg(
) group_id=g, message=f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + result
logger.info(f"自动更新群组 {g} 信息成功") )
except Exception as e: except ActionFailed:
logger.error(f"自动更新群组信息错误 e:{e}") logger.warning(f"{g} 群被禁言中,无法发送晚安")
except Exception as e:
logger.error(f"早晚安错误 e:{e}")
# 自动更新好友信息
@scheduler.scheduled_job(
"cron", # 自动更新群组信息
hour=3, @scheduler.scheduled_job(
minute=1, "cron",
) hour=3,
async def _(): minute=1,
try: )
bot = get_bot() async def _():
fl = await bot.get_friend_list() try:
for f in fl: bot = get_bot()
if await FriendUser.add_friend_info(f["user_id"], f["nickname"]): gl = await bot.get_group_list()
logger.info(f'自动更新好友 {f["user_id"]} 信息成功') gl = [g["group_id"] for g in gl]
else: for g in gl:
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败') group_info = await bot.get_group_info(group_id=g)
except Exception as e: await GroupInfo.add_group_info(
logger.error(f"自动更新群组信息错误 e:{e}") group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
# 一次性任务 group_info["member_count"],
# 固定时间触发,仅触发一次: )
# logger.info(f"自动更新群组 {g} 信息成功")
# from datetime import datetime except Exception as e:
# logger.error(f"自动更新群组信息错误 e:{e}")
# @nonebot.scheduler.scheduled_job(
# 'date',
# run_date=datetime(2021, 1, 1, 0, 0), # 自动更新好友信息
# # timezone=None, @scheduler.scheduled_job(
# ) "cron",
# async def _(): hour=3,
# await bot.send_group_msg(group_id=123456, minute=1,
# message="2021,新年快乐!") )
async def _():
# 定期任务 try:
# 从 start_date 开始到 end_date 结束,根据类似 Cron bot = get_bot()
# fl = await bot.get_friend_list()
# 的规则触发任务: for f in fl:
# if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
# @nonebot.scheduler.scheduled_job( logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
# 'cron', else:
# # year=None, logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
# # month=None, except Exception as e:
# # day=None, logger.error(f"自动更新群组信息错误 e:{e}")
# # week=None,
# day_of_week="mon,tue,wed,thu,fri",
# hour=7, # 自动备份
# # minute=None, @scheduler.scheduled_job(
# # second=None, "cron",
# # start_date=None, hour=3,
# # end_date=None, minute=25,
# # timezone=None, )
# ) async def _():
# async def _(): if Config.get_config("_backup", "BACKUP_FLAG"):
# await bot.send_group_msg(group_id=123456, _backup_path = Path() / 'backup'
# message="起床啦!") _backup_path.mkdir(exist_ok=True, parents=True)
for x in Config.get_config("_backup", "BACKUP_DIR_OR_FILE"):
# 间隔任务 try:
# path = Path(x)
# interval 触发器 _p = _backup_path / x
# if path.exists():
# 从 start_date 开始,每间隔一段时间触发,到 end_date 结束: if path.is_dir():
# if _p.exists():
# @nonebot.scheduler.scheduled_job( shutil.rmtree(_p, ignore_errors=True)
# 'interval', shutil.copytree(x, _p)
# # weeks=0, else:
# # days=0, if _p.exists():
# # hours=0, _p.unlink()
# minutes=5, shutil.copy(x, _p)
# # seconds=0, logger.info(f'已完成自动备份:{x}')
# # start_date=time.now(), except Exception as e:
# # end_date=None, logger.error(f"自动备份文件 {x} 发生错误 {type(e)}:{e}")
# )
# async def _():
# has_new_item = check_new_item() # 一次性任务
# if has_new_item: # 固定时间触发,仅触发一次:
# await bot.send_group_msg(group_id=123456, #
# message="XX有更新啦!") # from datetime import datetime
#
# @nonebot.scheduler.scheduled_job(
# 动态的计划任务 # 'date',
# import datetime # run_date=datetime(2021, 1, 1, 0, 0),
# # # timezone=None,
# from apscheduler.triggers.date import DateTrigger # 一次性触发器 # )
# # from apscheduler.triggers.cron import CronTrigger # 定期触发器 # async def _():
# # from apscheduler.triggers.interval import IntervalTrigger # 间隔触发器 # await bot.send_group_msg(group_id=123456,
# from nonebot import on_command, scheduler # message="2021,新年快乐!")
#
# @on_command('赖床') # 定期任务
# async def _(session: CommandSession): # 从 start_date 开始到 end_date 结束,根据类似 Cron
# await session.send('我会在5分钟后再喊你') #
# # 的规则触发任务:
# # 制作一个“5分钟后”触发器 #
# delta = datetime.timedelta(minutes=5) # @nonebot.scheduler.scheduled_job(
# trigger = DateTrigger( # 'cron',
# run_date=datetime.datetime.now() + delta # # year=None,
# ) # # month=None,
# # # day=None,
# # 添加任务 # # week=None,
# scheduler.add_job( # day_of_week="mon,tue,wed,thu,fri",
# func=session.send, # 要添加任务的函数,不要带参数 # hour=7,
# trigger=trigger, # 触发器 # # minute=None,
# args=('不要再赖床啦!',), # 函数的参数列表,注意:只有一个值时,不能省略末尾的逗号 # # second=None,
# # kwargs=None, # # start_date=None,
# misfire_grace_time=60, # 允许的误差时间,建议不要省略 # # end_date=None,
# # jobstore='default', # 任务储存库,在下一小节中说明 # # timezone=None,
# ) # )
# async def _():
# await bot.send_group_msg(group_id=123456,
# message="起床啦!")
# 间隔任务
#
# interval 触发器
#
# 从 start_date 开始,每间隔一段时间触发,到 end_date 结束:
#
# @nonebot.scheduler.scheduled_job(
# 'interval',
# # weeks=0,
# # days=0,
# # hours=0,
# minutes=5,
# # seconds=0,
# # start_date=time.now(),
# # end_date=None,
# )
# async def _():
# has_new_item = check_new_item()
# if has_new_item:
# await bot.send_group_msg(group_id=123456,
# message="XX有更新啦!")
# 动态的计划任务
# import datetime
#
# from apscheduler.triggers.date import DateTrigger # 一次性触发器
# # from apscheduler.triggers.cron import CronTrigger # 定期触发器
# # from apscheduler.triggers.interval import IntervalTrigger # 间隔触发器
# from nonebot import on_command, scheduler
#
# @on_command('赖床')
# async def _(session: CommandSession):
# await session.send('我会在5分钟后再喊你')
#
# # 制作一个“5分钟后”触发器
# delta = datetime.timedelta(minutes=5)
# trigger = DateTrigger(
# run_date=datetime.datetime.now() + delta
# )
#
# # 添加任务
# scheduler.add_job(
# func=session.send, # 要添加任务的函数,不要带参数
# trigger=trigger, # 触发器
# args=('不要再赖床啦!',), # 函数的参数列表,注意:只有一个值时,不能省略末尾的逗号
# # kwargs=None,
# misfire_grace_time=60, # 允许的误差时间,建议不要省略
# # jobstore='default', # 任务储存库,在下一小节中说明
# )
Regular → Executable
+156 -197
View File
@@ -1,197 +1,156 @@
from nonebot import on_command from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent, MessageEvent, Message, Bot
from models.ban_user import BanUser from nonebot.params import CommandArg, Command
from models.level_user import LevelUser from nonebot import on_command
from nonebot.typing import T_State from models.ban_user import BanUser
from nonebot.adapters.cqhttp import Bot from models.level_user import LevelUser
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent from typing import Tuple
from utils.utils import get_message_at, get_message_text, is_number from utils.utils import get_message_at, is_number
from configs.config import NICKNAME, Config from configs.config import NICKNAME, Config
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from services.log import logger from .data_source import parse_ban_time, a_ban
from services.log import logger
__zx_plugin_name__ = "封禁Ban用户 [Admin]"
__plugin_usage__ = """ __zx_plugin_name__ = "封禁Ban用户 [Admin]"
usage: __plugin_usage__ = """
将用户拉入或拉出黑名单 usage:
指令: 将用户拉入或拉出黑名单
.ban [at] ?[小时] ?[分钟] 指令:
.unban .ban [at] ?[小时] ?[分钟]
示例:.ban @user .unban
示例:.ban @user 6 示例:.ban @user
示例:.ban @user 3 10 示例:.ban @user 6
示例:.unban @user 示例:.ban @user 3 10
""".strip() 示例:.unban @user
__plugin_superuser_usage__ = """ """.strip()
usage: __plugin_superuser_usage__ = """
屏蔽用户消息,相当于最上级.ban usage:
指令: b了=屏蔽用户消息,相当于最上级.ban
b了 [at] 跨群ban以及跨群b了
示例:b了 @user 指令:
""".strip() b了 [at/qq]
__plugin_des__ = '你被逮捕了!丢进小黑屋!' .ban [user_id] ?[小时] ?[分钟]
__plugin_cmd__ = ['.ban [at] ?[小时] ?[分钟]', '.unban [at]', 'b了 [at] [_superuser]'] 示例:b了 @user
__plugin_version__ = 0.1 示例:b了 1234567
__plugin_author__ = 'HibiKier' 示例:.ban 12345567
__plugin_settings__ = { """.strip()
"admin_level": Config.get_config("ban", "BAN_LEVEL"), __plugin_des__ = '你被逮捕了!丢进小黑屋!'
"cmd": ['.ban', '.unban', 'ban', 'unban'] __plugin_cmd__ = ['.ban [at] ?[小时] ?[分钟]', '.unban [at]', 'b了 [at] [_superuser]']
} __plugin_version__ = 0.1
__plugin_configs__ = { __plugin_author__ = 'HibiKier'
"BAN_LEVEL [LEVEL]": { __plugin_settings__ = {
"value": 5, "admin_level": Config.get_config("ban", "BAN_LEVEL"),
"help": "ban/unban所需要的管理员权限等级", "cmd": ['.ban', '.unban', 'ban', 'unban']
"default_value": 5 }
} __plugin_configs__ = {
} "BAN_LEVEL [LEVEL]": {
"value": 5,
"help": "ban/unban所需要的管理员权限等级",
ban = on_command( "default_value": 5
".ban", }
aliases={".unban", "/ban", "/unban"}, }
priority=5,
block=True,
) ban = on_command(
".ban",
super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True) aliases={".unban", "/ban", "/unban"},
priority=5,
block=True,
@ban.handle() )
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
result = "" super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True)
qq = get_message_at(event.json())
if qq:
qq = qq[0] @ban.handle()
user_name = await bot.get_group_member_info(group_id=event.group_id, user_id=qq) async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
user_name = user_name['card'] if user_name['card'] else user_name['nickname'] cmd = cmd[0]
msg = get_message_text(event.json()) result = ""
if msg: qq = get_message_at(event.json())
msg = msg.split() if qq:
if len(msg) == 2: qq = qq[0]
if not is_number(msg[0].strip()) or not is_number(msg[1].strip()): user_name = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
await ban.finish("参数必须是数字!", at_sender=True) user_name = user_name['card'] or user_name['nickname']
time = int(msg[0]) * 60 * 60 + int(msg[1]) * 60 msg = arg.extract_plain_text().strip()
else: time = parse_ban_time(msg)
if not is_number(msg[0].strip()): if isinstance(time, str):
await ban.finish("参数必须是数字!", at_sender=True) await ban.finish(time, at_sender=True)
time = int(msg[0]) * 60 * 60 if cmd in [".ban", "/ban"]:
else: if (
time = -1 await LevelUser.get_user_level(event.user_id, event.group_id)
if state["_prefix"]["raw_command"] in [".ban", "/ban"]: <= await LevelUser.get_user_level(qq, event.group_id)
if ( and str(event.user_id) not in bot.config.superusers
await LevelUser.get_user_level(event.user_id, event.group_id) ):
<= await LevelUser.get_user_level(qq, event.group_id) await ban.finish(
and str(event.user_id) not in bot.config.superusers f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!",
): at_sender=True,
await ban.finish( )
f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!", result = await a_ban(qq, time, user_name, event)
at_sender=True, else:
) if (
if await BanUser.ban( await BanUser.check_ban_level(
qq, await LevelUser.get_user_level(event.user_id, event.group_id), time qq, await LevelUser.get_user_level(event.user_id, event.group_id)
): )
logger.info( and str(event.user_id) not in bot.config.superusers
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time/60} 分钟" ):
) await ban.finish(
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!" f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True
if time != -1: )
result += f"将在 {time/60} 分钟后解封" if await BanUser.unban(qq):
else: logger.info(
time = await BanUser.check_ban_time(qq) f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 解禁"
if is_number(time): )
time = abs(int(time)) result = f"已经把 {user_name} 从黑名单中删除了!"
if time < 60: else:
time = str(time) + " 秒" result = f"{user_name} 不在黑名单!"
else: else:
time = str(int(time / 60)) + " 分钟" await ban.finish("艾特人了吗??", at_sender=True)
else: await ban.send(result, at_sender=True)
time += " 分钟"
result = f"{user_name} 已在黑名单!预计 {time}后解封"
else: @ban.handle()
if ( async def _(bot: Bot, event: PrivateMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
await BanUser.check_ban_level( cmd = cmd[0]
qq, await LevelUser.get_user_level(event.user_id, event.group_id) msg = arg.extract_plain_text().strip()
) if msg:
and str(event.user_id) not in bot.config.superusers if str(event.user_id) in bot.config.superusers:
): if is_number(arg.extract_plain_text().strip().split()[0]):
await ban.finish( qq = int(msg[0])
f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True msg = msg[1:]
) if cmd in [".ban", "/ban"]:
if await BanUser.unban(qq): time = parse_ban_time(msg)
logger.info( if isinstance(time, str):
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 解禁" await ban.finish(time)
) result = await a_ban(qq, time, str(qq), event, 9)
result = f"已经把 {user_name} 从黑名单中删除了!" else:
else: if await BanUser.unban(qq):
result = f"{user_name} 不在黑名单!" logger.info(
else: f"USER {event.user_id} 将 USER {qq} 解禁"
await ban.finish("艾特人了吗??", at_sender=True) )
await ban.finish(result, at_sender=True) result = f"已经把 {qq} 从黑名单中删除了!"
else:
result = f"{qq} 不在黑名单!"
@ban.handle() await ban.send(result)
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): else:
if str(event.user_id) in bot.config.superusers: await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
msg = get_message_text(event.json())
msg = msg.split()
if is_number(msg[0]): @super_ban.handle()
qq = int(msg[0]) async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
if state["_prefix"]["raw_command"] in [".ban", "/ban"]: if isinstance(event, GroupMessageEvent):
hour = 0 qq = get_message_at(event.json())
minute = 0 else:
if len(msg) > 1 and is_number(msg[1]): qq = arg.extract_plain_text().strip()
hour = int(msg[1]) if not is_number(qq):
if len(msg) > 2 and is_number(msg[2]): await super_ban.finish("对象qq必须为纯数字...")
minute = int(msg[2]) qq = [qq]
time = hour * 60 * 60 + minute * 60 if qq:
time = time if time else -1 qq = qq[0]
if await BanUser.ban( user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
qq, 9, time user_name = user['card'] or user['nickname']
): if not await BanUser.ban(qq, 10, 99999999):
logger.info( await BanUser.unban(qq)
f"USER {event.user_id} 将 USER {qq} 封禁 时长 {time/60} 分钟" await BanUser.ban(qq, 10, 99999999)
) await ban.send(f"已将 {user_name} 拉入黑名单!")
result = f"已经将 {qq} 加入{NICKNAME}的黑名单了!" else:
if time != -1: await super_ban.send('需要添加被super ban的对象,可以使用at或者指定qq..')
result += f"将在 {time/60} 分钟后解封"
else:
result += f"将在 ∞ 分钟后解封"
await ban.send(result)
else:
time = await BanUser.check_ban_time(qq)
if is_number(time):
time = abs(int(time))
if time < 60:
time = str(time) + " 秒"
else:
time = str(int(time / 60)) + " 分钟"
else:
time += " 分钟"
await ban.send(f"{qq} 已在黑名单!预计 {time}后解封")
else:
if await BanUser.unban(qq):
logger.info(
f"USER {event.user_id} 将 USER {qq} 解禁"
)
result = f"已经把 {qq} 从黑名单中删除了!"
else:
result = f"{qq} 不在黑名单!"
await ban.send(result)
else:
await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
@super_ban.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
qq = get_message_at(event.json())
if qq:
qq = qq[0]
user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
user_name = user['card'] if user['card'] else user['nickname']
if not await BanUser.ban(qq, 10, 99999999):
await BanUser.unban(qq)
await BanUser.ban(qq, 10, 99999999)
await ban.send(f"已将 {user_name} 拉入黑名单!")
else:
await super_ban.send('需要艾特被super ban的对象..')
+69
View File
@@ -0,0 +1,69 @@
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from configs.config import NICKNAME
from models.level_user import LevelUser
from utils.utils import is_number
from models.ban_user import BanUser
from services.log import logger
from typing import Union
def parse_ban_time(msg: str) -> Union[int, str]:
"""
解析ban时长
:param msg: 文本消息
"""
if not msg:
return -1
msg = msg.split()
if len(msg) == 1:
if not is_number(msg[0].strip()):
return "参数必须是数字!"
return int(msg[0]) * 60 * 60
else:
if not is_number(msg[0].strip()) or not is_number(msg[1].strip()):
return "参数必须是数字!"
return int(msg[0]) * 60 * 60 + int(msg[1]) * 60
async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None) -> str:
"""
ban
:param qq: qq
:param time: ban时长
:param user_name: ban用户昵称
:param event: event
:param ban_level: ban级别
"""
if isinstance(event, GroupMessageEvent):
ban_level = await LevelUser.get_user_level(event.user_id, event.group_id)
if await BanUser.ban(qq, ban_level, time):
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time / 60} 分钟"
)
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
if time != -1:
result += f"将在 {time / 60} 分钟后解封"
else:
result += f"将在 ∞ 分钟后解封"
else:
time = await BanUser.check_ban_time(qq)
if is_number(time):
time = abs(int(time))
if time < 60:
time = str(time) + " 秒"
else:
time = str(int(time / 60)) + " 分钟"
else:
time += " 分钟"
result = f"{user_name} 已在黑名单!预计 {time}后解封"
return result
+67 -59
View File
@@ -1,59 +1,67 @@
from nonebot import on_command from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
from nonebot.typing import T_State from nonebot import on_command
from nonebot.adapters import Bot, Event from nonebot.permission import SUPERUSER
from nonebot.permission import SUPERUSER from nonebot.params import CommandArg
import asyncio from utils.utils import get_message_img
from utils.utils import get_message_text, get_message_imgs from services.log import logger
from services.log import logger from utils.message_builder import image
from utils.message_builder import image from utils.manager import group_manager
from utils.manager import group_manager from configs.config import Config
import asyncio
__zx_plugin_name__ = "广播 [Superuser]"
__plugin_usage__ = """
usage: __zx_plugin_name__ = "广播 [Superuser]"
指令: __plugin_usage__ = """
广播- ?[消息] ?[图片] usage:
示例:广播- 你们好! 指令:
""".strip() 广播- ?[消息] ?[图片]
__plugin_des__ = "昭告天下!" 示例:广播- 你们好!
__plugin_cmd__ = ["广播-"] """.strip()
__plugin_version__ = 0.1 __plugin_des__ = "昭告天下!"
__plugin_author__ = "HibiKier" __plugin_cmd__ = ["广播-"]
__plugin_task__ = {"broadcast": "广播"} __plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True) __plugin_task__ = {"broadcast": "广播"}
Config.add_plugin_config(
"_task",
@broadcast.handle() "DEFAULT_BROADCAST",
async def _(bot: Bot, event: Event, state: T_State): True,
msg = get_message_text(event.json()) help_="被动 广播 进群默认开关状态",
imgs = get_message_imgs(event.json()) default_value=True,
rst = "" )
for img in imgs:
rst += image(img) broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
sid = bot.self_id
gl = await bot.get_group_list(self_id=sid)
gl = [ @broadcast.handle()
g["group_id"] async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
for g in gl msg = arg.extract_plain_text().strip()
if await group_manager.check_group_task_status(g["group_id"], "broadcast") img_list = get_message_img(event.json())
] rst = ""
g_cnt = len(gl) for img in img_list:
cnt = 0 rst += image(img)
error = "" gl = await bot.get_group_list()
x = 0.25 gl = [
for g in gl: g["group_id"]
cnt += 1 for g in gl
if cnt / g_cnt > x: if await group_manager.check_group_task_status(g["group_id"], "broadcast")
await broadcast.send(f"已播报至 {int(cnt / g_cnt * 100)}% 的群聊") ]
x += 0.25 g_cnt = len(gl)
try: cnt = 0
await bot.send_group_msg(self_id=sid, group_id=g, message=msg + rst) error = ""
logger.info(f"GROUP {g} 投递广播成功") x = 0.25
except Exception as e: for g in gl:
logger.error(f"GROUP {g} 投递广播失败:{type(e)}") cnt += 1
error += f"GROUP {g} 投递广播失败:{type(e)}\n" if cnt / g_cnt > x:
await asyncio.sleep(0.5) await broadcast.send(f"已播报至 {int(cnt / g_cnt * 100)}% 的群聊")
await broadcast.send(f"已播报至 100% 的群聊") x += 0.25
if error: try:
await broadcast.send(f"播报时错误:{error}") await bot.send_group_msg(group_id=g, message=msg + rst)
logger.info(f"GROUP {g} 投递广播成功")
except Exception as e:
logger.error(f"GROUP {g} 投递广播失败:{type(e)}")
error += f"GROUP {g} 投递广播失败:{type(e)}\n"
await asyncio.sleep(0.5)
await broadcast.send(f"已播报至 100% 的群聊")
if error:
await broadcast.send(f"播报时错误:{error}")
+41
View File
@@ -0,0 +1,41 @@
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from models.chat_history import ChatHistory
from ._rule import rule
from configs.config import Config
from nonebot import on_message
__zx_plugin_name__ = "消息存储 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
Config.add_plugin_config(
"chat_history",
"FLAG",
True,
help_="是否开启消息自从存储",
name="消息存储",
default_value=True
)
chat_history = on_message(rule=rule, priority=1, block=False)
# test = on_command("aa")
@chat_history.handle()
async def _(event: MessageEvent):
if isinstance(event, GroupMessageEvent):
await ChatHistory.add_chat_msg(event.user_id, event.group_id, str(event.get_message()))
else:
await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message()))
# @test.handle()
# async def _(event: MessageEvent):
# print(await ChatHistory.get_user_msg(event.user_id, "private"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "private"))
# print(await ChatHistory.get_user_msg(event.user_id, "group"))
# print(await ChatHistory.get_user_msg_count(event.user_id, "group"))
# print(await ChatHistory.get_group_msg(event.group_id))
# print(await ChatHistory.get_group_msg_count(event.group_id))
+6
View File
@@ -0,0 +1,6 @@
from nonebot.adapters.onebot.v11 import Event, MessageEvent
from configs.config import Config
def rule(event: Event) -> bool:
return Config.get_config("chat_history", "FLAG") and isinstance(event, MessageEvent)
+195 -184
View File
@@ -1,184 +1,195 @@
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 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.cqhttp import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
GroupIncreaseNoticeEvent, GroupIncreaseNoticeEvent,
GroupDecreaseNoticeEvent, GroupDecreaseNoticeEvent,
) )
from nonebot.adapters.cqhttp.exception import ActionFailed 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
from utils.utils import FreqLimiter from utils.utils import FreqLimiter
from configs.config import Config from configs.config import Config
from pathlib import Path from pathlib import Path
import random import random
import os import os
try: try:
import ujson as json import ujson as json
except ModuleNotFoundError: except ModuleNotFoundError:
import json import json
__zx_plugin_name__ = "群事件处理 [Hidden]" __zx_plugin_name__ = "群事件处理 [Hidden]"
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = "HibiKier" __plugin_author__ = "HibiKier"
__plugin_task__ = {"group_welcome": "进群欢迎", "refund_group_remind": "退群提醒"} __plugin_task__ = {"group_welcome": "进群欢迎", "refund_group_remind": "退群提醒"}
Config.add_plugin_config( Config.add_plugin_config(
"auto_invite", "message", f"请不要未经同意就拉{NICKNAME}入群!告辞!", help_="强制拉群后进群回复的内容.." "invite_manager", "message", f"请不要未经同意就拉{NICKNAME}入群!告辞!", help_="强制拉群后进群回复的内容.."
) )
Config.add_plugin_config( Config.add_plugin_config(
"auto_invite", "flag", True, help_="被强制拉群后是否直接退出", default_value=True "invite_manager", "flag", True, help_="被强制拉群后是否直接退出", default_value=True
) )
Config.add_plugin_config( Config.add_plugin_config(
"auto_invite", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5 "invite_manager", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
) )
_flmt = FreqLimiter(Config.get_config("auto_invite", "welcome_msg_cd")) Config.add_plugin_config(
"_task",
"DEFAULT_GROUP_WELCOME",
# 群员增加处理 True,
group_increase_handle = on_notice(priority=1, block=False) help_="被动 进群欢迎 进群默认开关状态",
# 群员减少处理 default_value=True,
group_decrease_handle = on_notice(priority=1, block=False) )
# (群管理)加群同意请求 Config.add_plugin_config(
add_group = on_request(priority=1, block=False) "_task",
"DEFAULT_REFUND_GROUP_REMIND",
True,
@group_increase_handle.handle() help_="被动 退群提醒 进群默认开关状态",
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): default_value=True,
if event.user_id == int(bot.self_id): )
group = await GroupInfo.get_group_info(event.group_id)
# 群聊不存在或被强制拉群,退出该群
if (not group or group.group_flag == 0) and Config.get_config( _flmt = FreqLimiter(Config.get_config("invite_manager", "welcome_msg_cd"))
"auto_invite", "flag"
):
try: # 群员增加处理
msg = Config.get_config("auto_invite", "message") group_increase_handle = on_notice(priority=1, block=False)
if msg: # 群员减少处理
await bot.send_group_msg(group_id=event.group_id, message=msg) group_decrease_handle = on_notice(priority=1, block=False)
await bot.set_group_leave(group_id=event.group_id) # (群管理)加群同意请求
await bot.send_private_msg( add_group = on_request(priority=1, block=False)
user_id=int(list(bot.config.superusers)[0]),
message=f"触发强制入群保护,已成功退出群聊 {event.group_id}..",
) @group_increase_handle.handle()
logger.info(f"强制拉群或未有群信息,退出群聊 {group} 成功") async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
requests_manager.remove_request("group", event.group_id) if event.user_id == int(bot.self_id):
except Exception as e: group = await GroupInfo.get_group_info(event.group_id)
logger.info(f"强制拉群或未有群信息,退出群聊 {group} 失败 e:{e}") # 群聊不存在或被强制拉群,退出该群
await bot.send_private_msg( if (not group or group.group_flag == 0) and Config.get_config(
user_id=int(list(bot.config.superusers)[0]), "invite_manager", "flag"
message=f"触发强制入群保护,退出群聊 {event.group_id} 失败..", ):
) try:
# 默认群功能开关 msg = Config.get_config("invite_manager", "message")
elif event.group_id not in group_manager["group_manager"].keys(): if msg:
data = plugins2settings_manager.get_data() await bot.send_group_msg(group_id=event.group_id, message=msg)
for plugin in data.keys(): await bot.set_group_leave(group_id=event.group_id)
if not data[plugin]["default_status"]: await bot.send_private_msg(
group_manager.block_plugin(plugin, event.group_id) user_id=int(list(bot.config.superusers)[0]),
else: message=f"触发强制入群保护,已成功退出群聊 {event.group_id}..",
join_time = datetime.now() )
user_info = await bot.get_group_member_info( logger.info(f"强制拉群或未有群信息,退出群聊 {group} 成功")
group_id=event.group_id, user_id=event.user_id requests_manager.remove_request("group", event.group_id)
) except Exception as e:
if await GroupInfoUser.add_member_info( logger.info(f"强制拉群或未有群信息,退出群聊 {group} 失败 e:{e}")
user_info["user_id"], await bot.send_private_msg(
user_info["group_id"], user_id=int(list(bot.config.superusers)[0]),
user_info["nickname"], message=f"触发强制入群保护,退出群聊 {event.group_id} 失败..",
join_time, )
): # 默认群功能开关
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功") elif event.group_id not in group_manager["group_manager"].keys():
else: data = plugins2settings_manager.get_data()
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败") for plugin in data.keys():
if not data[plugin]["default_status"]:
# 群欢迎消息 group_manager.block_plugin(plugin, event.group_id)
if await group_manager.check_group_task_status( else:
event.group_id, "group_welcome" join_time = datetime.now()
) and _flmt.check(event.group_id): user_info = await bot.get_group_member_info(
_flmt.start_cd(event.group_id) group_id=event.group_id, user_id=event.user_id
msg = "" )
img = "" if await GroupInfoUser.add_member_info(
at_flag = False user_info["user_id"],
custom_welcome_msg_json = ( user_info["group_id"],
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json" user_info["nickname"],
) join_time,
if custom_welcome_msg_json.exists(): ):
data = json.load(open(custom_welcome_msg_json, "r")) logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
if data.get(str(event.group_id)): else:
msg = data[str(event.group_id)] logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
if msg.find("[at]") != -1:
msg = msg.replace("[at]", "") # 群欢迎消息
at_flag = True if _flmt.check(event.group_id):
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"): _flmt.start_cd(event.group_id)
img = image( msg = ""
abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg" img = ""
) at_flag = False
if msg or img: custom_welcome_msg_json = (
await group_increase_handle.send( Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
"\n" + msg.strip() + img, at_sender=at_flag )
) if custom_welcome_msg_json.exists():
else: data = json.load(open(custom_welcome_msg_json, "r"))
await group_increase_handle.send( if data.get(str(event.group_id)):
"新人快跑啊!!本群现状↓(快使用自定义!)" msg = data[str(event.group_id)]
+ image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz") if msg.find("[at]") != -1:
) msg = msg.replace("[at]", "")
at_flag = True
if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists():
@group_decrease_handle.handle() img = image(
async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict): DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg"
# 被踢出群 )
if event.sub_type == "kick_me": if msg or img:
group_id = event.group_id msg = msg.strip() + img
operator_id = event.operator_id msg = "\n" + msg if at_flag else msg
try: await group_increase_handle.send(
operator_name = ( "[[_task|group_welcome]]" + msg, at_sender=at_flag
await GroupInfoUser.get_member_info(event.operator_id, event.group_id) )
).user_name else:
except AttributeError: await group_increase_handle.send(
operator_name = "None" "[[_task|group_welcome]]新人快跑啊!!本群现状↓(快使用自定义!)"
group = await GroupInfo.get_group_info(group_id) + image(random.choice(os.listdir(IMAGE_PATH / "qxz")), "qxz")
group_name = group.group_name if group else "" )
coffee = int(list(bot.config.superusers)[0])
await bot.send_private_msg(
user_id=coffee, @group_decrease_handle.handle()
message=f"****呜..一份踢出报告****\n" async def _(bot: Bot, event: GroupDecreaseNoticeEvent):
f"我被 {operator_name}({operator_id})\n" # 被踢出群
f"踢出了 {group_name}({group_id})\n" if event.sub_type == "kick_me":
f"日期:{str(datetime.now()).split('.')[0]}", group_id = event.group_id
) operator_id = event.operator_id
return try:
if event.user_id == int(bot.self_id): operator_name = (
group_manager.delete_group(event.group_id) await GroupInfoUser.get_member_info(event.operator_id, event.group_id)
return ).user_name
try: except AttributeError:
user_name = ( operator_name = "None"
await GroupInfoUser.get_member_info(event.user_id, event.group_id) group = await GroupInfo.get_group_info(group_id)
).user_name group_name = group.group_name if group else ""
except AttributeError: coffee = int(list(bot.config.superusers)[0])
user_name = str(event.user_id) await bot.send_private_msg(
if await GroupInfoUser.delete_member_info(event.user_id, event.group_id): user_id=coffee,
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除成功") message=f"****呜..一份踢出报告****\n"
else: f"我被 {operator_name}({operator_id})\n"
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败") f"踢出了 {group_name}({group_id})\n"
if await group_manager.check_group_task_status( f"日期:{str(datetime.now()).split('.')[0]}",
event.group_id, "refund_group_remind" )
): return
rst = "" if event.user_id == int(bot.self_id):
if event.sub_type == "leave": group_manager.delete_group(event.group_id)
rst = f"{user_name}离开了我们..." return
if event.sub_type == "kick": try:
operator = await bot.get_group_member_info( user_name = (
user_id=event.operator_id, group_id=event.group_id await GroupInfoUser.get_member_info(event.user_id, event.group_id)
) ).user_name
operator_name = ( except AttributeError:
operator["card"] if operator["card"] else operator["nickname"] user_name = str(event.user_id)
) if await GroupInfoUser.delete_member_info(event.user_id, event.group_id):
rst = f"{user_name} 被 {operator_name} 送走了." logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除成功")
try: else:
await group_decrease_handle.send(f"{rst}") logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败")
except ActionFailed: rst = ""
return if event.sub_type == "leave":
rst = f"{user_name}离开了我们..."
if event.sub_type == "kick":
operator = await bot.get_group_member_info(
user_id=event.operator_id, group_id=event.group_id
)
operator_name = operator["card"] if operator["card"] else operator["nickname"]
rst = f"{user_name} 被 {operator_name} 送走了."
try:
await group_decrease_handle.send(f"[[_task|refund_group_remind]]{rst}")
except ActionFailed:
return
Regular → Executable
+73 -73
View File
@@ -1,73 +1,73 @@
from nonebot import on_command from nonebot import on_command
from nonebot.adapters.cqhttp import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
MessageEvent, MessageEvent,
GroupMessageEvent GroupMessageEvent,
) Message
from nonebot.typing import T_State )
from nonebot.rule import to_me from nonebot.params import CommandArg
from configs.path_config import IMAGE_PATH, DATA_PATH from nonebot.typing import T_State
from utils.message_builder import image from nonebot.rule import to_me
from .data_source import create_help_img, get_plugin_help from configs.path_config import IMAGE_PATH, DATA_PATH
from utils.utils import get_message_text from utils.message_builder import image
from pathlib import Path from .data_source import create_help_img, get_plugin_help
import os import os
__zx_plugin_name__ = "帮助" __zx_plugin_name__ = "帮助"
group_help_path = Path(DATA_PATH) / "group_help" group_help_path = DATA_PATH / "group_help"
help_image = Path(IMAGE_PATH) / "help.png" help_image = IMAGE_PATH / "help.png"
simple_help_image = Path(IMAGE_PATH) / "simple_help.png" simple_help_image = IMAGE_PATH / "simple_help.png"
if help_image.exists(): if help_image.exists():
help_image.unlink() help_image.unlink()
if simple_help_image.exists(): if simple_help_image.exists():
simple_help_image.unlink() simple_help_image.unlink()
group_help_path.mkdir(exist_ok=True, parents=True) group_help_path.mkdir(exist_ok=True, parents=True)
for x in os.listdir(group_help_path): for x in os.listdir(group_help_path):
group_help_image = group_help_path / x group_help_image = group_help_path / x
group_help_image.unlink() group_help_image.unlink()
_help = on_command("详细功能", rule=to_me(), aliases={"详细帮助"}, priority=1, block=True) _help = on_command("详细功能", rule=to_me(), aliases={"详细帮助"}, priority=1, block=True)
simple_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True) simple_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True)
@_help.handle() @_help.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): async def _(bot: Bot, event: MessageEvent, state: T_State):
if not help_image.exists(): if not help_image.exists():
if help_image.exists(): if help_image.exists():
help_image.unlink() help_image.unlink()
if simple_help_image.exists(): if simple_help_image.exists():
simple_help_image.unlink() simple_help_image.unlink()
await create_help_img(None, help_image, simple_help_image) await create_help_img(None, help_image, simple_help_image)
await _help.finish(image("help.png")) await _help.finish(image("help.png"))
@simple_help.handle() @simple_help.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): async def _(bot: Bot, event: MessageEvent, state: T_State, arg: Message = CommandArg()):
msg = get_message_text(event.json()) msg = arg.extract_plain_text().strip()
is_super = False is_super = False
if msg: if msg:
if '-super' in msg: if '-super' in msg:
if str(event.user_id) in bot.config.superusers: if str(event.user_id) in bot.config.superusers:
is_super = True is_super = True
msg = msg.replace('-super', '').strip() msg = msg.replace('-super', '').strip()
msg = get_plugin_help(msg, is_super) msg = get_plugin_help(msg, is_super)
if msg: if msg:
await _help.send(image(b64=msg)) await _help.send(image(b64=msg))
else: else:
await _help.send("没有此功能的帮助信息...") await _help.send("没有此功能的帮助信息...")
else: else:
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
_image_path = group_help_path / f"{event.group_id}.png" _image_path = group_help_path / f"{event.group_id}.png"
if not _image_path.exists(): if not _image_path.exists():
await create_help_img(event.group_id, help_image, _image_path) await create_help_img(event.group_id, help_image, _image_path)
await simple_help.send(image(_image_path)) await simple_help.send(image(_image_path))
else: else:
if not simple_help_image.exists(): if not simple_help_image.exists():
if help_image.exists(): if help_image.exists():
help_image.unlink() help_image.unlink()
if simple_help_image.exists(): if simple_help_image.exists():
simple_help_image.unlink() simple_help_image.unlink()
await create_help_img(None, help_image, simple_help_image) await create_help_img(None, help_image, simple_help_image)
await _help.finish(image("simple_help.png")) await _help.finish(image("simple_help.png"))
+367 -367
View File
@@ -1,367 +1,367 @@
from utils.image_utils import CreateImg from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from utils.manager import ( from utils.manager import (
plugins2settings_manager, plugins2settings_manager,
admin_manager, admin_manager,
plugins_manager, plugins_manager,
group_manager, group_manager,
) )
from typing import Optional from typing import Optional
from services.log import logger from services.log import logger
from pathlib import Path from pathlib import Path
from utils.utils import get_matchers from utils.utils import get_matchers
import random import random
import asyncio import asyncio
import nonebot import nonebot
import os import os
random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help" random_bk_path = IMAGE_PATH / "background" / "help" / "simple_help"
background = Path(IMAGE_PATH) / "background" / "0.png" background = IMAGE_PATH / "background" / "0.png"
async def create_help_img( async def create_help_img(
group_id: Optional[int], help_image: Path, simple_help_image: Path group_id: Optional[int], help_image: Path, simple_help_image: Path
): ):
""" """
生成帮助图片 生成帮助图片
:param group_id: 群号 :param group_id: 群号
:param help_image: 图片路径 :param help_image: 图片路径
:param simple_help_image: 简易帮助图片路径 :param simple_help_image: 简易帮助图片路径
""" """
return await asyncio.get_event_loop().run_in_executor( return await asyncio.get_event_loop().run_in_executor(
None, _create_help_img, group_id, help_image, simple_help_image None, _create_help_img, group_id, help_image, simple_help_image
) )
def _create_help_img( def _create_help_img(
group_id: Optional[int], help_image: Path, simple_help_image: Path group_id: Optional[int], help_image: Path, simple_help_image: Path
): ):
""" """
生成帮助图片 生成帮助图片
:param group_id: 群号 :param group_id: 群号
:param help_image: 图片路径 :param help_image: 图片路径
:param simple_help_image: 简易帮助图片路径 :param simple_help_image: 简易帮助图片路径
""" """
_matchers = get_matchers() _matchers = get_matchers()
width = 0 width = 0
matchers_data = {} matchers_data = {}
_des_tmp = {} _des_tmp = {}
_plugin_name_tmp = [] _plugin_name_tmp = []
_tmp = [] _tmp = []
tmp_img = CreateImg(0, 0, plain_text="1", font_size=24) tmp_img = BuildImage(0, 0, plain_text="1", font_size=24)
font_height = tmp_img.h font_height = tmp_img.h
# 插件分类 # 插件分类
for matcher in _matchers: for matcher in _matchers:
plugin_name = None plugin_name = None
_plugin = nonebot.plugin.get_plugin(matcher.module) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
_module = _plugin.module _module = _plugin.module
try: try:
plugin_name = _module.__getattribute__("__zx_plugin_name__") plugin_name = _module.__getattribute__("__zx_plugin_name__")
try: try:
plugin_des = _module.__getattribute__("__plugin_des__") plugin_des = _module.__getattribute__("__plugin_des__")
except AttributeError: except AttributeError:
plugin_des = "_" plugin_des = "_"
if ( if (
"[hidden]" in plugin_name.lower() "[hidden]" in plugin_name.lower()
or "[admin]" in plugin_name.lower() or "[admin]" in plugin_name.lower()
or "[superuser]" in plugin_name.lower() or "[superuser]" in plugin_name.lower()
or plugin_name in _plugin_name_tmp or plugin_name in _plugin_name_tmp
or plugin_name == "帮助" or plugin_name == "帮助"
): ):
continue continue
plugin_type = ("normal",) plugin_type = ("normal",)
text_type = 0 text_type = 0
if plugins2settings_manager.get( if plugins2settings_manager.get(
matcher.module matcher.plugin_name
) and plugins2settings_manager[matcher.module].get("plugin_type"): ) and plugins2settings_manager[matcher.plugin_name].get("plugin_type"):
plugin_type = tuple( plugin_type = tuple(
plugins2settings_manager.get_plugin_data(matcher.module)[ plugins2settings_manager.get_plugin_data(matcher.plugin_name)[
"plugin_type" "plugin_type"
] ]
) )
else: else:
try: try:
plugin_type = _module.__getattribute__("__plugin_type__") plugin_type = _module.__getattribute__("__plugin_type__")
except AttributeError: except AttributeError:
pass pass
if len(plugin_type) > 1: if len(plugin_type) > 1:
try: try:
text_type = int(plugin_type[1]) text_type = int(plugin_type[1])
except ValueError as e: except ValueError as e:
logger.warning(f"生成列向帮助排列失败 {plugin_name}: {type(e)}: {e}") logger.warning(f"生成列向帮助排列失败 {plugin_name}: {type(e)}: {e}")
plugin_type = plugin_type[0] plugin_type = plugin_type[0]
else: else:
plugin_type = plugin_type[0] plugin_type = plugin_type[0]
try: try:
plugin_cmd = _module.__getattribute__("__plugin_cmd__") plugin_cmd = _module.__getattribute__("__plugin_cmd__")
plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x] plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x]
except AttributeError: except AttributeError:
plugin_cmd = [] plugin_cmd = []
if plugin_type not in matchers_data.keys(): if plugin_type not in matchers_data.keys():
matchers_data[plugin_type] = {} matchers_data[plugin_type] = {}
if plugin_des in _des_tmp.keys(): if plugin_des in _des_tmp.keys():
try: try:
matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] = ( matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] = (
matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"]
+ plugin_cmd + plugin_cmd
) )
except KeyError as e: except KeyError as e:
logger.warning(f"{type(e)}: {e}") logger.warning(f"{type(e)}: {e}")
else: else:
matchers_data[plugin_type][plugin_name] = { matchers_data[plugin_type][plugin_name] = {
"module": matcher.module, "modules": matcher.plugin_name,
"des": plugin_des, "des": plugin_des,
"cmd": plugin_cmd, "cmd": plugin_cmd,
"text_type": text_type, "text_type": text_type,
} }
try: try:
if text_type == 0: if text_type == 0:
x = tmp_img.getsize( x = tmp_img.getsize(
f'{plugin_name}: {matchers_data[plugin_type][plugin_name]["des"]} ->' f'{plugin_name}: {matchers_data[plugin_type][plugin_name]["des"]} ->'
+ " / ".join(matchers_data[plugin_type][plugin_name]["cmd"]) + " / ".join(matchers_data[plugin_type][plugin_name]["cmd"])
)[0] )[0]
width = width if width > x else x width = width if width > x else x
except KeyError: except KeyError:
pass pass
if plugin_des not in _des_tmp: if plugin_des not in _des_tmp:
_des_tmp[plugin_des] = plugin_name _des_tmp[plugin_des] = plugin_name
except AttributeError as e: except AttributeError as e:
if plugin_name not in _plugin_name_tmp: if plugin_name not in _plugin_name_tmp:
logger.warning(f"获取功能 {matcher.module}: {plugin_name} 设置失败...e:{e}") logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e:{e}")
if plugin_name not in _plugin_name_tmp: if plugin_name not in _plugin_name_tmp:
_plugin_name_tmp.append(plugin_name) _plugin_name_tmp.append(plugin_name)
help_img_list = [] help_img_list = []
simple_help_img_list = [] simple_help_img_list = []
types = list(matchers_data.keys()) types = list(matchers_data.keys())
types.sort() types.sort()
ix = 0 ix = 0
# 详细帮助 # 详细帮助
for type_ in types: for type_ in types:
keys = list(matchers_data[type_].keys()) keys = list(matchers_data[type_].keys())
keys.sort() keys.sort()
help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n" help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
simple_help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n" simple_help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
for i, k in enumerate(keys): for i, k in enumerate(keys):
# 禁用flag # 禁用flag
flag = True flag = True
if plugins_manager.get_plugin_status( if plugins_manager.get_plugin_status(
matchers_data[type_][k]["module"], "all" matchers_data[type_][k]["modules"], "all"
): ):
flag = False flag = False
if group_id: if group_id:
flag = flag and plugins_manager.get_plugin_status( flag = flag and plugins_manager.get_plugin_status(
matchers_data[type_][k]["module"], "group" matchers_data[type_][k]["modules"], "group"
) )
simple_help_str += ( simple_help_str += (
f"{i+1}.{k}<|_|~|>" f"{i+1}.{k}<|_|~|>"
f"{group_manager.get_plugin_status(matchers_data[type_][k]['module'], group_id) if group_id else '_'}|" f"{group_manager.get_plugin_status(matchers_data[type_][k]['modules'], group_id) if group_id else '_'}|"
f"{flag}\n" f"{flag}\n"
) )
if matchers_data[type_][k]["text_type"] == 1: if matchers_data[type_][k]["text_type"] == 1:
_x = tmp_img.getsize( _x = tmp_img.getsize(
f"{i+1}".rjust(5) f"{i+1}".rjust(5)
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} ' + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
)[0] )[0]
_str = ( _str = (
f"{i+1}".rjust(5) f"{i+1}".rjust(5)
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} ' + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
) )
_str += matchers_data[type_][k]["cmd"][0] + "\n" _str += matchers_data[type_][k]["cmd"][0] + "\n"
for c in matchers_data[type_][k]["cmd"][1:]: for c in matchers_data[type_][k]["cmd"][1:]:
_str += "".rjust(int(_x * 0.125) + 1) + f"{c}\n" _str += "".rjust(int(_x * 0.125) + 1) + f"{c}\n"
help_str += _str help_str += _str
else: else:
help_str += ( help_str += (
f"{i+1}".rjust(5) f"{i+1}".rjust(5)
+ f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} ' + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
+ " / ".join(matchers_data[type_][k]["cmd"]) + " / ".join(matchers_data[type_][k]["cmd"])
+ "\n" + "\n"
) )
height = len(help_str.split("\n")) * (font_height + 5) height = len(help_str.split("\n")) * (font_height + 5)
simple_height = len(simple_help_str.split("\n")) * (font_height + 5) simple_height = len(simple_help_str.split("\n")) * (font_height + 5)
A = CreateImg( A = BuildImage(
width + 150, height, font_size=24, color="white" if not ix % 2 else "black" width + 150, height, font_size=24, color="white" if not ix % 2 else "black"
) )
A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0)) A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
# 生成各个分类的插件简易帮助图片 # 生成各个分类的插件简易帮助图片
simple_width = 0 simple_width = 0
for x in [ for x in [
tmp_img.getsize(x.split("<|_|~|>")[0])[0] tmp_img.getsize(x.split("<|_|~|>")[0])[0]
for x in simple_help_str.split("\n") for x in simple_help_str.split("\n")
]: ]:
simple_width = simple_width if simple_width > x else x simple_width = simple_width if simple_width > x else x
bk = CreateImg(simple_width + 20, simple_height, font_size=24, color="#6495ED") bk = BuildImage(simple_width + 20, simple_height, font_size=24, color="#6495ED")
B = CreateImg( B = BuildImage(
simple_width + 20, simple_width + 20,
simple_height, simple_height,
font_size=24, font_size=24,
color="white" if not ix % 2 else "black", color="white" if not ix % 2 else "black",
) )
# 切分,判断插件开关状态 # 切分,判断插件开关状态
_s_height = 10 _s_height = 10
for _s in simple_help_str.split("\n"): for _s in simple_help_str.split("\n"):
text_color = (255, 255, 255) if ix % 2 else (0, 0, 0) text_color = (255, 255, 255) if ix % 2 else (0, 0, 0)
_line_flag = False _line_flag = False
if "<|_|~|>" in _s: if "<|_|~|>" in _s:
_x = _s.split("<|_|~|>") _x = _s.split("<|_|~|>")
_flag_sp = _x[-1].split("|") _flag_sp = _x[-1].split("|")
if group_id: if group_id:
if _flag_sp[0].lower() != "true": if _flag_sp[0].lower() != "true":
text_color = (252, 75, 13) text_color = (252, 75, 13)
if _flag_sp[1].lower() == "true": if _flag_sp[1].lower() == "true":
_line_flag = True _line_flag = True
_s = _x[0] _s = _x[0]
B.text((10, _s_height), _s, text_color) B.text((10, _s_height), _s, text_color)
if _line_flag: if _line_flag:
B.line( B.line(
( (
7, 7,
_s_height + int(B.getsize(_s)[1] / 2) + 2, _s_height + int(B.getsize(_s)[1] / 2) + 2,
B.getsize(_s)[0] + 11, B.getsize(_s)[0] + 11,
_s_height + int(B.getsize(_s)[1] / 2) + 2, _s_height + int(B.getsize(_s)[1] / 2) + 2,
), ),
(236, 66, 7), (236, 66, 7),
3, 3,
) )
_s_height += B.getsize("1")[1] + 5 _s_height += B.getsize("1")[1] + 5
# B.text((10, 10), simple_help_str, (255, 255, 255) if ix % 2 else (0, 0, 0)) # B.text((10, 10), simple_help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
bk.paste(B, center_type="center") bk.paste(B, center_type="center")
bk.transparent(2) bk.transparent(2)
ix += 1 ix += 1
help_img_list.append(A) help_img_list.append(A)
simple_help_img_list.append(bk) simple_help_img_list.append(bk)
height = 0 height = 0
for img in help_img_list: for img in help_img_list:
height += img.h height += img.h
if not group_id: if not group_id:
A = CreateImg(width + 150, height + 50, font_size=24) A = BuildImage(width + 150, height + 50, font_size=24)
A.text( A.text(
(10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n' (10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n'
) )
current_height = 50 current_height = 50
for img in help_img_list: for img in help_img_list:
A.paste(img, (0, current_height)) A.paste(img, (0, current_height))
current_height += img.h current_height += img.h
A.save(help_image) A.save(help_image)
# 详细帮助生成完毕 # 详细帮助生成完毕
# 简易帮助图片合成 # 简易帮助图片合成
height = 0 height = 0
width = 0 width = 0
for img in simple_help_img_list: for img in simple_help_img_list:
if img.h > height: if img.h > height:
height = img.h height = img.h
width += img.w + 10 width += img.w + 10
B = CreateImg(width + 100, height + 250, font_size=24) B = BuildImage(width + 100, height + 250, font_size=24)
width, _ = get_max_width_or_paste(simple_help_img_list, B) width, _ = get_max_width_or_paste(simple_help_img_list, B)
bk = None bk = None
random_bk = os.listdir(random_bk_path) random_bk = os.listdir(random_bk_path)
if random_bk: if random_bk:
bk = random.choice(random_bk) bk = random.choice(random_bk)
x = max(width + 50, height + 250) x = max(width + 50, height + 250)
B = CreateImg( B = BuildImage(
x, x,
x, x,
font_size=24, font_size=24,
color="#FFEFD5", color="#FFEFD5",
background=random_bk_path / bk, background=random_bk_path / bk,
) )
B.filter("GaussianBlur", 10) B.filter("GaussianBlur", 10)
_, B = get_max_width_or_paste(simple_help_img_list, B, True) _, B = get_max_width_or_paste(simple_help_img_list, B, True)
w = 10 w = 10
h = 10 h = 10
for msg in ["目前支持的功能列表:", "可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法", "或者使用 ‘详细帮助’ 来获取所有功能方法"]: for msg in ["目前支持的功能列表:", "可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法", "或者使用 ‘详细帮助’ 来获取所有功能方法"]:
text = CreateImg( text = BuildImage(
0, 0,
0, 0,
plain_text=msg, plain_text=msg,
font_size=24, font_size=24,
font="yuanshen.ttf", font="yuanshen.ttf",
) )
B.paste(text, (w, h), True) B.paste(text, (w, h), True)
h += 50 h += 50
if msg == "目前支持的功能列表:": if msg == "目前支持的功能列表:":
w += 50 w += 50
B.paste( B.paste(
CreateImg( BuildImage(
0, 0,
0, 0,
plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护", plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护",
font_size=24, font_size=24,
font="yuanshen.ttf", font="yuanshen.ttf",
font_color=(231, 74, 57) font_color=(231, 74, 57)
), ),
(300, 10), (300, 10),
True, True,
) )
B.save(simple_help_image) B.save(simple_help_image)
def get_max_width_or_paste( def get_max_width_or_paste(
simple_help_img_list: list, B: CreateImg = None, is_paste: bool = False simple_help_img_list: list, B: BuildImage = None, is_paste: bool = False
) -> "int, CreateImg": ) -> "int, BuildImage":
""" """
获取最大宽度,或直接贴图 获取最大宽度,或直接贴图
:param simple_help_img_list: 简单帮助图片列表 :param simple_help_img_list: 简单帮助图片列表
:param B: 背景图 :param B: 背景图
:param is_paste: 是否直接贴图 :param is_paste: 是否直接贴图
""" """
current_width = 50 current_width = 50
current_height = 180 current_height = 180
max_width = simple_help_img_list[0].w max_width = simple_help_img_list[0].w
for i in range(len(simple_help_img_list)): for i in range(len(simple_help_img_list)):
try: try:
if is_paste and B: if is_paste and B:
B.paste(simple_help_img_list[i], (current_width, current_height), True) B.paste(simple_help_img_list[i], (current_width, current_height), True)
current_height += simple_help_img_list[i].h + 40 current_height += simple_help_img_list[i].h + 40
if current_height + simple_help_img_list[i + 1].h > B.h - 10: if current_height + simple_help_img_list[i + 1].h > B.h - 10:
current_height = 180 current_height = 180
current_width += max_width + 30 current_width += max_width + 30
max_width = 0 max_width = 0
elif simple_help_img_list[i].w > max_width: elif simple_help_img_list[i].w > max_width:
max_width = simple_help_img_list[i].w max_width = simple_help_img_list[i].w
except IndexError: except IndexError:
pass pass
if current_width > simple_help_img_list[0].w + 50: if current_width > simple_help_img_list[0].w + 50:
current_width += simple_help_img_list[-1].w current_width += simple_help_img_list[-1].w
return current_width, B return current_width, B
def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]: def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
""" """
获取功能的帮助信息 获取功能的帮助信息
:param msg: 功能cmd :param msg: 功能cmd
:param is_super: 是否为超级用户 :param is_super: 是否为超级用户
""" """
module = plugins2settings_manager.get_plugin_module(msg) module = plugins2settings_manager.get_plugin_module(msg)
if not module: if not module:
module = admin_manager.get_plugin_module(msg) module = admin_manager.get_plugin_module(msg)
if module: if module:
try: try:
plugin = nonebot.plugin.get_plugin(module) plugin = nonebot.plugin.get_plugin(module)
if plugin: if plugin:
if is_super: if is_super:
result = plugin.module.__getattribute__( result = plugin.module.__getattribute__(
"__plugin_superuser_usage__" "__plugin_superuser_usage__"
) )
else: else:
result = plugin.module.__getattribute__("__plugin_usage__") result = plugin.module.__getattribute__("__plugin_usage__")
if result: if result:
width = 0 width = 0
for x in result.split("\n"): for x in result.split("\n"):
_width = len(x) * 24 _width = len(x) * 24
width = width if width > _width else _width width = width if width > _width else _width
height = len(result.split("\n")) * 45 height = len(result.split("\n")) * 45
A = CreateImg(width, height, font_size=24) A = BuildImage(width, height, font_size=24)
bk = CreateImg( bk = BuildImage(
width, width,
height, height,
background=Path(IMAGE_PATH) / "background" / "1.png", background=IMAGE_PATH / "background" / "1.png",
) )
A.paste(bk, alpha=True) A.paste(bk, alpha=True)
A.text((int(width * 0.048), int(height * 0.21)), result) A.text((int(width * 0.048), int(height * 0.21)), result)
return A.pic2bs4() return A.pic2bs4()
except AttributeError: except AttributeError:
pass pass
return None return None
Regular → Executable
+36 -38
View File
@@ -1,38 +1,36 @@
from configs.config import Config from configs.config import Config
import nonebot
Config.add_plugin_config(
Config.add_plugin_config( "hook",
"hook", "CHECK_NOTICE_INFO_CD",
"CHECK_NOTICE_INFO_CD", 300,
300, name="基础hook配置",
name="基础hook配置", help_="群检测,个人权限检测等各种检测提示信息cd",
help_="群检测,个人权限检测等各种检测提示信息cd", default_value=300
default_value=300 )
)
Config.add_plugin_config(
Config.add_plugin_config( "hook",
"hook", "MALICIOUS_BAN_TIME",
"MALICIOUS_BAN_TIME", 30,
30, help_="恶意命令触发检测触发后ban的时长(分钟)",
help_="恶意命令触发检测触发后ban的时长(分钟)", default_value=30
default_value=30 )
)
Config.add_plugin_config(
Config.add_plugin_config( "hook",
"hook", "MALICIOUS_CHECK_TIME",
"MALICIOUS_CHECK_TIME", 5,
5, help_="恶意命令触发检测规定时间内(秒)",
help_="恶意命令触发检测规定时间内(秒)", default_value=5
default_value=5 )
)
Config.add_plugin_config(
Config.add_plugin_config( "hook",
"hook", "MALICIOUS_BAN_COUNT",
"MALICIOUS_BAN_COUNT", 6,
6, help_="恶意命令触发检测最大触发次数",
help_="恶意命令触发检测最大触发次数", default_value=6
default_value=6 )
)
nonebot.load_plugins("basic_plugins/hooks")
@@ -1,7 +1,11 @@
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent
from utils.manager import plugins2block_manager, StaticData from utils.manager import plugins2block_manager, StaticData
import time import time
ignore_rst_module = ["ai", "poke", "dialogue"]
other_limit_plugins = ["poke"]
class StatusMessageManager(StaticData): class StatusMessageManager(StaticData):
Regular → Executable
+386 -210
View File
@@ -1,210 +1,386 @@
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
from nonebot.adapters.cqhttp.exception import ActionFailed from nonebot.adapters.onebot.v11.exception import ActionFailed
from utils.manager import ( from models.friend_user import FriendUser
plugins2settings_manager, from models.group_member_info import GroupInfoUser
admin_manager, from models.bag_user import BagUser
group_manager, from utils.manager import (
plugins_manager, plugins2settings_manager,
) admin_manager,
from .utils import set_block_limit_false, status_message_manager group_manager,
from nonebot.typing import T_State plugins_manager,
from nonebot.adapters.cqhttp import ( plugins2cd_manager,
Bot, plugins2block_manager,
MessageEvent, plugins2count_manager,
GroupMessageEvent, )
PokeNotifyEvent, from ._utils import (
) set_block_limit_false,
from configs.config import Config status_message_manager,
from models.ban_user import BanUser ignore_rst_module,
from utils.utils import FreqLimiter other_limit_plugins,
from utils.message_builder import at )
from models.level_user import LevelUser from nonebot.typing import T_State
from typing import Optional
from nonebot.adapters.onebot.v11 import (
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) Bot,
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) MessageEvent,
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) GroupMessageEvent,
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) PokeNotifyEvent,
PrivateMessageEvent,
Message,
ignore_rst_module = ["ai", "poke", "dialogue"] Event,
)
from configs.config import Config
# 权限检测 from models.ban_user import BanUser
@run_preprocessor from utils.utils import FreqLimiter
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): from utils.message_builder import at
module = matcher.module from models.level_user import LevelUser
plugins2info_dict = plugins2settings_manager.get_data() import nonebot
if (
(not isinstance(event, MessageEvent) and module != "poke") _flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
or await BanUser.is_ban(event.user_id) _flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
and str(event.user_id) not in bot.config.superusers _flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
) or ( _flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
str(event.user_id) in bot.config.superusers
and plugins2info_dict.get(module)
and not plugins2info_dict[module]["limit_superuser"] # 权限检测
): @run_preprocessor
return async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
# 群黑名单检测 module = matcher.plugin_name
if isinstance(event, GroupMessageEvent): plugins2info_dict = plugins2settings_manager.get_data()
if group_manager.get_group_level(event.group_id) < 0: # 功能的金币检测 #######################################
raise IgnoredException("群黑名单") # 功能的金币检测 #######################################
if module in admin_manager.keys() and matcher.priority not in [1, 9]: # 功能的金币检测 #######################################
if isinstance(event, GroupMessageEvent): cost_gold = 0
# 个人权限 if isinstance(
if ( event, GroupMessageEvent
not await LevelUser.check_level( ) and plugins2settings_manager.get_plugin_data(module).get("cost_gold"):
event.user_id, cost_gold = plugins2settings_manager.get_plugin_data(module).get("cost_gold")
event.group_id, if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
admin_manager.get_plugin_level(module), await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
) raise IgnoredException(f"{module} 金币限制...")
and admin_manager.get_plugin_level(module) > 0 # 当插件不阻塞超级用户时,超级用户提前扣除金币
): if (
try: str(event.user_id) in bot.config.superusers
if _flmt.check(event.user_id): and not plugins2info_dict[module]["limit_superuser"]
_flmt.start_cd(event.user_id) ):
await bot.send_group_msg( await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
group_id=event.group_id, try:
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:" if (
f"{admin_manager.get_plugin_level(module)}", (not isinstance(event, MessageEvent) and module not in other_limit_plugins)
) or await BanUser.is_ban(event.user_id)
except ActionFailed: and str(event.user_id) not in bot.config.superusers
pass ) or (
set_block_limit_false(event, module) str(event.user_id) in bot.config.superusers
if event.is_tome(): and plugins2info_dict.get(module)
status_message_manager.add(event.group_id) and not plugins2info_dict[module]["limit_superuser"]
raise IgnoredException("权限不足") ):
else: return
if not await LevelUser.check_level( except AttributeError:
event.user_id, 0, admin_manager.get_plugin_level(module) pass
): # 超级用户命令
try: try:
await bot.send_private_msg( _plugin = nonebot.plugin.get_plugin(module)
user_id=event.user_id, _module = _plugin.module
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}", plugin_name = _module.__getattribute__("__zx_plugin_name__")
) if (
except ActionFailed: "[superuser]" in plugin_name.lower()
pass and str(event.user_id) in bot.config.superusers
set_block_limit_false(event, module) ):
if event.is_tome(): return
status_message_manager.add(event.user_id) except AttributeError:
raise IgnoredException("权限不足") pass
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]: # 群黑名单检测 群总开关检测
# 戳一戳单独判断 if isinstance(event, GroupMessageEvent) or matcher.plugin_name == other_limit_plugins:
if isinstance(event, GroupMessageEvent) or ( try:
isinstance(event, PokeNotifyEvent) and event.group_id if (
): group_manager.get_group_level(event.group_id) < 0
if status_message_manager.get(event.group_id) is None: and str(event.user_id) not in bot.config.superusers
status_message_manager.delete(event.group_id) ):
if plugins2info_dict[module]["level"] > group_manager.get_group_level( raise IgnoredException("群黑名单")
event.group_id if not group_manager.check_group_bot_status(event.group_id):
): try:
try: if str(event.get_message()) != "醒来":
if _flmt_g.check(event.user_id) and module not in ignore_rst_module: raise IgnoredException("功能总开关关闭状态")
_flmt_g.start_cd(event.user_id) except ValueError:
await bot.send_group_msg( raise IgnoredException("功能总开关关闭状态")
group_id=event.group_id, message="群权限不足..." except AttributeError:
) pass
except ActionFailed: if module in admin_manager.keys() and matcher.priority not in [1, 9]:
pass if isinstance(event, GroupMessageEvent):
if event.is_tome(): # 个人权限
status_message_manager.add(event.group_id) if (
set_block_limit_false(event, module) not await LevelUser.check_level(
raise IgnoredException("群权限不足") event.user_id,
# 插件状态 event.group_id,
if not group_manager.get_plugin_status(module, event.group_id): admin_manager.get_plugin_level(module),
try: )
if module not in ignore_rst_module and _flmt_s.check( and admin_manager.get_plugin_level(module) > 0
event.group_id ):
): try:
_flmt_s.start_cd(event.group_id) if _flmt.check(event.user_id):
await bot.send_group_msg( _flmt.start_cd(event.user_id)
group_id=event.group_id, message="该群未开启此功能.." await bot.send_group_msg(
) group_id=event.group_id,
except ActionFailed: message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
pass f"{admin_manager.get_plugin_level(module)}",
if event.is_tome(): )
status_message_manager.add(event.group_id) except ActionFailed:
set_block_limit_false(event, module) pass
raise IgnoredException("未开启此功能...") set_block_limit_false(event, module)
# 管理员禁用 if event.is_tome():
if not group_manager.get_plugin_status(f"{module}:super", event.group_id): status_message_manager.add(event.group_id)
try: raise IgnoredException("权限不足")
if ( else:
_flmt_s.check(event.group_id) if not await LevelUser.check_level(
and module not in ignore_rst_module event.user_id, 0, admin_manager.get_plugin_level(module)
): ):
_flmt_s.start_cd(event.group_id) try:
await bot.send_group_msg( await bot.send_private_msg(
group_id=event.group_id, message="管理员禁用了此群该功能..." user_id=event.user_id,
) message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}",
except ActionFailed: )
pass except ActionFailed:
if event.is_tome(): pass
status_message_manager.add(event.group_id) set_block_limit_false(event, module)
set_block_limit_false(event, module) if event.is_tome():
raise IgnoredException("管理员禁用了此群该功能...") status_message_manager.add(event.user_id)
# 群聊禁用 raise IgnoredException("权限不足")
if not plugins_manager.get_plugin_status(module, block_type="group"): if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
try: # 戳一戳单独判断
if ( if isinstance(event, GroupMessageEvent) or isinstance(event, PokeNotifyEvent) or matcher.plugin_name in other_limit_plugins:
_flmt_c.check(event.group_id) if status_message_manager.get(event.group_id) is None:
and module not in ignore_rst_module status_message_manager.delete(event.group_id)
): if plugins2info_dict[module]["level"] > group_manager.get_group_level(
_flmt_c.start_cd(event.group_id) event.group_id
await bot.send_group_msg( ):
group_id=event.group_id, message="该功能在群聊中已被禁用..." try:
) if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
except ActionFailed: _flmt_g.start_cd(event.user_id)
pass await bot.send_group_msg(
if event.is_tome(): group_id=event.group_id, message="群权限不足..."
status_message_manager.add(event.group_id) )
set_block_limit_false(event, module) except ActionFailed:
raise IgnoredException("该插件在群聊中已被禁用...") pass
else: if event.is_tome():
# 私聊禁用 status_message_manager.add(event.group_id)
if not plugins_manager.get_plugin_status(module, block_type="private"): set_block_limit_false(event, module)
try: raise IgnoredException("群权限不足")
if _flmt_c.check(event.user_id): # 插件状态
_flmt_c.start_cd(event.user_id) if not group_manager.get_plugin_status(module, event.group_id):
await bot.send_private_msg( try:
user_id=event.user_id, message="该功能在私聊中已被禁用..." if module not in ignore_rst_module and _flmt_s.check(
) event.group_id
except ActionFailed: ):
pass _flmt_s.start_cd(event.group_id)
if event.is_tome(): await bot.send_group_msg(
status_message_manager.add(event.user_id) group_id=event.group_id, message="该群未开启此功能.."
set_block_limit_false(event, module) )
raise IgnoredException("该插件在私聊中已被禁用...") except ActionFailed:
# 维护 pass
if not plugins_manager.get_plugin_status(module, block_type="all"): if event.is_tome():
if isinstance( status_message_manager.add(event.group_id)
event, GroupMessageEvent set_block_limit_false(event, module)
) and group_manager.check_group_is_white(event.group_id): raise IgnoredException("未开启此功能...")
return # 管理员禁用
try: if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
if isinstance(event, GroupMessageEvent): try:
if ( if (
_flmt_c.check(event.group_id) _flmt_s.check(event.group_id)
and module not in ignore_rst_module and module not in ignore_rst_module
): ):
_flmt_c.start_cd(event.group_id) _flmt_s.start_cd(event.group_id)
await bot.send_group_msg( await bot.send_group_msg(
group_id=event.group_id, message="此功能正在维护..." group_id=event.group_id, message="管理员禁用了此群该功能..."
) )
else: except ActionFailed:
await bot.send_private_msg( pass
user_id=event.user_id, message="此功能正在维护..." if event.is_tome():
) status_message_manager.add(event.group_id)
except ActionFailed: set_block_limit_false(event, module)
pass raise IgnoredException("管理员禁用了此群该功能...")
if event.is_tome(): # 群聊禁用
id_ = ( if not plugins_manager.get_plugin_status(module, block_type="group"):
event.group_id try:
if isinstance(event, GroupMessageEvent) if (
else event.user_id _flmt_c.check(event.group_id)
) and module not in ignore_rst_module
status_message_manager.add(id_) ):
set_block_limit_false(event, module) _flmt_c.start_cd(event.group_id)
raise IgnoredException("此功能正在维护...") await bot.send_group_msg(
group_id=event.group_id, message="该功能在群聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("该插件在群聊中已被禁用...")
else:
# 私聊禁用
if not plugins_manager.get_plugin_status(module, block_type="private"):
try:
if _flmt_c.check(event.user_id):
_flmt_c.start_cd(event.user_id)
await bot.send_private_msg(
user_id=event.user_id, message="该功能在私聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.user_id)
set_block_limit_false(event, module)
raise IgnoredException("该插件在私聊中已被禁用...")
# 维护
if not plugins_manager.get_plugin_status(module, block_type="all"):
if isinstance(
event, GroupMessageEvent
) and group_manager.check_group_is_white(event.group_id):
return
try:
if isinstance(event, GroupMessageEvent):
if (
_flmt_c.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="此功能正在维护..."
)
else:
await bot.send_private_msg(
user_id=event.user_id, message="此功能正在维护..."
)
except ActionFailed:
pass
if event.is_tome():
id_ = (
event.group_id
if isinstance(event, GroupMessageEvent)
else event.user_id
)
status_message_manager.add(id_)
set_block_limit_false(event, module)
raise IgnoredException("此功能正在维护...")
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# Cd
if plugins2cd_manager.check_plugin_cd_status(module):
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
check_type = plugin_cd_data["check_type"]
limit_type = plugin_cd_data["limit_type"]
rst = plugin_cd_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
):
cd_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
cd_type_ = event.group_id
if not plugins2cd_manager.check(module, cd_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} 正在cd中...")
else:
plugins2cd_manager.start_cd(module, cd_type_)
# Block
if plugins2block_manager.check_plugin_block_status(module):
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
check_type = plugin_block_data["check_type"]
limit_type = plugin_block_data["limit_type"]
rst = plugin_block_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or check_type == "all"
):
block_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
block_type_ = event.group_id
if plugins2block_manager.check(block_type_, module):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{event.user_id}正在调用{module}....")
else:
plugins2block_manager.set_true(block_type_, module)
# Count
if (
plugins2count_manager.check_plugin_count_status(module)
and event.user_id not in bot.config.superusers
):
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
limit_type = plugin_count_data["limit_type"]
rst = plugin_count_data["rst"]
count_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
count_type_ = event.group_id
if not plugins2count_manager.check(module, count_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} count次数限制...")
else:
plugins2count_manager.increase(module, count_type_)
# 功能花费的金币 #######################################
# 功能花费的金币 #######################################
if cost_gold:
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
"""
发送信息
:param rst: pass
:param bot: pass
:param event: pass
"""
rst = await init_rst(rst, event)
try:
if isinstance(event, GroupMessageEvent):
status_message_manager.add(event.group_id)
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
else:
status_message_manager.add(event.user_id)
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
except ActionFailed:
pass
# 解除命令block阻塞
@run_postprocessor
async def _(
matcher: Matcher,
exception: Optional[Exception],
bot: Bot,
event: Event,
state: T_State,
):
if not isinstance(event, MessageEvent) and matcher.plugin_name != "poke":
return
module = matcher.plugin_name
set_block_limit_false(event, module)
async def init_rst(rst: str, event: MessageEvent):
if "[uname]" in rst:
uname = event.sender.card or event.sender.nickname
rst = rst.replace("[uname]", uname)
if "[nickname]" in rst:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
rst = rst.replace("[nickname]", nickname)
if "[at]" in rst and isinstance(event, GroupMessageEvent):
rst = rst.replace("[at]", str(at(event.user_id)))
return rst
Regular → Executable
+94 -83
View File
@@ -1,83 +1,94 @@
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.cqhttp.exception import ActionFailed from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.adapters.cqhttp import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
MessageEvent, Event,
GroupMessageEvent, MessageEvent,
) PokeNotifyEvent,
from configs.config import Config GroupMessageEvent,
from models.ban_user import BanUser )
from utils.utils import is_number, static_flmt from configs.config import Config
from utils.message_builder import at from models.ban_user import BanUser
from utils.utils import is_number, static_flmt, FreqLimiter
from utils.message_builder import at
Config.add_plugin_config( from ._utils import ignore_rst_module, other_limit_plugins
"hook",
"BAN_RESULT",
"才不会给你发消息.", Config.add_plugin_config(
help_="对被ban用户发送的消息", "hook",
) "BAN_RESULT",
"才不会给你发消息.",
help_="对被ban用户发送的消息",
# 检查是否被ban )
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): _flmt = FreqLimiter(300)
try:
if (
await BanUser.is_super_ban(event.user_id) # 检查是否被ban
and str(event.user_id) not in bot.config.superusers @run_preprocessor
): async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
raise IgnoredException("用户处于超级黑名单中") if (
except AttributeError: (isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent))
pass and matcher.priority not in [1, 9]
if not isinstance(event, MessageEvent): ) or matcher.plugin_name in other_limit_plugins:
return try:
if matcher.type == "message" and matcher.priority not in [1, 9]: if (
if ( await BanUser.is_super_ban(event.user_id)
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 ):
): raise IgnoredException("用户处于超级黑名单中")
time = await BanUser.check_ban_time(event.user_id) except AttributeError:
if is_number(time): pass
time = abs(int(time)) if (
if time < 60: await BanUser.is_ban(event.user_id)
time = str(time) + " 秒" and str(event.user_id) not in bot.config.superusers
else: ):
time = str(int(time / 60)) + " 分钟" time = await BanUser.check_ban_time(event.user_id)
else: if is_number(time):
time = str(time) + " 分钟" time = abs(int(time))
if isinstance(event, GroupMessageEvent): if time < 60:
if not static_flmt.check(event.user_id): time = str(time) + " 秒"
raise IgnoredException("用户处于黑名单中") else:
static_flmt.start_cd(event.user_id) time = str(int(time / 60)) + " 分钟"
if matcher.priority != 9: else:
try: time = str(time) + " 分钟"
ban_result = Config.get_config("hook", "BAN_RESULT") if isinstance(event, GroupMessageEvent):
if ban_result: if not static_flmt.check(event.user_id):
await bot.send_group_msg( raise IgnoredException("用户处于黑名单中")
group_id=event.group_id, static_flmt.start_cd(event.user_id)
message=at(event.user_id) if matcher.priority != 9:
+ ban_result try:
+ f" 在..在 {time} 后才会理你喔", ban_result = Config.get_config("hook", "BAN_RESULT")
) if (
except ActionFailed: ban_result
pass and _flmt.check(event.user_id)
else: and matcher.plugin_name not in ignore_rst_module
if not static_flmt.check(event.user_id): ):
raise IgnoredException("用户处于黑名单中") _flmt.start_cd(event.user_id)
static_flmt.start_cd(event.user_id) await bot.send_group_msg(
if matcher.priority != 9: group_id=event.group_id,
try: message=at(event.user_id)
ban_result = Config.get_config("hook", "BAN_RESULT") + ban_result
if ban_result: + f" 在..在 {time} 后才会理你喔",
await bot.send_private_msg( )
user_id=event.user_id, except ActionFailed:
message=at(event.user_id) pass
+ ban_result else:
+ f" 在..在 {time}后才会理你喔", if not static_flmt.check(event.user_id):
) raise IgnoredException("用户处于黑名单中")
except ActionFailed: static_flmt.start_cd(event.user_id)
pass if matcher.priority != 9:
raise IgnoredException("用户处于黑名单中") try:
ban_result = Config.get_config("hook", "BAN_RESULT")
if ban_result and matcher.plugin_name not in ignore_rst_module:
await bot.send_private_msg(
user_id=event.user_id,
message=at(event.user_id)
+ ban_result
+ f" 在..在 {time}后才会理你喔",
)
except ActionFailed:
pass
raise IgnoredException("用户处于黑名单中")
+54 -54
View File
@@ -1,54 +1,54 @@
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.cqhttp.exception import ActionFailed from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.adapters.cqhttp import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
MessageEvent, MessageEvent,
GroupMessageEvent, GroupMessageEvent,
) )
from configs.config import Config from configs.config import Config
from models.ban_user import BanUser from models.ban_user import BanUser
from utils.utils import BanCheckLimiter from utils.utils import BanCheckLimiter
from utils.message_builder import at from utils.message_builder import at
from services.log import logger from services.log import logger
_blmt = BanCheckLimiter( _blmt = BanCheckLimiter(
Config.get_config("hook", "MALICIOUS_CHECK_TIME"), Config.get_config("hook", "MALICIOUS_CHECK_TIME"),
Config.get_config("hook", "MALICIOUS_BAN_COUNT"), Config.get_config("hook", "MALICIOUS_BAN_COUNT"),
) )
# 恶意触发命令检测 # 恶意触发命令检测
@run_preprocessor @run_preprocessor
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, 9]:
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(
event.user_id, event.user_id,
9, 9,
Config.get_config("hook", "MALICIOUS_BAN_TIME") * 60, Config.get_config("hook", "MALICIOUS_BAN_TIME") * 60,
): ):
logger.info(f"USER {event.user_id} 触发了恶意触发检测") logger.info(f"USER {event.user_id} 触发了恶意触发检测")
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
try: try:
await bot.send_group_msg( await bot.send_group_msg(
group_id=event.group_id, group_id=event.group_id,
message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟", message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
) )
except ActionFailed: except ActionFailed:
pass pass
else: else:
try: try:
await bot.send_private_msg( await bot.send_private_msg(
user_id=event.user_id, user_id=event.user_id,
message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟", message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
) )
except ActionFailed: except ActionFailed:
pass pass
raise IgnoredException("检测到恶意触发命令") raise IgnoredException("检测到恶意触发命令")
_blmt.add(f'{event.user_id}{state["_prefix"]["raw_command"]}') _blmt.add(f'{event.user_id}{state["_prefix"]["raw_command"]}')
-146
View File
@@ -1,146 +0,0 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
from nonebot.adapters.cqhttp.exception import ActionFailed
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from utils.message_builder import at
from .utils import status_message_manager, set_block_limit_false
from utils.manager import (
plugins2cd_manager,
plugins2block_manager,
plugins2count_manager,
)
from typing import Optional
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import (
Bot,
Event,
MessageEvent,
PrivateMessageEvent,
GroupMessageEvent,
Message,
)
# 命令cd | 命令阻塞 | 命令次数
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
if not isinstance(event, MessageEvent) and matcher.module != "poke":
return
module = matcher.module
if (
isinstance(event, GroupMessageEvent)
and status_message_manager.get(event.group_id) is None
):
status_message_manager.delete(event.group_id)
# Count
if (
plugins2count_manager.check_plugin_count_status(module)
and event.user_id not in bot.config.superusers
):
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
limit_type = plugin_count_data["limit_type"]
rst = plugin_count_data["rst"]
count_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
count_type_ = event.group_id
if not plugins2count_manager.check(module, count_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} count次数限制...")
else:
plugins2count_manager.increase(module, count_type_)
# Cd
if plugins2cd_manager.check_plugin_cd_status(module):
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
check_type = plugin_cd_data["check_type"]
limit_type = plugin_cd_data["limit_type"]
rst = plugin_cd_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
):
cd_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
cd_type_ = event.group_id
if not plugins2cd_manager.check(module, cd_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} 正在cd中...")
else:
plugins2cd_manager.start_cd(module, cd_type_)
# Block
if plugins2block_manager.check_plugin_block_status(module):
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
check_type = plugin_block_data["check_type"]
limit_type = plugin_block_data["limit_type"]
rst = plugin_block_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or check_type == "all"
):
block_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
block_type_ = event.group_id
if plugins2block_manager.check(block_type_, module):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{event.user_id}正在调用{module}....")
else:
plugins2block_manager.set_true(block_type_, module)
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
"""
发送信息
:param rst: pass
:param bot: pass
:param event: pass
"""
rst = await init_rst(rst, event)
try:
if isinstance(event, GroupMessageEvent):
status_message_manager.add(event.group_id)
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
else:
status_message_manager.add(event.user_id)
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
except ActionFailed:
pass
# 解除命令block阻塞
@run_postprocessor
async def _(
matcher: Matcher,
exception: Optional[Exception],
bot: Bot,
event: Event,
state: T_State,
):
if not isinstance(event, MessageEvent) and matcher.module != "poke":
return
module = matcher.module
set_block_limit_false(event, module)
async def init_rst(rst: str, event: MessageEvent):
if "[uname]" in rst:
uname = event.sender.card if event.sender.card else event.sender.nickname
rst = rst.replace("[uname]", uname)
if "[nickname]" in rst:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
rst = rst.replace("[nickname]", nickname)
if "[at]" in rst and isinstance(event, GroupMessageEvent):
rst = rst.replace("[at]", str(at(event.user_id)))
return rst
+51 -41
View File
@@ -1,41 +1,51 @@
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.typing import T_State from nonebot.typing import T_State
from .utils import status_message_manager from ._utils import status_message_manager
from nonebot.adapters.cqhttp import ( from utils.image_utils import text2image
Bot, from typing import Dict, Any
MessageEvent, from nonebot.adapters.onebot.v11 import (
PrivateMessageEvent, Bot,
GroupMessageEvent, MessageEvent,
) PrivateMessageEvent,
GroupMessageEvent,
)
# 为什么AI会自己和自己聊天 import re
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_State):
if not isinstance(event, MessageEvent): # 为什么AI会自己和自己聊天
return @run_preprocessor
if event.user_id == int(bot.self_id): async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_State):
raise IgnoredException("为什么AI会自己和自己聊天") if not isinstance(event, MessageEvent):
return
if event.user_id == int(bot.self_id):
# 有命令就别说话了 raise IgnoredException("为什么AI会自己和自己聊天")
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
if not isinstance(event, MessageEvent): # 有命令就别说话了
return @run_preprocessor
if matcher.type == "message" and matcher.module == "ai": async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
if ( if not isinstance(event, MessageEvent):
isinstance(event, GroupMessageEvent) return
and not status_message_manager.check(event.group_id) if matcher.type == "message" and matcher.plugin_name == "ai":
): if (
status_message_manager.delete(event.group_id) isinstance(event, GroupMessageEvent)
raise IgnoredException("有命令就别说话了") and not status_message_manager.check(event.group_id)
elif ( ):
isinstance(event, PrivateMessageEvent) status_message_manager.delete(event.group_id)
and not status_message_manager.check(event.user_id) raise IgnoredException("有命令就别说话了")
): elif (
print(status_message_manager) isinstance(event, PrivateMessageEvent)
status_message_manager.delete(event.user_id) and not status_message_manager.check(event.user_id)
raise IgnoredException("有命令就别说话了") ):
status_message_manager.delete(event.user_id)
raise IgnoredException("有命令就别说话了")
# @Bot.on_calling_api
# async def handle_api_call(bot: Bot, api: str, data: Dict[str, Any]):
# if api in ["send_msg", "send_group_msg", "send_private_msg"]:
# msg = str(data["message"])
# if (r := re.search("\[\[To_Img\|?(.*?)]]", msg)) or (r := re.search("&#91;&#91;To_Img\|?(.*?)&#91;&#91;")):
+47
View File
@@ -0,0 +1,47 @@
from nonebot.exception import MockApiException
from nonebot.adapters.onebot.v11 import Bot, Message
from utils.manager import group_manager
from typing import Dict, Any
import re
@Bot.on_calling_api
async def handle_api_call(bot: Bot, api: str, data: Dict[str, Any]):
r = None
if (
(
(api == "send_msg" and data["message_type"] == "group")
or api == "send_group_msg"
)
and (
(
r := re.search(
"^\[\[_task\|(.*)]]",
data["message"].strip()
if isinstance(data["message"], str)
else str(data["message"]["text"]).strip(),
)
)
or (
r := re.search(
"^&#91;&#91;_task\|(.*)&#93;&#93;",
data["message"].strip()
if isinstance(data["message"], str)
else str(data["message"]["text"]).strip(),
)
)
)
and r.group(1) in group_manager.get_task_data().keys()
):
task = r.group(1)
group_id = data["group_id"]
if group_manager.get_group_level(
group_id
) < 0 or not await group_manager.check_group_task_status(group_id, task):
raise MockApiException(f"被动技能 {task} 处于关闭状态...")
else:
msg = str(data["message"]).strip()
msg = msg.replace(f"&#91;&#91;_task|{task}&#93;&#93;", "").replace(
f"[[_task|{task}]]", ""
)
data["message"] = Message(msg)
+28 -28
View File
@@ -1,28 +1,28 @@
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.message import run_postprocessor from nonebot.message import run_postprocessor
from typing import Optional from typing import Optional
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, Event from nonebot.adapters.onebot.v11 import Bot, Event
from utils.manager import withdraw_message_manager from utils.manager import withdraw_message_manager
import asyncio import asyncio
# 消息撤回 # 消息撤回
@run_postprocessor @run_postprocessor
async def _( async def _(
matcher: Matcher, matcher: Matcher,
exception: Optional[Exception], exception: Optional[Exception],
bot: Bot, bot: Bot,
event: Event, event: Event,
state: T_State, state: T_State,
): ):
tasks = [] tasks = []
for id_, time in withdraw_message_manager.data: for id_, time in withdraw_message_manager.data:
tasks.append(asyncio.ensure_future(_withdraw_message(bot, id_, time))) tasks.append(asyncio.ensure_future(_withdraw_message(bot, id_, time)))
withdraw_message_manager.remove((id_, time)) withdraw_message_manager.remove((id_, time))
await asyncio.gather(*tasks) await asyncio.gather(*tasks)
async def _withdraw_message(bot: Bot, id_: int, time: int): async def _withdraw_message(bot: Bot, id_: int, time: int):
await asyncio.sleep(time) await asyncio.sleep(time)
await bot.delete_msg(message_id=id_, self_id=int(bot.self_id)) await bot.delete_msg(message_id=id_)
+10 -1
View File
@@ -9,10 +9,12 @@ from .init_plugins_limit import (
init_plugins_count_limit, init_plugins_count_limit,
init_plugins_cd_limit, init_plugins_cd_limit,
) )
from .init import init
from .check_plugin_status import check_plugin_status from .check_plugin_status import check_plugin_status
from nonebot.adapters.cqhttp import Bot from nonebot.adapters.onebot.v11 import Bot
from configs.path_config import DATA_PATH from configs.path_config import DATA_PATH
from services.log import logger from services.log import logger
from pathlib import Path
from nonebot import Driver from nonebot import Driver
import nonebot import nonebot
@@ -30,6 +32,11 @@ def _():
""" """
初始化数据 初始化数据
""" """
_flag = False
config_file = DATA_PATH / "configs" / "plugins2config.yaml"
if not config_file.exists():
_flag = True
init()
init_plugins_settings(DATA_PATH) init_plugins_settings(DATA_PATH)
init_plugins_cd_limit(DATA_PATH) init_plugins_cd_limit(DATA_PATH)
init_plugins_block_limit(DATA_PATH) init_plugins_block_limit(DATA_PATH)
@@ -42,6 +49,8 @@ def _():
if x: if x:
for key in x.keys(): for key in x.keys():
plugins_manager.block_plugin(key, block_type=x[key]) plugins_manager.block_plugin(key, block_type=x[key])
if _flag:
raise Exception("首次运行,已在configs目录下生成配置文件config.yaml,修改后重启即可...")
logger.info("初始化数据完成...") logger.info("初始化数据完成...")
+18 -18
View File
@@ -1,18 +1,18 @@
from utils.manager import plugins_manager from utils.manager import plugins_manager
from nonebot.adapters.cqhttp import Bot from nonebot.adapters.onebot.v11 import Bot
async def check_plugin_status(bot: Bot): async def check_plugin_status(bot: Bot):
""" """
遍历查看插件加载情况 遍历查看插件加载情况
""" """
rst = "" rst = ""
for plugin in plugins_manager.keys(): for plugin in plugins_manager.keys():
data = plugins_manager.get(plugin) data = plugins_manager.get(plugin)
if data.get("error") or data.get("error") is None: if data.get("error") or data.get("error") is None:
rst += f'{plugin}:{data["plugin_name"]}\n' rst += f'{plugin}:{data["plugin_name"]}\n'
if rst: if rst:
rst = "以下插件加载失败..\n" + rst rst = "以下插件加载失败..\n" + rst
await bot.send_private_msg( await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]), message=rst[:-1] user_id=int(list(bot.config.superusers)[0]), message=rst[:-1]
) )
+14
View File
@@ -0,0 +1,14 @@
from utils.manager import plugins2settings_manager
def init():
if plugins2settings_manager.get("update_pic"):
plugins2settings_manager["update_picture"] = plugins2settings_manager["update_pic"]
plugins2settings_manager.delete("update_pic")
if plugins2settings_manager.get("white2black_img"):
plugins2settings_manager["white2black_image"] = plugins2settings_manager["white2black_img"]
plugins2settings_manager.delete("white2black_img")
if plugins2settings_manager.get("send_img"):
plugins2settings_manager["send_image"] = plugins2settings_manager["send_img"]
plugins2settings_manager.delete("send_img")
+73 -73
View File
@@ -1,73 +1,73 @@
from pathlib import Path from pathlib import Path
from utils.manager import group_manager from utils.manager import group_manager
from services.db_context import db from services.db_context import db
from asyncpg.exceptions import DuplicateColumnError from asyncpg.exceptions import DuplicateColumnError
from services.log import logger from services.log import logger
try: try:
import ujson as json import ujson as json
except ModuleNotFoundError: except ModuleNotFoundError:
import json import json
try: try:
from models.group_remind import GroupRemind from models.group_remind import GroupRemind
except ModuleNotFoundError: except ModuleNotFoundError:
pass pass
async def init_group_manager(): async def init_group_manager():
""" """
旧数据格式替换为新格式 旧数据格式替换为新格式
初始化数据 初始化数据
""" """
old_group_level_file = Path() / "data" / "manager" / "group_level.json" old_group_level_file = Path() / "data" / "manager" / "group_level.json"
old_plugin_list_file = Path() / "data" / "manager" / "plugin_list.json" old_plugin_list_file = Path() / "data" / "manager" / "plugin_list.json"
if old_group_level_file.exists(): if old_group_level_file.exists():
data = json.load(open(old_group_level_file, "r", encoding="utf8")) data = json.load(open(old_group_level_file, "r", encoding="utf8"))
for key in data.keys(): for key in data.keys():
group = key group = key
level = data[key] level = data[key]
group_manager.set_group_level(group, level) group_manager.set_group_level(group, level)
old_group_level_file.unlink() old_group_level_file.unlink()
group_manager.save() group_manager.save()
if old_plugin_list_file.exists(): if old_plugin_list_file.exists():
data = json.load(open(old_plugin_list_file, "r", encoding="utf8")) data = json.load(open(old_plugin_list_file, "r", encoding="utf8"))
for plugin in data.keys(): for plugin in data.keys():
for group in data[plugin].keys(): for group in data[plugin].keys():
if group == "default" and not data[plugin]["default"]: if group == "default" and not data[plugin]["default"]:
group_manager.block_plugin(plugin) group_manager.block_plugin(plugin)
elif not data[plugin][group]: elif not data[plugin][group]:
group_manager.block_plugin(plugin, group) group_manager.block_plugin(plugin, group)
old_plugin_list_file.unlink() old_plugin_list_file.unlink()
old_data_table = Path() / "models" / "group_remind.py" old_data_table = Path() / "models" / "group_remind.py"
try: try:
if old_data_table.exists(): if old_data_table.exists():
b = { b = {
"hy": "group_welcome", "hy": "group_welcome",
"kxcz": "open_case_reset_remind", "kxcz": "open_case_reset_remind",
"zwa": "zwa", "zwa": "zwa",
"blpar": "bilibili_parse", "blpar": "bilibili_parse",
"epic": "epic_free_game", "epic": "epic_free_game",
"pa": "pa", "pa": "pa",
"almanac": "genshin_alc", "almanac": "genshin_alc",
} }
for group in group_manager.get_data()["group_manager"]: for group in group_manager.get_data()["group_manager"]:
for remind in b: for remind in b:
try: try:
status = await GroupRemind.get_status(int(group), remind) status = await GroupRemind.get_status(int(group), remind)
if status is not None: if status is not None:
if status: if status:
await group_manager.open_group_task(group, b[remind]) await group_manager.open_group_task(group, b[remind])
logger.info(f"读取旧数据-->{group} 开启 {b[remind]}") logger.info(f"读取旧数据-->{group} 开启 {b[remind]}")
else: else:
await group_manager.close_group_task(group, b[remind]) await group_manager.close_group_task(group, b[remind])
logger.info(f"读取旧数据-->{group} 关闭 {b[remind]}") logger.info(f"读取旧数据-->{group} 关闭 {b[remind]}")
except Exception as e: except Exception as e:
pass pass
query = db.text("DROP TABLE group_reminds;") query = db.text("DROP TABLE group_reminds;")
await db.first(query) await db.first(query)
old_data_table.unlink() old_data_table.unlink()
logger.info("旧数据读取完毕,删除了舍弃表 group_reminds...") logger.info("旧数据读取完毕,删除了舍弃表 group_reminds...")
except (ModuleNotFoundError, DuplicateColumnError): except (ModuleNotFoundError, DuplicateColumnError):
pass pass
group_manager.save() group_manager.save()
+45 -45
View File
@@ -1,45 +1,45 @@
from utils.manager import ( from utils.manager import (
none_plugin_count_manager, none_plugin_count_manager,
plugins2count_manager, plugins2count_manager,
plugins2cd_manager, plugins2cd_manager,
plugins2settings_manager, plugins2settings_manager,
plugins2block_manager, plugins2block_manager,
plugins_manager, plugins_manager,
resources_manager resources_manager
) )
from services.log import logger from services.log import logger
from utils.utils import get_matchers from utils.utils import get_matchers
try: try:
import ujson as json import ujson as json
except ModuleNotFoundError: except ModuleNotFoundError:
import json import json
def init_none_plugin_count_manager(): def init_none_plugin_count_manager():
""" """
清除已删除插件数据 清除已删除插件数据
""" """
modules = [x.module for x in get_matchers()] modules = [x.module for x in get_matchers()]
for module in none_plugin_count_manager.keys(): for module in none_plugin_count_manager.keys():
if module not in modules: if module not in modules:
none_plugin_count_manager.add_count(module) none_plugin_count_manager.add_count(module)
else: else:
none_plugin_count_manager.reset(module) none_plugin_count_manager.reset(module)
if none_plugin_count_manager.check(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: try:
plugins2settings_manager.delete(module) plugins2settings_manager.delete(module)
plugins2count_manager.delete(module) plugins2count_manager.delete(module)
plugins2cd_manager.delete(module) plugins2cd_manager.delete(module)
plugins2block_manager.delete(module) plugins2block_manager.delete(module)
plugins_manager.delete(module) plugins_manager.delete(module)
resources_manager.remove_resource(module) resources_manager.remove_resource(module)
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...") logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
except Exception as e: except Exception as e:
logger.error( logger.error(
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}" f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}"
) )
+153 -147
View File
@@ -1,147 +1,153 @@
from pathlib import Path from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML 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.utils import get_matchers from utils.utils import get_matchers
from ruamel import yaml from ruamel import yaml
import nonebot import nonebot
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
def init_plugins_config(data_path): def init_plugins_config(data_path):
""" """
初始化插件数据配置 初始化插件数据配置
""" """
plugins2config_file = Path(data_path) / "configs" / "plugins2config.yaml" plugins2config_file = data_path / "configs" / "plugins2config.yaml"
plugins2config_file.parent.mkdir(parents=True, exist_ok=True) plugins2config_file.parent.mkdir(parents=True, exist_ok=True)
_data = {} _data = {}
if plugins2config_file.exists(): if plugins2config_file.exists():
_data = _yaml.load(open(plugins2config_file, "r", encoding="utf8")) _data = _yaml.load(open(plugins2config_file, "r", encoding="utf8"))
_matchers = get_matchers() _matchers = get_matchers()
for matcher in _matchers: for matcher in _matchers:
_plugin = nonebot.plugin.get_plugin(matcher.module) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try: try:
_module = _plugin.module _module = _plugin.module
except AttributeError: except AttributeError:
continue continue
try: try:
plugin_version = _module.__getattribute__("__plugin_version__") plugin_version = _module.__getattribute__("__plugin_version__")
except AttributeError: except AttributeError:
plugin_version = None plugin_version = None
try: try:
plugin_configs = _module.__getattribute__("__plugin_configs__") plugin_configs = _module.__getattribute__("__plugin_configs__")
except AttributeError: except AttributeError:
continue continue
# 插件配置版本更新或为Version为None或不在存储配置内 # 插件配置版本更新或为Version为None或不在存储配置内
if ( if (
plugin_version is None plugin_version is None
or ( or (
_data.get(matcher.module) _data.get(matcher.plugin_name)
and _data[matcher.module].keys() != plugin_configs.keys() and _data[matcher.plugin_name].keys() != plugin_configs.keys()
) )
or plugin_version > plugins_manager.get(matcher.module)["version"] or plugin_version > plugins_manager.get(matcher.plugin_name)["version"]
or matcher.module not in _data.keys() or matcher.plugin_name not in _data.keys()
): ):
for key in plugin_configs: for key in plugin_configs:
if isinstance(plugin_configs[key], dict): if isinstance(plugin_configs[key], dict):
Config.add_plugin_config( Config.add_plugin_config(
matcher.module, matcher.plugin_name,
key, key,
plugin_configs[key].get("value"), plugin_configs[key].get("value"),
help_=plugin_configs[key].get("help"), help_=plugin_configs[key].get("help"),
default_value=plugin_configs[key].get("default_value"), default_value=plugin_configs[key].get("default_value"),
_override=True, _override=True,
) )
else: else:
Config.add_plugin_config(matcher.module, key, plugin_configs[key]) Config.add_plugin_config(matcher.plugin_name, key, plugin_configs[key])
else: else:
plugin_configs = _data[matcher.module] plugin_configs = _data[matcher.plugin_name]
for key in plugin_configs: for key in plugin_configs:
Config.add_plugin_config( Config.add_plugin_config(
matcher.module, matcher.plugin_name,
key, key,
plugin_configs[key]["value"], plugin_configs[key]["value"],
help_=plugin_configs[key]["help"], help_=plugin_configs[key]["help"],
default_value=plugin_configs[key]["default_value"], default_value=plugin_configs[key]["default_value"],
_override=True, _override=True,
) )
if not Config.is_empty(): if not Config.is_empty():
Config.save() Config.save()
_data = round_trip_load(open(plugins2config_file, encoding="utf8")) _data = round_trip_load(open(plugins2config_file, encoding="utf8"))
for plugin in _data.keys(): for plugin in _data.keys():
try: try:
plugin_name = plugins_manager.get(plugin)["plugin_name"] plugin_name = plugins_manager.get(plugin)["plugin_name"]
except (AttributeError, TypeError): except (AttributeError, TypeError):
plugin_name = plugin plugin_name = plugin
_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) admin_manager.set_admin_level(k, v)
# 存完插件基本设置 # 存完插件基本设置
with open(plugins2config_file, "w", encoding="utf8") as wf: with open(plugins2config_file, "w", encoding="utf8") as wf:
round_trip_dump( round_trip_dump(
_data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True _data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
) )
# 再开始读取用户配置 # 再开始读取用户配置
user_config_file = Path() / "configs" / "config.yaml" user_config_file = Path() / "configs" / "config.yaml"
_data = {} _data = {}
_tmp_data = {} _tmp_data = {}
if user_config_file.exists(): if user_config_file.exists():
with open(user_config_file, "r", encoding="utf8") as f: with open(user_config_file, "r", encoding="utf8") as f:
_data = _yaml.load(f) _data = _yaml.load(f)
for plugin in Config.keys(): # 数据替换
_tmp_data[plugin] = {} for plugin in Config.keys():
for k in Config[plugin].keys(): _tmp_data[plugin] = {}
if _data.get(plugin) and k in _data[plugin].keys(): for k in Config[plugin].keys():
Config.set_config(plugin, k, _data[plugin][k]) if _data.get(plugin) and k in _data[plugin].keys():
_tmp_data[plugin][k] = Config.get_config(plugin, k) Config.set_config(plugin, k, _data[plugin][k])
Config.save() if level2module := Config.get_level2module(plugin, k):
temp_file = Path() / "configs" / "temp_config.yaml" try:
try: admin_manager.set_admin_level(level2module, _data[plugin][k])
with open(temp_file, "w", encoding="utf8") as wf: except KeyError:
yaml.dump( logger.warning(f"{level2module} 设置权限等级失败:{_data[plugin][k]}")
_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True _tmp_data[plugin][k] = Config.get_config(plugin, k)
) Config.save()
with open(temp_file, "r", encoding="utf8") as rf: temp_file = Path() / "configs" / "temp_config.yaml"
_data = round_trip_load(rf) try:
# 添加注释 with open(temp_file, "w", encoding="utf8") as wf:
for plugin in _data.keys(): yaml.dump(
rst = "" _tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
plugin_name = None )
try: with open(temp_file, "r", encoding="utf8") as rf:
plugin_data = Config.get(plugin) _data = round_trip_load(rf)
for x in list(Config.get(plugin).keys()): # 添加注释
try: for plugin in _data.keys():
_x = plugin_data[x].get("name") rst = ""
if _x: plugin_name = None
plugin_name = _x try:
except AttributeError: plugin_data = Config.get(plugin)
pass for x in list(Config.get(plugin).keys()):
except (KeyError, AttributeError): try:
plugin_name = None _x = plugin_data[x].get("name")
if not plugin_name: if _x:
try: plugin_name = _x
plugin_name = plugins_manager.get(plugin)["plugin_name"] except AttributeError:
except (AttributeError, TypeError): pass
plugin_name = plugin except (KeyError, AttributeError):
plugin_name = ( plugin_name = None
plugin_name.replace("[Hidden]", "") if not plugin_name:
.replace("[Superuser]", "") try:
.replace("[Admin]", "") plugin_name = plugins_manager.get(plugin)["plugin_name"]
.strip() except (AttributeError, TypeError):
) plugin_name = plugin
rst += plugin_name + "\n" plugin_name = (
for k in _data[plugin].keys(): plugin_name.replace("[Hidden]", "")
rst += f'{k}: {Config[plugin][k]["help"]}' + "\n" .replace("[Superuser]", "")
_data[plugin].yaml_set_start_comment(rst[:-1], indent=2) .replace("[Admin]", "")
with open(Path() / "configs" / "config.yaml", "w", encoding="utf8") as wf: .strip()
round_trip_dump( )
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True rst += plugin_name + "\n"
) for k in _data[plugin].keys():
except Exception as e: rst += f'{k}: {Config[plugin][k]["help"]}' + "\n"
logger.error(f"生成简易配置注释错误 {type(e)}:{e}") _data[plugin].yaml_set_start_comment(rst[:-1], indent=2)
if temp_file.exists(): with open(Path() / "configs" / "config.yaml", "w", encoding="utf8") as wf:
temp_file.unlink() round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
except Exception as e:
logger.error(f"生成简易配置注释错误 {type(e)}:{e}")
if temp_file.exists():
temp_file.unlink()
+82 -82
View File
@@ -1,82 +1,82 @@
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel.yaml import YAML
from utils.manager import plugins_manager from utils.manager import plugins_manager
from utils.utils import get_matchers from utils.utils import get_matchers
import nonebot import nonebot
try: try:
import ujson as json import ujson as json
except ModuleNotFoundError: except ModuleNotFoundError:
import json import json
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
def init_plugins_data(data_path): def init_plugins_data(data_path):
""" """
初始化插件数据信息 初始化插件数据信息
""" """
plugin2data_file = Path(data_path) / "manager" / "plugin_manager.json" plugin2data_file = data_path / "manager" / "plugin_manager.json"
plugin2data_file.parent.mkdir(parents=True, exist_ok=True) plugin2data_file.parent.mkdir(parents=True, exist_ok=True)
_data = {} _data = {}
if plugin2data_file.exists(): if plugin2data_file.exists():
_data = json.load(open(plugin2data_file, "r", encoding="utf8")) _data = json.load(open(plugin2data_file, "r", encoding="utf8"))
_matchers = get_matchers() _matchers = get_matchers()
for matcher in _matchers: for matcher in _matchers:
_plugin = nonebot.plugin.get_plugin(matcher.module) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try: try:
_module = _plugin.module _module = _plugin.module
except AttributeError: except AttributeError:
if matcher.module not in _data.keys(): if matcher.plugin_name not in _data.keys():
plugins_manager.add_plugin_data( plugins_manager.add_plugin_data(
matcher.module, matcher.module, error=True matcher.plugin_name, matcher.plugin_name, error=True
) )
else: else:
plugins_manager.set_module_data(matcher.module, "error", True) plugins_manager.set_module_data(matcher.plugin_name, "error", True)
plugin_data = plugins_manager.get(matcher.module) plugin_data = plugins_manager.get(matcher.plugin_name)
if plugin_data: if plugin_data:
plugins_manager.set_module_data( plugins_manager.set_module_data(
matcher.module, "version", plugin_data.get("version") matcher.plugin_name, "version", plugin_data.get("version")
) )
else: else:
try: try:
plugin_version = _module.__getattribute__("__plugin_version__") plugin_version = _module.__getattribute__("__plugin_version__")
except AttributeError: except AttributeError:
plugin_version = None plugin_version = None
try: try:
plugin_name = _module.__getattribute__("__zx_plugin_name__") plugin_name = _module.__getattribute__("__zx_plugin_name__")
except AttributeError: except AttributeError:
plugin_name = matcher.module plugin_name = matcher.plugin_name
try: try:
plugin_author = _module.__getattribute__("__plugin_author__") plugin_author = _module.__getattribute__("__plugin_author__")
except AttributeError: except AttributeError:
plugin_author = None plugin_author = None
if matcher.module in plugins_manager.keys(): if matcher.plugin_name in plugins_manager.keys():
plugins_manager.set_module_data(matcher.module, "error", False) plugins_manager.set_module_data(matcher.plugin_name, "error", False)
if matcher.module not in plugins_manager.keys(): if matcher.plugin_name not in plugins_manager.keys():
plugins_manager.add_plugin_data( plugins_manager.add_plugin_data(
matcher.module, matcher.plugin_name,
plugin_name=plugin_name, plugin_name=plugin_name,
author=plugin_author, author=plugin_author,
version=plugin_version, version=plugin_version,
) )
elif plugins_manager[matcher.module]["version"] is None or ( elif plugins_manager[matcher.plugin_name]["version"] is None or (
plugin_version is not None plugin_version is not None
and plugin_version > plugins_manager[matcher.module]["version"] and plugin_version > plugins_manager[matcher.plugin_name]["version"]
): ):
plugins_manager.set_module_data( plugins_manager.set_module_data(
matcher.module, "plugin_name", plugin_name matcher.plugin_name, "plugin_name", plugin_name
) )
plugins_manager.set_module_data(matcher.module, "author", plugin_author) plugins_manager.set_module_data(matcher.plugin_name, "author", plugin_author)
plugins_manager.set_module_data( plugins_manager.set_module_data(
matcher.module, "version", plugin_version matcher.plugin_name, "version", plugin_version
) )
if matcher.module in _data.keys(): if matcher.plugin_name in _data.keys():
plugins_manager.set_module_data( plugins_manager.set_module_data(
matcher.module, "error", _data[matcher.module]["error"] matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
) )
plugins_manager.set_module_data( plugins_manager.set_module_data(
matcher.module, "plugin_name", _data[matcher.module]["plugin_name"] matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
) )
plugins_manager.save() plugins_manager.save()
+157 -157
View File
@@ -1,157 +1,157 @@
from pathlib import Path from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import ( from utils.manager import (
plugins2cd_manager, plugins2cd_manager,
plugins2block_manager, plugins2block_manager,
plugins2count_manager, plugins2count_manager,
) )
from utils.utils import get_matchers from utils.utils import get_matchers
from ruamel import yaml from ruamel import yaml
import nonebot import nonebot
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
def init_plugins_cd_limit(data_path): def init_plugins_cd_limit(data_path):
""" """
加载 cd 限制 加载 cd 限制
""" """
plugins2cd_file = Path(data_path) / "configs" / "plugins2cd.yaml" plugins2cd_file = data_path / "configs" / "plugins2cd.yaml"
plugins2cd_file.parent.mkdir(exist_ok=True, parents=True) plugins2cd_file.parent.mkdir(exist_ok=True, parents=True)
_data = {} _data = {}
_matchers = get_matchers() _matchers = get_matchers()
for matcher in _matchers: for matcher in _matchers:
if not plugins2cd_manager.get_plugin_cd_data(matcher.module): if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.module) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try: try:
_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.module, data_dict=plugin_cd_limit matcher.plugin_name, data_dict=plugin_cd_limit
) )
except AttributeError: except AttributeError:
pass pass
if not plugins2cd_manager.keys(): if not plugins2cd_manager.keys():
plugins2cd_manager.add_cd_limit( plugins2cd_manager.add_cd_limit(
"这是一个示例" "这是一个示例"
) )
_tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()} _tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()}
with open(plugins2cd_file, "w", encoding="utf8") as wf: with open(plugins2cd_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True) yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2cd_file, encoding="utf8")) _data = round_trip_load(open(plugins2cd_file, encoding="utf8"))
_data["PluginCdLimit"].yaml_set_start_comment( _data["PluginCdLimit"].yaml_set_start_comment(
"""# 需要cd的功能 """# 需要cd的功能
# 自定义的功能需要cd也可以在此配置 # 自定义的功能需要cd也可以在此配置
# key:模块名称 # key:模块名称
# cd:cd 时长(秒) # cd:cd 时长(秒)
# status:此限制的开关状态 # status:此限制的开关状态
# check_type:'private'/'group'/'all',限制私聊/群聊/全部 # check_type:'private'/'group'/'all',限制私聊/群聊/全部
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id # limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次 # 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称 # rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复 # rst 为 "" 或 None 时则不回复
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]" # rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批" # rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""", # 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2, indent=2,
) )
with open(plugins2cd_file, "w", encoding="utf8") as wf: with open(plugins2cd_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True) round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2cd_manager.reload_cd_limit() plugins2cd_manager.reload_cd_limit()
def init_plugins_block_limit(data_path): def init_plugins_block_limit(data_path):
""" """
加载阻塞限制 加载阻塞限制
""" """
plugins2block_file = Path(data_path) / "configs" / "plugins2block.yaml" plugins2block_file = data_path / "configs" / "plugins2block.yaml"
plugins2block_file.parent.mkdir(exist_ok=True, parents=True) plugins2block_file.parent.mkdir(exist_ok=True, parents=True)
_data = {} _data = {}
_matchers = get_matchers() _matchers = get_matchers()
for matcher in _matchers: for matcher in _matchers:
if not plugins2block_manager.get_plugin_block_data(matcher.module): if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.module) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try: try:
_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.module, data_dict=plugin_block_limit matcher.plugin_name, data_dict=plugin_block_limit
) )
except AttributeError: except AttributeError:
pass pass
if not plugins2block_manager.keys(): if not plugins2block_manager.keys():
plugins2block_manager.add_block_limit( plugins2block_manager.add_block_limit(
"这是一个示例" "这是一个示例"
) )
_tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()} _tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()}
with open(plugins2block_file, "w", encoding="utf8") as wf: with open(plugins2block_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True) yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2block_file, encoding="utf8")) _data = round_trip_load(open(plugins2block_file, encoding="utf8"))
_data["PluginBlockLimit"].yaml_set_start_comment( _data["PluginBlockLimit"].yaml_set_start_comment(
"""# 用户调用阻塞 """# 用户调用阻塞
# 即 当用户调用此功能还未结束时 # 即 当用户调用此功能还未结束时
# 用发送消息阻止用户重复调用此命令直到该命令结束 # 用发送消息阻止用户重复调用此命令直到该命令结束
# key:模块名称 # key:模块名称
# status:此限制的开关状态 # status:此限制的开关状态
# check_type:'private'/'group'/'all',限制私聊/群聊/全部 # check_type:'private'/'group'/'all',限制私聊/群聊/全部
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id # limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
# 示例:'user':阻塞用户,'group':阻塞群聊 # 示例:'user':阻塞用户,'group':阻塞群聊
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称 # rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复 # rst 为 "" 或 None 时则不回复
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]" # rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批" # rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""", # 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2, indent=2,
) )
with open(plugins2block_file, "w", encoding="utf8") as wf: with open(plugins2block_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True) round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2block_manager.reload_block_limit() plugins2block_manager.reload_block_limit()
def init_plugins_count_limit(data_path): def init_plugins_count_limit(data_path):
""" """
加载次数限制 加载次数限制
""" """
plugins2count_file = Path(data_path) / "configs" / "plugins2count.yaml" plugins2count_file = data_path / "configs" / "plugins2count.yaml"
plugins2count_file.parent.mkdir(exist_ok=True, parents=True) plugins2count_file.parent.mkdir(exist_ok=True, parents=True)
_data = {} _data = {}
_matchers = get_matchers() _matchers = get_matchers()
for matcher in _matchers: for matcher in _matchers:
if not plugins2count_manager.get_plugin_count_data(matcher.module): if not plugins2count_manager.get_plugin_count_data(matcher.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.module) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try: try:
_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.module, data_dict=plugin_count_limit matcher.plugin_name, data_dict=plugin_count_limit
) )
except AttributeError: except AttributeError:
pass pass
if not plugins2count_manager.keys(): if not plugins2count_manager.keys():
plugins2count_manager.add_count_limit( plugins2count_manager.add_count_limit(
"这是一个示例" "这是一个示例"
) )
_tmp_data = {"PluginCountLimit": plugins2count_manager.get_data()} _tmp_data = {"PluginCountLimit": plugins2count_manager.get_data()}
with open(plugins2count_file, "w", encoding="utf8") as wf: with open(plugins2count_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True) yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2count_file, encoding="utf8")) _data = round_trip_load(open(plugins2count_file, encoding="utf8"))
_data["PluginCountLimit"].yaml_set_start_comment( _data["PluginCountLimit"].yaml_set_start_comment(
"""# 命令每日次数限制 """# 命令每日次数限制
# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置] # 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
# 每日调用直到 00:00 刷新 # 每日调用直到 00:00 刷新
# key:模块名称 # key:模块名称
# max_count: 每日调用上限 # max_count: 每日调用上限
# status:此限制的开关状态 # status:此限制的开关状态
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id # limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
# 示例:'user':用户上限,'group':群聊上限 # 示例:'user':用户上限,'group':群聊上限
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称 # rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复 # rst 为 "" 或 None 时则不回复
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]" # rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批" # rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""", # 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2, indent=2,
) )
with open(plugins2count_file, "w", encoding="utf8") as wf: with open(plugins2count_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True) round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2count_manager.reload_count_limit() plugins2count_manager.reload_count_limit()
+43 -43
View File
@@ -1,43 +1,43 @@
from utils.manager import resources_manager from utils.manager import resources_manager
from utils.utils import get_matchers from utils.utils import get_matchers
from services.log import logger from services.log import logger
from pathlib import Path from pathlib import Path
import nonebot import nonebot
def init_plugins_resources(): def init_plugins_resources():
""" """
资源文件路径的移动 资源文件路径的移动
""" """
_tmp = [] _tmp = []
for matcher in get_matchers(): for matcher in get_matchers():
if matcher.module not in _tmp: if matcher.plugin_name not in _tmp:
_tmp.append(matcher.module) _tmp.append(matcher.plugin_name)
_plugin = nonebot.plugin.get_plugin(matcher.module) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try: try:
_module = _plugin.module _module = _plugin.module
except AttributeError: except AttributeError:
logger.warning(f"插件 {matcher.module} 加载失败...,资源控制未加载...") logger.warning(f"插件 {matcher.plugin_name} 加载失败...,资源控制未加载...")
else: else:
try: try:
resources = _module.__getattribute__("__plugin_resources__") resources = _module.__getattribute__("__plugin_resources__")
except AttributeError: except AttributeError:
pass pass
else: else:
path = Path(_module.__getattribute__("__file__")).parent path = Path(_module.__getattribute__("__file__")).parent
for resource in resources.keys(): for resource in resources.keys():
resources_manager.add_resource(matcher.module, (path / resource).absolute(), resources[resource]) resources_manager.add_resource(matcher.plugin_name, path / resource, resources[resource])
resources_manager.save() resources_manager.save()
resources_manager.start_move() resources_manager.start_move()
+128 -130
View File
@@ -1,130 +1,128 @@
from pathlib import Path from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import plugins2settings_manager, admin_manager from utils.manager import plugins2settings_manager, admin_manager
from services.log import logger from services.log import logger
from utils.utils import get_matchers from utils.utils import get_matchers
from ruamel import yaml from ruamel import yaml
import nonebot import nonebot
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
def init_plugins_settings(data_path: str): def init_plugins_settings(data_path: str):
""" """
初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__ 初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
""" """
plugins2settings_file = Path(data_path) / "configs" / "plugins2settings.yaml" plugins2settings_file = data_path / "configs" / "plugins2settings.yaml"
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True) plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
_matchers = get_matchers() _matchers = get_matchers()
_data = {} _tmp_module = {}
if plugins2settings_file.exists(): _tmp = []
with open(plugins2settings_file, "r", encoding="utf8") as f: for x in plugins2settings_manager.keys():
_data = _yaml.load(f) try:
_data = _data["PluginSettings"] if _data else {} _plugin = nonebot.plugin.get_plugin(x)
_tmp_module = {} _module = _plugin.module
_tmp = [] plugin_name = _module.__getattribute__("__zx_plugin_name__")
for matcher in _matchers: _tmp_module[x] = plugin_name
if matcher.module in _data.keys(): except (KeyError, AttributeError) as e:
plugins2settings_manager.add_plugin_settings( logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
matcher.module, _tmp_module[x] = ""
plugin_type=_data[matcher.module]["plugin_type"], for matcher in _matchers:
data_dict=_data[matcher.module], if matcher.plugin_name not in plugins2settings_manager.keys():
) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
if _data[matcher.module]["cmd"]: try:
_tmp_module[matcher.module] = _data[matcher.module]["cmd"][0] _module = _plugin.module
else: except AttributeError:
_plugin = nonebot.plugin.get_plugin(matcher.module) logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
try: else:
_module = _plugin.module try:
except AttributeError: plugin_name = _module.__getattribute__("__zx_plugin_name__")
logger.warning(f"插件 {matcher.module} 加载失败...,插件控制未加载.") if "[admin]" in plugin_name.lower():
else: try:
try: admin_settings = _module.__getattribute__(
plugin_name = _module.__getattribute__("__zx_plugin_name__") "__plugin_settings__"
if "[admin]" in plugin_name.lower(): )
try: level = admin_settings["admin_level"]
admin_settings = _module.__getattribute__( cmd = admin_settings.get("cmd")
"__plugin_settings__" except (AttributeError, KeyError):
) level = 5
level = admin_settings["admin_level"] cmd = None
cmd = admin_settings.get("cmd") if level is None:
except (AttributeError, KeyError): level = 5
level = 5 admin_manager.add_admin_plugin_settings(
cmd = None matcher.plugin_name, cmd, level
if not level: )
level = 5 if (
admin_manager.add_admin_plugin_settings( "[hidden]" in plugin_name.lower()
matcher.module, cmd, level or "[admin]" in plugin_name.lower()
) or "[superuser]" in plugin_name.lower()
if ( or matcher.plugin_name in plugins2settings_manager.keys()
"[hidden]" in plugin_name.lower() ):
or "[admin]" in plugin_name.lower() continue
or "[superuser]" in plugin_name.lower() except AttributeError:
or matcher.module in plugins2settings_manager.keys() if matcher.plugin_name not in _tmp:
): logger.warning(
continue f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
except AttributeError: )
if matcher.module not in _tmp: else:
logger.warning( try:
f"获取插件 {matcher.module} __zx_plugin_name__ 失败...,插件控制未加载." _tmp_module[matcher.plugin_name] = plugin_name
) plugin_settings = _module.__getattribute__(
else: "__plugin_settings__"
try: )
_tmp_module[matcher.module] = plugin_name if plugin_settings.get('cost_gold') is None:
plugin_settings = _module.__getattribute__( plugin_settings['cost_gold'] = 0
"__plugin_settings__" if (
) plugin_settings.get("cmd") is not None
if ( and plugin_name not in plugin_settings["cmd"]
plugin_settings["cmd"] ):
and plugin_name not in plugin_settings["cmd"] plugin_settings["cmd"].append(plugin_name)
): if plugins2settings_manager.get(
plugin_settings["cmd"].append(plugin_name) matcher.plugin_name
if plugins2settings_manager.get( ) and plugins2settings_manager[matcher.plugin_name].get(
matcher.module "plugin_type"
) and plugins2settings_manager[matcher.module].get( ):
"plugin_type" plugin_type = tuple(
): plugins2settings_manager.get_plugin_data(
plugin_type = tuple( matcher.plugin_name
plugins2settings_manager.get_plugin_data( )["plugin_type"]
matcher.module )
)["plugin_type"] else:
) try:
else: plugin_type = _module.__getattribute__(
try: "__plugin_type__"
plugin_type = _module.__getattribute__( )
"__plugin_type__" except AttributeError:
) plugin_type = ("normal",)
except AttributeError: if plugin_settings and matcher.plugin_name:
plugin_type = ("normal",) plugins2settings_manager.add_plugin_settings(
if plugin_settings and matcher.module: matcher.plugin_name,
plugins2settings_manager.add_plugin_settings( plugin_type=plugin_type,
matcher.module, **plugin_settings,
plugin_type=plugin_type, )
data_dict=plugin_settings, except AttributeError:
) pass
except AttributeError: _tmp.append(matcher.plugin_name)
pass _tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
_tmp.append(matcher.module) with open(plugins2settings_file, "w", encoding="utf8") as wf:
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()} yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
with open(plugins2settings_file, "w", encoding="utf8") as wf: _data = round_trip_load(open(plugins2settings_file, encoding="utf8"))
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True) _data["PluginSettings"].yaml_set_start_comment(
_data = round_trip_load(open(plugins2settings_file, encoding="utf8")) """# 模块与对应命令和对应群权限
_data["PluginSettings"].yaml_set_start_comment( # 用于生成帮助图片 和 开关功能
"""# 模块与对应命令和对应群权限 # key:模块名称
# 用于生成帮助图片 和 开关功能 # level:需要的群等级
# key:模块名称 # default_status:加入群时功能的默认开关状态
# level:需要的群等级 # limit_superuser: 功能状态是否限制超级用户
# default_status:加入群时功能的默认开关状态 # cmd: 关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称
# limit_superuser: 功能状态是否限制超级用户 # plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1),1代表帮助命令列向排列,否则为横向排列""",
# cmd: 关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称 indent=2,
# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1),1代表帮助命令列向排列,否则为横向排列""", )
indent=2, for plugin in _data["PluginSettings"].keys():
) _data["PluginSettings"][plugin].yaml_set_start_comment(
for plugin in _data["PluginSettings"].keys(): f"{plugin}:{_tmp_module[plugin]}", indent=2
_data["PluginSettings"][plugin].yaml_set_start_comment( )
f"{plugin}:{_tmp_module[plugin]}", indent=2 with open(plugins2settings_file, "w", encoding="utf8") as wf:
) round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
with open(plugins2settings_file, "w", encoding="utf8") as wf: logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")
+149 -150
View File
@@ -1,150 +1,149 @@
from nonebot import on_request, on_message from nonebot import on_request, on_message
from nonebot.adapters.cqhttp import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
FriendRequestEvent, FriendRequestEvent,
GroupRequestEvent, GroupRequestEvent,
MessageEvent, MessageEvent,
) )
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.cqhttp.exception import ActionFailed 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
import asyncio import asyncio
import time import time
import re import re
__zx_plugin_name__ = "好友群聊处理请求 [Hidden]" __zx_plugin_name__ = "好友群聊处理请求 [Hidden]"
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = "HibiKier" __plugin_author__ = "HibiKier"
__plugin_configs__ = { __plugin_configs__ = {
"AUTO_ADD_FRIEND": {"value": False, "help": "是否自动同意好友添加", "default_value": False} "AUTO_ADD_FRIEND": {"value": False, "help": "是否自动同意好友添加", "default_value": False}
} }
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=5, block=False) x = on_message(priority=9, block=False)
exists_data = {"private": {}, "group": {}} exists_data = {"private": {}, "group": {}}
@friend_req.handle() @friend_req.handle()
async def _(bot: Bot, event: FriendRequestEvent, state: dict): async def _(bot: Bot, event: FriendRequestEvent):
print(event) global exists_data
global exists_data if exists_data["private"].get(event.user_id):
if exists_data["private"].get(event.user_id): if time.time() - exists_data["private"][event.user_id] < 60 * 5:
if time.time() - exists_data["private"][event.user_id] < 60 * 5: return
return exists_data["private"][event.user_id] = time.time()
exists_data["private"][event.user_id] = time.time() user = await bot.get_stranger_info(user_id=event.user_id)
user = await bot.get_stranger_info(user_id=event.user_id) nickname = user["nickname"]
nickname = user["nickname"] sex = user["sex"]
sex = user["sex"] age = str(user["age"])
age = str(user["age"]) comment = event.comment
comment = event.comment await bot.send_private_msg(
await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]),
user_id=int(list(bot.config.superusers)[0]), message=f"*****一份好友申请*****\n"
message=f"*****一份好友申请*****\n" f"昵称:{nickname}({event.user_id})\n"
f"昵称:{nickname}({event.user_id})\n" f"自动同意:{'√' if Config.get_config('invite_manager', 'AUTO_ADD_FRIEND') else '×'}\n"
f"自动同意:{'√' if Config.get_config('auto_invite', 'AUTO_ADD_FRIEND') else '×'}\n" f"日期:{str(datetime.now()).split('.')[0]}\n"
f"日期:{str(datetime.now()).split('.')[0]}\n" f"备注:{event.comment}",
f"备注:{event.comment}", )
) if Config.get_config("invite_manager", "AUTO_ADD_FRIEND"):
if Config.get_config("auto_invite", "AUTO_ADD_FRIEND"): await bot.set_friend_add_request(flag=event.flag, approve=True)
await bot.set_friend_add_request(flag=event.flag, approve=True) await FriendUser.add_friend_info(user["user_id"], user["nickname"])
await FriendUser.add_friend_info(user["user_id"], user["nickname"]) else:
else: requests_manager.add_request(
requests_manager.add_request( event.user_id,
event.user_id, "private",
"private", event.flag,
event.flag, nickname=nickname,
nickname=nickname, sex=sex,
sex=sex, age=age,
age=age, comment=comment,
comment=comment, )
)
@group_req.handle()
@group_req.handle() async def _(bot: Bot, event: GroupRequestEvent):
async def _(bot: Bot, event: GroupRequestEvent, state: dict): global exists_data
global exists_data if event.sub_type == "invite":
if event.sub_type == "invite": if str(event.user_id) in bot.config.superusers:
if str(event.user_id) in bot.config.superusers: try:
try: if await GroupInfo.get_group_info(event.group_id):
await bot.set_group_add_request( await GroupInfo.set_group_flag(event.group_id, 1)
flag=event.flag, sub_type="invite", approve=True else:
) group_info = await bot.get_group_info(group_id=event.group_id)
if await GroupInfo.get_group_info(event.group_id): await GroupInfo.add_group_info(
await GroupInfo.set_group_flag(event.group_id, 1) group_info["group_id"],
else: group_info["group_name"],
group_info = await bot.get_group_info(group_id=event.group_id) group_info["max_member_count"],
await GroupInfo.add_group_info( group_info["member_count"],
group_info["group_id"], 1,
group_info["group_name"], )
group_info["max_member_count"], await bot.set_group_add_request(
group_info["member_count"], flag=event.flag, sub_type="invite", approve=True
1, )
) except ActionFailed:
except ActionFailed: pass
pass else:
else: user = await bot.get_stranger_info(user_id=event.user_id)
user = await bot.get_stranger_info(user_id=event.user_id) sex = user["sex"]
sex = user["sex"] age = str(user["age"])
age = str(user["age"]) if exists_data["group"].get(f"{event.user_id}:{event.group_id}"):
if exists_data["group"].get(f"{event.user_id}:{event.group_id}"): if (
if ( time.time()
time.time() - exists_data["group"][f"{event.user_id}:{event.group_id}"]
- exists_data["group"][f"{event.user_id}:{event.group_id}"] < 60 * 5
< 60 * 5 ):
): return
return exists_data["group"][f"{event.user_id}:{event.group_id}"] = time.time()
exists_data["group"][f"{event.user_id}:{event.group_id}"] = time.time() nickname = await FriendUser.get_user_name(event.user_id)
nickname = await FriendUser.get_user_name(event.user_id) await bot.send_private_msg(
await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]),
user_id=int(list(bot.config.superusers)[0]), message=f"*****一份入群申请*****\n"
message=f"*****一份入群申请*****\n" f"申请人:{nickname}({event.user_id})\n"
f"申请人:{nickname}({event.user_id})\n" f"群聊:{event.group_id}\n"
f"群聊:{event.group_id}\n" f"邀请日期:{str(datetime.now()).split('.')[0]}",
f"邀请日期:{str(datetime.now()).split('.')[0]}", )
) await bot.send_private_msg(
await bot.send_private_msg( user_id=event.user_id,
user_id=event.user_id, message=f"想要邀请我偷偷入群嘛~已经提醒{NICKNAME}的管理员大人了\n"
message=f"想要邀请我偷偷入群嘛~已经提醒{NICKNAME}的管理员大人了\n" "请确保已经群主或群管理沟通过!\n"
"请确保已经群主或群管理沟通过!\n" "等待管理员处理吧!",
"等待管理员处理吧!", )
) requests_manager.add_request(
requests_manager.add_request( event.user_id,
event.user_id, "group",
"group", event.flag,
event.flag, invite_group=event.group_id,
invite_group=event.group_id, nickname=nickname,
nickname=nickname, sex=sex,
sex=sex, age=age,
age=age, )
)
@x.handle()
@x.handle() async def _(event: MessageEvent):
async def _(bot: Bot, event: MessageEvent, state: dict): await asyncio.sleep(0.1)
await asyncio.sleep(0.1) r = re.search(r'groupcode="(.*?)"', str(event.get_message()))
r = re.search(r'groupcode="(.*?)"', str(event.get_message())) if r:
if r: group_id = int(r.group(1))
group_id = int(r.group(1)) else:
else: return
return r = re.search(r'groupname="(.*?)"', str(event.get_message()))
r = re.search(r'groupname="(.*?)"', str(event.get_message())) if r:
if r: group_name = r.group(1)
group_name = r.group(1) else:
else: group_name = "None"
group_name = "None" requests_manager.set_group_name(group_name, group_id)
requests_manager.set_group_name(group_name, group_id)
@scheduler.scheduled_job(
@scheduler.scheduled_job( "interval",
"interval", minutes=5,
minutes=5, )
) async def _():
async def _(): global exists_data
global exists_data exists_data = {"private": {}, "group": {}}
exists_data = {"private": {}, "group": {}}
Regular → Executable
+200 -194
View File
@@ -1,194 +1,200 @@
from nonebot import on_command from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message
from nonebot.typing import T_State from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, PrivateMessageEvent from nonebot.typing import T_State
from nonebot.rule import to_me from nonebot.rule import to_me
from utils.utils import get_message_text from models.group_member_info import GroupInfoUser
from models.group_member_info import GroupInfoUser from models.friend_user import FriendUser
from models.friend_user import FriendUser from models.ban_user import BanUser
import random from services.log import logger
from models.ban_user import BanUser from configs.config import NICKNAME, Config
from services.log import logger from nonebot.params import CommandArg
from configs.config import NICKNAME import random
__zx_plugin_name__ = "昵称系统"
__zx_plugin_name__ = "昵称系统" __plugin_usage__ = f"""
__plugin_usage__ = f""" usage:
usage: 个人昵称系统,群聊 与 私聊 昵称相互独立
个人昵称系统,群聊 与 私聊 昵称相互独立 指令:
指令: 以后叫我 [昵称]
以后叫我 [昵称] {NICKNAME}我是谁
{NICKNAME}我是谁 """.strip()
""".strip() __plugin_des__ = "区区昵称,才不想叫呢!"
__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_configs__ = {
"BLACK_WORD": {
nickname = on_command( "value": ["爸", "爹", "爷"],
"nickname", "help": "昵称所屏蔽的关键词,会被替换为 *",
aliases={"以后叫我", "以后请叫我", "称呼我", "以后请称呼我", "以后称呼我", "叫我", "请叫我"}, "default_value": None
rule=to_me(), }
priority=5, }
block=True,
) nickname = on_command(
"nickname",
my_nickname = on_command( aliases={"以后叫我", "以后请叫我", "称呼我", "以后请称呼我", "以后称呼我", "叫我", "请叫我"},
"my_name", aliases={"我叫什么", "我是谁", "我的名字"}, rule=to_me(), priority=5, block=True rule=to_me(),
) priority=5,
block=True,
)
cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=True)
my_nickname = on_command(
"my_name", aliases={"我叫什么", "我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
@nickname.handle() )
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg = get_message_text(event.json())
if not msg: cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=True)
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
if len(msg) > 10:
await nickname.finish("昵称可不能超过10个字!", at_sender=True) @nickname.handle()
if await GroupInfoUser.set_group_member_nickname( async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
event.user_id, event.group_id, msg msg = arg.extract_plain_text().strip()
): if not msg:
if len(msg) < 5: await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
if random.random() < 0.5: if len(msg) > 10:
msg = "~".join(msg) await nickname.finish("昵称可不能超过10个字!", at_sender=True)
await nickname.send( if msg in bot.config.superusers:
random.choice( await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True)
[ _tmp = ""
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", black_word = Config.get_config("nickname", "BLACK_WORD")
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", for x in msg:
f"好突然,突然要叫你昵称什么的...{msg}..", _tmp += "*" if x in black_word else x
f"{NICKNAME}会好好记住的{msg}的,放心吧", msg = _tmp
f"好..好.,那窝以后就叫你{msg}了.", if isinstance(event, GroupMessageEvent):
] if await GroupInfoUser.set_group_member_nickname(
) event.user_id, event.group_id, msg
) ):
logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}") if len(msg) < 5:
else: if random.random() < 0.3:
await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True) msg = "~".join(msg)
logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败") await nickname.send(
random.choice(
[
@nickname.handle() f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
msg = get_message_text(event.json()) f"好突然,突然要叫你昵称什么的...{msg}..",
if not msg: f"{NICKNAME}会好好记住的{msg}的,放心吧",
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True) f"好..好.,那窝以后就叫你{msg}了.",
if len(msg) > 10: ]
await nickname.finish("不要超过10个字!", at_sender=True) )
if await FriendUser.set_friend_nickname(event.user_id, msg): )
await nickname.send( logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}")
random.choice( else:
[ await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True)
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败")
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", else:
f"好突然,突然要叫你昵称什么的...{msg}..", if await FriendUser.set_friend_nickname(event.user_id, msg):
f"{NICKNAME}会好好记住的{msg}的,放心吧", await nickname.send(
f"好..好.,那窝以后就叫你{msg}了.", random.choice(
] [
) f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
) f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
logger.info(f"USER {event.user_id} 设置昵称 {msg}") f"好突然,突然要叫你昵称什么的...{msg}..",
else: f"{NICKNAME}会好好记住的{msg}的,放心吧",
await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True) f"好..好.,那窝以后就叫你{msg}了.",
logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败") ]
)
)
@my_nickname.handle() logger.info(f"USER {event.user_id} 设置昵称 {msg}")
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): else:
try: await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True)
nickname_ = await GroupInfoUser.get_group_member_nickname( logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败")
event.user_id, event.group_id
)
except AttributeError: @my_nickname.handle()
nickname_ = "" async def _(event: GroupMessageEvent):
if nickname_: try:
await my_nickname.send( nickname_ = await GroupInfoUser.get_group_member_nickname(
random.choice( event.user_id, event.group_id
[ )
f"我肯定记得你啊,你是{nickname_}啊", except AttributeError:
f"我不会忘记你的,你也不要忘记我!{nickname_}", nickname_ = ""
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}", if nickname_:
f"嗯?你是失忆了嘛...{nickname_}..", await my_nickname.send(
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ", random.choice(
f"哎?{nickname_}..怎么了吗..突然这样问..", [
] f"我肯定记得你啊,你是{nickname_}啊",
) f"我不会忘记你的,你也不要忘记我!{nickname_}",
) f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
else: f"嗯?你是失忆了嘛...{nickname_}..",
nickname_ = event.sender.card if event.sender.card else event.sender.nickname f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
await my_nickname.send( f"哎?{nickname_}..怎么了吗..突然这样问..",
random.choice( ]
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"] )
).format(nickname_) )
) else:
nickname_ = event.sender.card or event.sender.nickname
await my_nickname.send(
@my_nickname.handle() random.choice(
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): ["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
nickname_ = await FriendUser.get_friend_nickname(event.user_id) ).format(nickname_)
if nickname_: )
await my_nickname.send(
random.choice(
[ @my_nickname.handle()
f"我肯定记得你啊,你是{nickname_}啊", async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
f"我不会忘记你的,你也不要忘记我!{nickname_}", nickname_ = await FriendUser.get_friend_nickname(event.user_id)
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}", if nickname_:
f"嗯?你是失忆了嘛...{nickname_}..", await my_nickname.send(
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ", random.choice(
f"哎?{nickname_}..怎么了吗..突然这样问..", [
] f"我肯定记得你啊,你是{nickname_}啊",
) f"我不会忘记你的,你也不要忘记我!{nickname_}",
) f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
else: f"嗯?你是失忆了嘛...{nickname_}..",
nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"] f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
await my_nickname.send( f"哎?{nickname_}..怎么了吗..突然这样问..",
random.choice( ]
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"] )
).format(nickname_) )
) else:
nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"]
await my_nickname.send(
@cancel_nickname.handle() random.choice(
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): ["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
nickname_ = await GroupInfoUser.get_group_member_nickname( ).format(nickname_)
event.user_id, event.group_id )
)
if nickname_:
await cancel_nickname.send( @cancel_nickname.handle()
random.choice( async def _(event: GroupMessageEvent):
[ nickname_ = await GroupInfoUser.get_group_member_nickname(
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}", event.user_id, event.group_id
f"窝知道了..{nickname_}..", )
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}", if nickname_:
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!", await cancel_nickname.send(
f"可..可恶!{nickname_}!太可恶了!呜", random.choice(
] [
) f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
) f"窝知道了..{nickname_}..",
await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "") f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
await BanUser.ban(event.user_id, 9, 60) f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
else: f"可..可恶!{nickname_}!太可恶了!呜",
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True) ]
)
)
@cancel_nickname.handle() await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "")
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): await BanUser.ban(event.user_id, 9, 60)
nickname_ = await FriendUser.get_friend_nickname(event.user_id) else:
if nickname_: await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
await cancel_nickname.send(
random.choice(
[ @cancel_nickname.handle()
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}", async def _(event: PrivateMessageEvent):
f"窝知道了..{nickname_}..", nickname_ = await FriendUser.get_friend_nickname(event.user_id)
f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}", if nickname_:
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!", await cancel_nickname.send(
f"可..可恶!{nickname_}!太可恶了!呜", random.choice(
] [
) f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
) f"窝知道了..{nickname_}..",
await FriendUser.get_user_name(event.user_id) f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
await BanUser.ban(event.user_id, 9, 60) f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
else: f"可..可恶!{nickname_}!太可恶了!呜",
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True) ]
)
)
await FriendUser.get_user_name(event.user_id)
await BanUser.ban(event.user_id, 9, 60)
else:
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
Regular → Executable
+211 -111
View File
@@ -1,111 +1,211 @@
from nonebot import Driver from asyncpg.exceptions import (
from services.db_context import db DuplicateColumnError,
from asyncpg.exceptions import DuplicateColumnError UndefinedColumnError,
from models.group_info import GroupInfo PostgresSyntaxError,
from nonebot.adapters.cqhttp import Bot )
from utils.user_agent import get_user_agent from nonebot import Driver
from services.log import logger from services.db_context import db
from configs.path_config import TEXT_PATH from models.group_info import GroupInfo
from asyncio.exceptions import TimeoutError from models.bag_user import BagUser
from pathlib import Path from nonebot.adapters.onebot.v11 import Bot
import aiohttp from services.log import logger
import nonebot from configs.path_config import TEXT_PATH
from asyncio.exceptions import TimeoutError
try: from typing import List
import ujson as json from utils.http_utils import AsyncHttpx
except ModuleNotFoundError: from utils.utils import scheduler
import json import nonebot
try:
driver: Driver = nonebot.get_driver() import ujson as json
except ModuleNotFoundError:
import json
@driver.on_startup
async def update_city():
""" driver: Driver = nonebot.get_driver()
部分插件需要中国省份城市
这里直接更新,避免插件内代码重复
:return: @driver.on_startup
""" async def update_city():
china_city = Path(TEXT_PATH) / "china_city.json" """
data = {} 部分插件需要中国省份城市
try: 这里直接更新,避免插件内代码重复
async with aiohttp.ClientSession(headers=get_user_agent()) as session: """
async with session.get( china_city = TEXT_PATH / "china_city.json"
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5 data = {}
) as res: if not china_city.exists():
provinces_data = json.loads(await res.text(encoding="utf8")) try:
for province in provinces_data.keys(): res = await AsyncHttpx.get(
data[provinces_data[province]] = [] "http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
async with session.get( )
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html", res.encoding = "utf8"
timeout=5, provinces_data = json.loads(res.text)
) as res: for province in provinces_data.keys():
city_data = json.loads(await res.text(encoding="utf8")) data[provinces_data[province]] = []
for city in city_data.keys(): res = await AsyncHttpx.get(
data[provinces_data[province]].append(city_data[city]) f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
with open(china_city, "w", encoding="utf8") as f: timeout=5,
json.dump(data, f, indent=4, ensure_ascii=False) )
logger.info("自动更新城市列表完成.....") res.encoding = "utf8"
except TimeoutError: city_data = json.loads(res.text)
logger.info("自动更新城市列表超时.....") for city in city_data.keys():
data[provinces_data[province]].append(city_data[city])
with open(china_city, "w", encoding="utf8") as f:
@driver.on_startup json.dump(data, f, indent=4, ensure_ascii=False)
async def _(): logger.info("自动更新城市列表完成.....")
""" except TimeoutError:
数据库表结构变换 logger.warning("自动更新城市列表超时.....")
""" except ValueError:
sql_str = [ logger.warning("自动城市列表失败.....")
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;" # group_info表添加一个group_flag except Exception as e:
] logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
for sql in sql_str:
try:
query = db.text(sql) @driver.on_startup
await db.first(query) async def _():
except DuplicateColumnError: """
pass 数据库表结构变换
"""
_flag = []
@driver.on_bot_connect sql_str = [
async def _(bot: Bot): (
""" "ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;",
版本某些需要的变换 "group_info",
""" ), # group_info表添加一个group_flag
# 清空不存在的群聊信息,并将已所有已存在的群聊group_flag设置为1(认证所有已存在的群) (
if not await GroupInfo.get_group_info(114514): "ALTER TABLE bag_users rename belonging_group To group_id;",
# 标识符,该功能只需执行一次 "bag_users",
await GroupInfo.add_group_info( ), # 将 bag_users 的 belonging_group 改为 group_id
114514, (
"114514", "ALTER TABLE group_info_users rename belonging_group To group_id;",
114514, "group_info_users",
114514, ),
1 (
) "ALTER TABLE sign_group_users rename belonging_group To group_id;",
group_list = await bot.get_group_list() "sign_group_users",
group_list = [g["group_id"] for g in group_list] ),
_gl = [x.group_id for x in await GroupInfo.get_all_group()] (
if 114514 in _gl: "ALTER TABLE open_cases_users rename belonging_group To group_id;",
_gl.remove(114514) "open_cases_users",
for group_id in _gl: ),
if group_id in group_list: (
if await GroupInfo.get_group_info(group_id): "ALTER TABLE bag_users ADD property json NOT NULL DEFAULT '{}';",
await GroupInfo.set_group_flag(group_id, 1) "bag_users",
else: ), # bag_users 新增字段 property 替代 props
group_info = await bot.get_group_info(group_id=group_id) (
await GroupInfo.add_group_info( "ALTER TABLE genshin ADD auto_sign_time timestamp with time zone;",
group_info["group_id"], "genshin"
group_info["group_name"], ), # 新增原神自动签到字段
group_info["max_member_count"], (
group_info["member_count"], "ALTER TABLE genshin ADD resin_remind boolean DEFAULT False;",
1 "genshin"
) ), # 新增原神自动签到字段
logger.info(f"已将群聊 {group_id} 添加认证...") (
else: "ALTER TABLE genshin ADD resin_recovery_time timestamp with time zone;",
await GroupInfo.delete_group_info(group_id) "genshin"
logger.info(f"移除不存在的群聊信息:{group_id}") ), # 新增原神自动签到字段
(
"ALTER TABLE genshin ADD bind_group Integer;",
"genshin"
), # 新增原神群号绑定字段
]
for sql in sql_str:
try:
flag = sql[1]
sql = sql[0]
query = db.text(sql)
await db.first(query)
logger.info(f"完成sql操作:{sql}")
_flag.append(flag)
except (DuplicateColumnError, UndefinedColumnError):
pass
except PostgresSyntaxError:
logger.error(f"语法错误:执行sql失败:{sql}")
# bag_user 将文本转为字典格式
await __database_script(_flag)
# 完成后
end_sql_str = [
# "ALTER TABLE bag_users DROP COLUMN props;" # 删除 bag_users 的 props 字段(还不到时候)
]
for sql in end_sql_str:
try:
query = db.text(sql)
await db.first(query)
logger.info(f"完成执行sql操作:{sql}")
except (DuplicateColumnError, UndefinedColumnError):
pass
except PostgresSyntaxError:
logger.error(f"语法错误:执行sql失败:{sql}")
# str2json_sql = ["alter table bag_users alter COLUMN props type json USING props::json;"] # 字段类型替换
# rename_sql = 'alter table {} rename {} to {};' # 字段更名
# for sql in str2json_sql:
# try:
# query = db.text(sql)
# await db.first(query)
# except DuplicateColumnError:
# pass
@driver.on_bot_connect
async def _(bot: Bot):
"""
版本某些需要的变换
"""
# 清空不存在的群聊信息,并将已所有已存在的群聊group_flag设置为1(认证所有已存在的群)
if not await GroupInfo.get_group_info(114514):
# 标识符,该功能只需执行一次
await GroupInfo.add_group_info(114514, "114514", 114514, 114514, 1)
group_list = await bot.get_group_list()
group_list = [g["group_id"] for g in group_list]
_gl = [x.group_id for x in await GroupInfo.get_all_group()]
if 114514 in _gl:
_gl.remove(114514)
for group_id in _gl:
if group_id in group_list:
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 1)
else:
group_info = await bot.get_group_info(group_id=group_id)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
logger.info(f"已将群聊 {group_id} 添加认证...")
else:
await GroupInfo.delete_group_info(group_id)
logger.info(f"移除不存在的群聊信息:{group_id}")
async def __database_script(_flag: List[str]):
# bag_user 将文本转为字典格式
if "bag_users" in _flag:
for x in await BagUser.get_all_users():
props = {}
if x.props:
for prop in [p for p in x.props.split(",") if p]:
if props.get(prop):
props[prop] += 1
else:
props[prop] = 1
logger.info(
f"__database_script USER {x.user_qq} GROUP {x.group_id} 更新数据 {props}"
)
await x.update(
property=props,
props="",
).apply()
# 自动更新城市列表
@scheduler.scheduled_job(
"cron",
hour=6,
minute=1,
)
async def _():
await update_city()
@@ -11,4 +11,4 @@ Config.add_plugin_config(
) )
nonebot.load_plugins("plugins/shop") nonebot.load_plugins("basic_plugins/shop")
@@ -1,89 +1,94 @@
from nonebot import on_command from nonebot import on_command
from services.log import logger from services.log import logger
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.typing import T_State from nonebot.params import CommandArg
from utils.utils import get_message_text, is_number from utils.utils import is_number
from models.bag_user import BagUser from models.bag_user import BagUser
from services.db_context import db from services.db_context import db
from nonebot.adapters.cqhttp.permission import GROUP from nonebot.adapters.onebot.v11.permission import GROUP
from .models.goods_info import GoodsInfo from models.goods_info import GoodsInfo
import time
__zx_plugin_name__ = "商店 - 购买道具"
__plugin_usage__ = """ __zx_plugin_name__ = "商店 - 购买道具"
usage: __plugin_usage__ = """
购买道具 usage:
指令: 购买道具
购买 [序号或名称] ?[数量=1] 指令:
示例:购买 好感双倍加持卡Ⅰ 购买 [序号或名称] ?[数量=1]
示例:购买 1 4 示例:购买 好感双倍加持卡Ⅰ
""".strip() 示例:购买 1 4
__plugin_des__ = "商店 - 购买道具" """.strip()
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"] __plugin_des__ = "商店 - 购买道具"
__plugin_type__ = ('商店',) __plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
__plugin_version__ = 0.1 __plugin_type__ = ("商店",)
__plugin_author__ = "HibiKier" __plugin_version__ = 0.1
__plugin_settings__ = { __plugin_author__ = "HibiKier"
"level": 5, __plugin_settings__ = {
"default_status": True, "level": 5,
"limit_superuser": False, "default_status": True,
"cmd": ["商店", "购买道具"], "limit_superuser": False,
} "cmd": ["商店", "购买道具"],
}
__plugin_cd_limit__ = {"cd": 3}
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
@buy.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if get_message_text(event.json()) in ["神秘药水"]: @buy.handle()
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True) async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
goods_lst = await GoodsInfo.get_all_goods() goods = None
goods_name_lst = [x.goods_name for x in goods_lst] if arg.extract_plain_text().strip() in ["神秘药水"]:
msg = get_message_text(event.json()).strip().split(" ") await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
num = 1 goods_list = [
if len(msg) > 1: x
if is_number(msg[1]): for x in await GoodsInfo.get_all_goods()
num = int(msg[1]) if x.goods_limit_time > time.time() or x.goods_limit_time == 0
else: ]
await buy.finish("购买的数量要是数字!", at_sender=True) goods_name_list = [
# print(msg, num) x.goods_name
if is_number(msg[0]): for x in goods_list
msg = int(msg[0]) ]
if msg > len(goods_lst) or msg < 1: msg = arg.extract_plain_text().strip().split()
await buy.finish("请输入正确的商品id!", at_sender=True) num = 1
goods = goods_lst[msg - 1] if len(msg) > 1:
else: if is_number(msg[1]) and int(msg[1]) > 0:
if msg[0] in goods_name_lst: num = int(msg[1])
for i in range(len(goods_name_lst)): else:
if msg[0] == goods_name_lst[i]: await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
goods = goods_lst[i] if is_number(msg[0]):
break msg = int(msg[0])
else: if msg > len(goods_name_list) or msg < 1:
await buy.finish("请输入正确的商品名称!") await buy.finish("请输入正确的商品id!", at_sender=True)
else: goods = goods_list[msg - 1]
await buy.finish("请输入正确的商品名称!", at_sender=True) else:
async with db.transaction(): if msg[0] in goods_name_list:
if ( for i in range(len(goods_name_list)):
await BagUser.get_gold(event.user_id, event.group_id) if msg[0] == goods_name_list[i]:
) < goods.goods_price * num: goods = goods_list[i]
await buy.finish("您的金币好像不太够哦", at_sender=True) break
if await BagUser.spend_gold( else:
event.user_id, event.group_id, goods.goods_price * num await buy.finish("请输入正确的商品名称!")
): else:
for _ in range(num): await buy.finish("请输入正确的商品名称!", at_sender=True)
await BagUser.add_props(event.user_id, event.group_id, goods.goods_name) async with db.transaction():
await buy.send( if (
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!", await BagUser.get_gold(event.user_id, event.group_id)
at_sender=True, ) < goods.goods_price * num * goods.goods_discount:
) await buy.finish("您的金币好像不太够哦", at_sender=True)
logger.info( if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
f"USER {event.user_id} GROUP {event.group_id} " await buy.send(
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!" f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
) at_sender=True,
else: )
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True) logger.info(
logger.info( f"USER {event.user_id} GROUP {event.group_id} "
f"USER {event.user_id} GROUP {event.group_id} " f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 失败!" )
) else:
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} "
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 失败!"
)
@@ -1,11 +1,11 @@
from nonebot import on_command from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.typing import T_State from nonebot.params import CommandArg
from nonebot.adapters.cqhttp.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.message_builder import image from utils.message_builder import image
from utils.utils import get_message_text, is_number from utils.utils import is_number
__zx_plugin_name__ = "商店 - 我的金币" __zx_plugin_name__ = "商店 - 我的金币"
__plugin_usage__ = """ __plugin_usage__ = """
@@ -33,13 +33,13 @@ gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP)
@my_gold.handle() @my_gold.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): async def _(event: GroupMessageEvent):
await my_gold.finish(await BagUser.get_my_total_gold(event.user_id, event.group_id)) await my_gold.finish(await BagUser.get_user_total_gold(event.user_id, event.group_id))
@gold_rank.handle() @gold_rank.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
num = get_message_text(event.json()) num = arg.extract_plain_text().strip()
if is_number(num) and 51 > int(num) > 10: if is_number(num) and 51 > int(num) > 10:
num = int(num) num = int(num)
else: else:
@@ -1,52 +1,41 @@
from nonebot import on_command from nonebot import on_command
from services.log import logger from services.log import logger
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent
from nonebot.typing import T_State from models.bag_user import BagUser
from models.bag_user import BagUser from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.adapters.cqhttp.permission import GROUP
__zx_plugin_name__ = "商店 - 我的道具"
__zx_plugin_name__ = "商店 - 我的道具" __plugin_usage__ = """
__plugin_usage__ = """ usage:
usage: 我的道具
我的道具 指令:
指令: 我的道具
我的道具 """.strip()
""".strip() __plugin_des__ = "商店 - 我的道具"
__plugin_des__ = "商店 - 我的道具" __plugin_cmd__ = ["我的道具"]
__plugin_cmd__ = ["我的道具"] __plugin_type__ = ('商店',)
__plugin_type__ = ('商店',) __plugin_version__ = 0.1
__plugin_version__ = 0.1 __plugin_author__ = "HibiKier"
__plugin_author__ = "HibiKier" __plugin_settings__ = {
__plugin_settings__ = { "level": 5,
"level": 5, "default_status": True,
"default_status": True, "limit_superuser": False,
"limit_superuser": False, "cmd": ["商店", "我的道具"],
"cmd": ["商店", "我的道具"], }
}
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
@my_props.handle()
@my_props.handle() async def _(event: GroupMessageEvent):
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): props = await BagUser.get_property(event.user_id, event.group_id)
props = await BagUser.get_props(event.user_id, event.group_id) if props:
if props: rst = ""
pname_list = [] for i, p in enumerate(props.keys()):
pnum_list = [] rst += f"{i+1}.{p}\t×{props[p]}\n"
rst = "" await my_props.send("\n" + rst[:-1], at_sender=True)
props = props[:-1].split(",") logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
for p in props: else:
if p != "": await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
if p in pname_list:
pnum_list[pname_list.index(p)] += 1
else:
pname_list.append(p)
pnum_list.append(1)
for i in range(len(pname_list)):
rst += f"{i+1}.{pname_list[i]}\t×{pnum_list[i]}\n"
await my_props.send("\n" + rst[:-1], at_sender=True)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
else:
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
@@ -1,26 +1,26 @@
from utils.utils import scheduler from utils.utils import scheduler
from models.bag_user import BagUser from models.bag_user import BagUser
from services.log import logger from services.log import logger
__zx_plugin_name__ = "每日金币重置 [Hidden]" __zx_plugin_name__ = "每日金币重置 [Hidden]"
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = "HibiKier" __plugin_author__ = "HibiKier"
# 重置每日金币 # 重置每日金币
@scheduler.scheduled_job( @scheduler.scheduled_job(
"cron", "cron",
hour=0, hour=0,
minute=1, minute=1,
) )
async def _(): async def _():
try: try:
user_list = await BagUser.get_all_users() user_list = await BagUser.get_all_users()
for user in user_list: for user in user_list:
await user.update( await user.update(
get_today_gold=0, get_today_gold=0,
spend_today_gold=0, spend_today_gold=0,
).apply() ).apply()
except Exception as e: except Exception as e:
logger.error(f"重置每日金币错误 e:{e}") logger.error(f"重置每日金币错误 e:{e}")
+133
View File
@@ -0,0 +1,133 @@
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info
from nonebot.adapters.onebot.v11 import MessageEvent, Message
from nonebot import on_command
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from nonebot.permission import SUPERUSER
from utils.utils import is_number
from nonebot.params import CommandArg
from nonebot.plugin import export
from services.log import logger
import os
__zx_plugin_name__ = "商店"
__plugin_usage__ = """
usage:
商店项目,这可不是奸商
指令:
商店
""".strip()
__plugin_superuser_usage__ = """
usage:
商品操作
指令:
添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)
删除商品 [名称或序号]
修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时]
示例:添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
示例:添加商品 name:可疑的药 price:5 des:效果未知
示例:删除商品 2
示例:修改商品 name:1 price:900 修改序号为1的商品的价格为900
* 修改商品只需添加需要值即可 *
""".strip()
__plugin_des__ = "商店系统[金币回收计划]"
__plugin_cmd__ = [
"商店",
"添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)) [_superuser]",
"删除商品 [名称或序号] [_superuser]",
"修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时] [_superuser]",
]
__plugin_type__ = ('商店',)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["商店"],
}
__plugin_block_limit__ = {
"limit_type": "group"
}
# 导出方法供其他插件使用
export = export()
export.register_goods = register_goods
export.delete_goods = delete_goods
export.update_goods = update_goods
shop_help = on_command("商店", priority=5, block=True)
shop_add_goods = on_command("添加商品", priority=5, permission=SUPERUSER, block=True)
shop_del_goods = on_command("删除商品", priority=5, permission=SUPERUSER, block=True)
shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER, block=True)
@shop_help.handle()
async def _():
await shop_help.send(image(b64=await create_shop_help()))
@shop_add_goods.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if msg:
data = parse_goods_info(msg)
if isinstance(data, str):
await shop_add_goods.finish(data)
if not data.get("name") or not data.get("price") or not data.get("des"):
await shop_add_goods.finish("name:price:des 参数不可缺少!")
if await register_goods(**data):
await shop_add_goods.send(f"添加商品 {data['name']} 成功!\n"
f"名称:{data['name']}\n"
f"价格:{data['price']}金币\n"
f"简介:{data['des']}\n"
f"折扣:{data.get('discount')}\n"
f"限时:{data.get('limit_time')}", at_sender=True)
logger.info(f"USER {event.user_id} 添加商品 {msg} 成功")
else:
await shop_add_goods.send(f"添加商品 {msg} 失败了...", at_sender=True)
logger.warning(f"USER {event.user_id} 添加商品 {msg} 失败")
@shop_del_goods.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if msg:
name = ""
id_ = 0
if is_number(msg):
id_ = int(msg)
else:
name = msg
rst, goods_name, code = await delete_goods(name, id_)
if code == 200:
await shop_del_goods.send(f"删除商品 {goods_name} 成功了...", at_sender=True)
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
os.remove(f"{IMAGE_PATH}/shop_help.png")
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 成功")
else:
await shop_del_goods.send(f"删除商品 {goods_name} 失败了...", at_sender=True)
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 失败")
@shop_update_goods.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if msg:
data = parse_goods_info(msg)
if isinstance(data, str):
await shop_add_goods.finish(data)
if not data.get("name"):
await shop_add_goods.finish("name 参数不可缺少!")
flag, name, text = await update_goods(**data)
if flag:
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功")
else:
await shop_update_goods.send(f"修改商品 {name} 失败了...", at_sender=True)
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败")
@@ -0,0 +1,269 @@
from models.goods_info import GoodsInfo
from utils.image_utils import BuildImage
from models.sign_group_user import SignGroupUser
from utils.utils import is_number
from configs.path_config import IMAGE_PATH
from typing import Optional, Union
from configs.config import Config
from nonebot import Driver
from nonebot.plugin import require
import nonebot
import time
driver: Driver = nonebot.get_driver()
use = require("use")
@driver.on_startup
async def init_default_shop_goods():
"""
导入内置的三个商品
"""
async def sign_card(**kwargs):
user_id = kwargs['user_id']
group_id = kwargs['group_id']
prob = kwargs["prob"]
user = await SignGroupUser.ensure(user_id, group_id)
await user.update(add_probability=prob).apply()
if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
await register_goods(
"好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"
)
use.register_use("好感度双倍加持卡Ⅰ", sign_card, **{"prob": 0.1})
await register_goods("好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)")
use.register_use("好感度双倍加持卡Ⅱ", sign_card, **{"prob": 0.2})
await register_goods(
"好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"
)
use.register_use("好感度双倍加持卡Ⅲ", sign_card, **{"prob": 0.3})
# 创建商店界面
async def create_shop_help() -> str:
"""
制作商店图片
:return: 图片base64
"""
goods_lst = await GoodsInfo.get_all_goods()
idx = 1
_dc = {}
font_h = BuildImage(0, 0).getsize("正")[1]
h = 10
_list = []
for goods in goods_lst:
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time:
h += len(goods.goods_description.strip().split("\n")) * font_h + 80
_list.append(goods)
A = BuildImage(1000, h, color="#f9f6f2")
current_h = 0
for goods in _list:
bk = BuildImage(
700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf"
)
goods_image = BuildImage(
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
)
name_image = BuildImage(
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
)
await name_image.atext(
(15, 0), f"{idx}.{goods.goods_name}", center_type="by_height"
)
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
await name_image.atext((390, 0), "售价:", center_type="by_height")
await name_image.atext(
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
)
await name_image.atext(
(
440
+ BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w,
0,
),
" 金币",
center_type="by_height",
)
await name_image.acircle_corner(5)
await goods_image.apaste(name_image, (0, 5), True, center_type="by_width")
await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
await goods_image.acircle_corner(20)
await bk.apaste(goods_image, alpha=True)
# 添加限时图标和时间
if goods.goods_limit_time > 0:
_limit_time_logo = BuildImage(40, 40, background=f"{IMAGE_PATH}/other/time.png")
await bk.apaste(_limit_time_logo, (600, 0), True)
await bk.apaste(BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"), (640, 10), True)
limit_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)).split()
y_m_d = limit_time[0]
_h_m = limit_time[1].split(":")
h_m = _h_m[0] + "时 " + _h_m[1] + "分"
await bk.atext((605, 38), str(y_m_d))
await bk.atext((615, 57), str(h_m))
await bk.aline((550, -1, 710, -1), "#a29ad6", 5)
await bk.aline((550, 80, 710, 80), "#a29ad6", 5)
idx += 1
await A.apaste(bk, (0, current_h), True)
current_h += 90
w = 1000
h = A.h + 230 + 100
h = 1000 if h < 1000 else h
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
shop.paste(A, (20, 230))
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan.png")
zx_img.replace_color_tran(((240, 240, 240), (255, 255, 255)), (249, 246, 242))
await shop.apaste(zx_img, (780, 100))
await shop.apaste(shop_logo, (450, 30), True)
shop.text(
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
"注【通过 序号 或者 商品名称 购买】",
)
shop.text((20, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
return shop.pic2bs4()
async def register_goods(
name: str,
price: int,
des: str,
discount: Optional[float] = 1,
limit_time: Optional[int] = 0,
**kwargs,
):
"""
添加商品
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
添加商品 name:可疑的药 price:5 des:效果未知
:param name: 商品名称
:param price: 商品价格
:param des: 商品简介
:param discount: 商品折扣
:param limit_time: 商品限时销售时间,单位为小时
:param kwargs: kwargs
:return: 是否添加成功
"""
if kwargs:
name = kwargs.get("name")
price = kwargs.get("price")
des = kwargs.get("des")
discount = kwargs.get("discount")
limit_time = kwargs.get("time_limit")
limit_time = float(limit_time) if limit_time else limit_time
discount = discount if discount is None else 1
limit_time = int(time.time() + limit_time * 60 * 60) if limit_time is not None and limit_time != 0 else 0
return await GoodsInfo.add_goods(
name, int(price), des, float(discount), limit_time
)
# 删除商品
async def delete_goods(name: str, id_: int) -> "str, str, int":
"""
删除商品
:param name: 商品名称
:param id_: 商品id
:return: 删除状况
"""
goods_lst = await GoodsInfo.get_all_goods()
if id_:
if id_ < 1 or id_ > len(goods_lst):
return "序号错误,没有该序号商品...", "", 999
goods_name = goods_lst[id_ - 1].goods_name
if await GoodsInfo.delete_goods(goods_name):
return f"删除商品 {goods_name} 成功!", goods_name, 200
else:
return f"删除商品 {goods_name} 失败!", goods_name, 999
if name:
if await GoodsInfo.delete_goods(name):
return f"删除商品 {name} 成功!", name, 200
else:
return f"删除商品 {name} 失败!", name, 999
# 更新商品信息
async def update_goods(**kwargs) -> "str, str, int":
"""
更新商品信息
:param kwargs: kwargs
:return: 更新状况
"""
if kwargs:
goods_lst = await GoodsInfo.get_all_goods()
if is_number(kwargs["name"]):
if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst):
return "序号错误,没有该序号的商品...", "", 999
goods = goods_lst[int(kwargs["name"]) - 1]
else:
goods = await GoodsInfo.get_goods_info(kwargs["name"])
if not goods:
return "名称错误,没有该名称的商品...", "", 999
name = goods.goods_name
price = goods.goods_price
des = goods.goods_description
discount = goods.goods_discount
limit_time = goods.goods_limit_time
new_time = 0
tmp = ""
if kwargs.get("price"):
tmp += f'价格:{price} --> {kwargs["price"]}\n'
price = kwargs["price"]
if kwargs.get("des"):
tmp += f'描述:{des} --> {kwargs["des"]}\n'
des = kwargs["des"]
if kwargs.get("discount"):
tmp += f'折扣:{discount} --> {kwargs["discount"]}\n'
discount = kwargs["discount"]
if kwargs.get("limit_time"):
kwargs["limit_time"] = float(kwargs["limit_time"])
new_time = time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime(time.time() + kwargs["limit_time"] * 60 * 60),
)
tmp += f"限时至: {new_time}\n"
limit_time = kwargs["limit_time"]
return (
await GoodsInfo.update_goods(
name,
int(price),
des,
float(discount),
int(time.time() + limit_time * 60 * 60 if limit_time != 0 and new_time else 0),
),
name,
tmp[:-1],
)
def parse_goods_info(msg: str) -> Union[dict, str]:
"""
解析格式数据
:param msg: 消息
:return: 解析完毕的数据data
"""
if "name:" not in msg:
return "必须指定修改的商品名称或序号!"
data = {}
for x in msg.split():
sp = x.split(":", maxsplit=1)
if str(sp[1]).strip():
sp[1] = sp[1].strip()
if sp[0] == "name":
data["name"] = sp[1]
elif sp[0] == "price":
if not is_number(sp[1]) or int(sp[1]) < 0:
return "price参数不合法,必须大于等于0!"
data["price"] = sp[1]
elif sp[0] == "des":
data["des"] = sp[1]
elif sp[0] == "discount":
if not is_number(sp[1]) or float(sp[1]) < 0:
return "discount参数不合法,必须大于0!"
data["discount"] = sp[1]
elif sp[0] == "limit_time":
if not is_number(sp[1]) or float(sp[1]) < 0:
return "limit_time参数不合法,必须大于0!"
data["limit_time"] = sp[1]
return data
+81
View File
@@ -0,0 +1,81 @@
from nonebot import on_command
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
from nonebot.params import CommandArg
from utils.utils import is_number
from models.bag_user import BagUser
from nonebot.adapters.onebot.v11.permission import GROUP
from services.db_context import db
from nonebot.plugin import export
from .data_source import effect, register_use, func_manager
__zx_plugin_name__ = "商店 - 使用道具"
__plugin_usage__ = """
usage:
普通的使用道具
指令:
使用道具 [序号或道具名称] ?[数量]=1
* 序号以 ”我的道具“ 为准 *
""".strip()
__plugin_des__ = "商店 - 使用道具"
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
__plugin_type__ = ('商店',)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["商店", "使用道具"],
}
# 导出方法供其他插件使用
export = export()
export.register_use = register_use
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
@use_props.handle()
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
num = 1
msg_sp = msg.split()
if len(msg_sp) > 1 and is_number(msg_sp[-1]) and int(msg_sp[-1]) > 0:
num = int(msg.split()[-1])
msg = " ".join(msg.split()[:-1])
property_ = await BagUser.get_property(event.user_id, event.group_id)
if property_:
async with db.transaction():
if is_number(msg):
if 0 < int(msg) <= len(property_):
name = list(property_.keys())[int(msg) - 1]
else:
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
else:
if msg not in property_.keys():
await use_props.finish("道具名称错误!", at_sender=True)
name = msg
_user_prop_count = property_[name]
if num > _user_prop_count:
await use_props.finish(f"道具数量不足,无法使用{num}次!")
if num > (n := func_manager.get_max_num_limit(name)):
await use_props.finish(f"该道具单次只能使用 {n} 个!")
if await BagUser.delete_property(
event.user_id, event.group_id, name, num
):
if func_manager.check_send_success_message(name):
await use_props.send(f"使用道具 {name} {num} 次成功!", at_sender=True)
if msg := await effect(bot, event, name, num):
await use_props.send(msg, at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次成功"
)
else:
await use_props.send(f"使用道具 {name} {num} 次失败!", at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次失败"
)
else:
await use_props.send("您的背包里没有任何的道具噢", at_sender=True)
+121
View File
@@ -0,0 +1,121 @@
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot
from typing import Optional, Union
import asyncio
class GoodsUseFuncManager:
def __init__(self):
self._data = {}
def register_use(self, goods_name: str, **kwargs):
"""
注册商品使用方法
:param goods_name: 商品名称
:param kwargs: kwargs
"""
self._data[goods_name] = kwargs
def exists(self, goods_name: str) -> bool:
"""
判断商品使用方法是否被注册
:param goods_name: 商品名称
"""
return bool(self._data.get(goods_name))
def get_max_num_limit(self, goods_name: str) -> int:
"""
获取单次商品使用数量
:param goods_name: 商品名称
"""
if self.exists(goods_name):
return self._data[goods_name]["kwargs"]["_max_num_limit"]
return 1
async def use(self, **kwargs) -> Optional[Union[str, MessageSegment]]:
"""
使用道具
:param kwargs: kwargs
"""
goods_name = kwargs.get("goods_name")
if self.exists(goods_name):
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
return await self._data[goods_name]["func"](
**kwargs,
)
else:
return self._data[goods_name]["func"](
**kwargs,
)
def check_send_success_message(self, goods_name: str) -> bool:
"""
检查是否发送使用成功信息
:param goods_name: 商品名称
"""
if self.exists(goods_name):
return bool(self._data[goods_name]["kwargs"]["send_success_msg"])
return False
def get_kwargs(self, goods_name: str) -> dict:
"""
获取商品使用方法的kwargs
:param goods_name: 商品名称
"""
if self.exists(goods_name):
return self._data[goods_name]["kwargs"]
return {}
func_manager = GoodsUseFuncManager()
async def effect(
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int
) -> Optional[Union[str, MessageSegment]]:
"""
商品生效
:param bot: Bot
:param event: GroupMessageEvent
:param goods_name: 商品名称
:param num: 使用数量
:return: 使用是否成功
"""
# 优先使用注册的商品插件
try:
if func_manager.exists(goods_name):
_kwargs = func_manager.get_kwargs(goods_name)
return await func_manager.use(
**{
**_kwargs,
"_bot": bot,
"event": event,
"group_id": event.group_id,
"user_id": event.user_id,
"num": num,
"goods_name": goods_name,
}
)
except Exception as e:
logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
return None
def register_use(goods_name: str, func, **kwargs):
"""
注册商品使用方法
:param goods_name: 商品名称
:param func: 使用函数
:param kwargs: kwargs
"""
if func_manager.exists(goods_name):
raise ValueError("该商品使用函数已被注册!")
# 发送使用成功信息
if kwargs.get("send_success_msg") is None:
kwargs["send_success_msg"] = True
kwargs["_max_num_limit"] = (
kwargs.get("_max_num_limit") if kwargs.get("_max_num_limit") else 1
)
func_manager.register_use(goods_name, **{"func": func, "kwargs": kwargs})
logger.info(f"register_use 成功注册商品:{goods_name} 的使用函数")
+10 -10
View File
@@ -1,10 +1,10 @@
import nonebot import nonebot
nonebot.load_plugins('basic_plugins/super_cmd') nonebot.load_plugins('basic_plugins/super_cmd')
+153 -152
View File
@@ -1,152 +1,153 @@
from nonebot import on_command from nonebot import on_command
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.typing import T_State from nonebot.adapters.onebot.v11 import Bot, Message
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message from nonebot.params import Command, CommandArg
from nonebot.rule import to_me from typing import Tuple
from utils.utils import get_message_text, is_number from nonebot.rule import to_me
from utils.manager import requests_manager from utils.utils import is_number
from utils.message_builder import image from utils.manager import requests_manager
from models.group_info import GroupInfo from utils.message_builder import image
from models.group_info import GroupInfo
__zx_plugin_name__ = "显示所有好友群组 [Superuser]"
__plugin_usage__ = """ __zx_plugin_name__ = "显示所有好友群组 [Superuser]"
usage: __plugin_usage__ = """
显示所有好友群组 usage:
指令: 显示所有好友群组
查看所有好友/查看所有群组 指令:
同意好友请求 [id] 查看所有好友/查看所有群组
拒绝好友请求 [id] 同意好友请求 [id]
同意群聊请求 [id] 拒绝好友请求 [id]
拒绝群聊请求 [id] 同意群聊请求 [id]
查看所有请求 拒绝群聊请求 [id]
清空所有请求 查看所有请求
""".strip() 清空所有请求
__plugin_des__ = "显示所有好友群组" """.strip()
__plugin_cmd__ = [ __plugin_des__ = "显示所有好友群组"
"查看所有好友/查看所有群组", __plugin_cmd__ = [
"同意好友请求 [id]", "查看所有好友/查看所有群组",
"拒绝好友请求 [id]", "同意好友请求 [id]",
"同意群聊请求 [id]", "拒绝好友请求 [id]",
"拒绝群聊请求 [id]", "同意群聊请求 [id]",
"查看所有请求", "拒绝群聊请求 [id]",
"清空所有请求", "查看所有请求",
] "清空所有请求",
__plugin_version__ = 0.1 ]
__plugin_author__ = "HibiKier" __plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
cls_group = on_command(
"查看所有群组", rule=to_me(), permission=SUPERUSER, priority=1, block=True cls_group = on_command(
) "查看所有群组", rule=to_me(), permission=SUPERUSER, priority=1, block=True
cls_friend = on_command( )
"查看所有好友", rule=to_me(), permission=SUPERUSER, priority=1, block=True cls_friend = on_command(
) "查看所有好友", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
friend_handle = on_command(
"同意好友请求", aliases={"拒绝好友请求"}, permission=SUPERUSER, priority=1, block=True friend_handle = on_command(
) "同意好友请求", aliases={"拒绝好友请求"}, permission=SUPERUSER, priority=1, block=True
)
group_handle = on_command(
"同意群聊请求", aliases={"拒绝群聊请求"}, permission=SUPERUSER, priority=1, block=True group_handle = on_command(
) "同意群聊请求", aliases={"拒绝群聊请求"}, permission=SUPERUSER, priority=1, block=True
)
clear_request = on_command("清空所有请求", permission=SUPERUSER, priority=1, block=True)
clear_request = on_command("清空所有请求", permission=SUPERUSER, priority=1, block=True)
cls_request = on_command("查看所有请求", permission=SUPERUSER, priority=1, block=True)
cls_request = on_command("查看所有请求", permission=SUPERUSER, priority=1, block=True)
@cls_group.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): @cls_group.handle()
gl = await bot.get_group_list(self_id=int(bot.self_id)) async def _(bot: Bot):
msg = ["{group_id} {group_name}".format_map(g) for g in gl] gl = await bot.get_group_list()
msg = "\n".join(msg) msg = ["{group_id} {group_name}".format_map(g) for g in gl]
msg = f"bot:{bot.self_id}\n| 群号 | 群名 | 共{len(gl)}个群\n" + msg msg = "\n".join(msg)
await bot.send_private_msg( msg = f"bot:{bot.self_id}\n| 群号 | 群名 | 共{len(gl)}个群\n" + msg
self_id=int(bot.self_id), await cls_group.send(msg)
user_id=int(list(bot.config.superusers)[0]),
message=msg,
) @cls_friend.handle()
async def _(bot: Bot):
gl = await bot.get_friend_list()
@cls_friend.handle() msg = ["{user_id} {nickname}".format_map(g) for g in gl]
async def _(bot: Bot, event: MessageEvent, state: T_State): msg = "\n".join(msg)
gl = await bot.get_friend_list(self_id=int(bot.self_id)) msg = f"| QQ号 | 昵称 | 共{len(gl)}个好友\n" + msg
msg = ["{user_id} {nickname}".format_map(g) for g in gl] await cls_friend.send(msg)
msg = "\n".join(msg)
msg = f"| QQ号 | 昵称 | 共{len(gl)}个好友\n" + msg
await bot.send_private_msg( @friend_handle.handle()
self_id=int(bot.self_id), async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
user_id=int(list(bot.config.superusers)[0]), cmd = cmd[0]
message=msg, id_ = arg.extract_plain_text().strip()
) if is_number(id_):
id_ = int(id_)
if cmd[:2] == "同意":
@friend_handle.handle() flag = await requests_manager.approve(bot, id_, "private")
async def _(bot: Bot, event: MessageEvent, state: T_State): else:
id_ = get_message_text(event.json()) flag = await requests_manager.refused(bot, id_, "private")
if is_number(id_): if flag == 1:
id_ = int(id_) await friend_handle.send(f"{cmd[:2]}好友请求失败,该请求已失效..")
if state["_prefix"]["raw_command"][:2] == "同意": requests_manager.delete_request(id_, "private")
if await requests_manager.approve(bot, id_, "private"): elif flag == 2:
await friend_handle.send("同意好友请求成功..") await friend_handle.send(f"{cmd[:2]}好友请求失败,未找到此id的请求..")
else: else:
await friend_handle.send("同意好友请求失败,可能是未找到此id的请求..") await friend_handle.send(f"{cmd[:2]}好友请求成功!")
else: else:
if await requests_manager.refused(bot, id_, "private"): await friend_handle.send("id必须为纯数字!")
await friend_handle.send("拒绝好友请求成功..")
else:
await friend_handle.send("拒绝好友请求失败,可能是未找到此id的请求..") @group_handle.handle()
else: async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
await friend_handle.send("id必须为纯数字!") cmd = cmd[0]
id_ = arg.extract_plain_text().strip()
flag = None
@group_handle.handle() if is_number(id_):
async def _(bot: Bot, event: MessageEvent, state: T_State): id_ = int(id_)
id_ = get_message_text(event.json()) if cmd[:2] == "同意":
if is_number(id_): rid = requests_manager.get_group_id(id_)
id_ = int(id_) if rid:
if state["_prefix"]["raw_command"][:2] == "同意": if await GroupInfo.get_group_info(rid):
rid = await requests_manager.approve(bot, id_, "group") await GroupInfo.set_group_flag(rid, 1)
if rid: else:
await friend_handle.send("同意群聊请求成功..") group_info = await bot.get_group_info(group_id=rid)
if await GroupInfo.get_group_info(rid): await GroupInfo.add_group_info(
await GroupInfo.set_group_flag(rid, 1) rid,
else: group_info["group_name"],
group_info = await bot.get_group_info(group_id=rid) group_info["max_member_count"],
await GroupInfo.add_group_info( group_info["member_count"],
rid, 1
group_info["group_name"], )
group_info["max_member_count"], flag = await requests_manager.approve(bot, id_, "group")
group_info["member_count"], else:
1 await friend_handle.send("同意群聊请求失败,未找到此id的请求..")
) else:
else: flag = await requests_manager.refused(bot, id_, "group")
await friend_handle.send("同意群聊请求失败,可能是未找到此id的请求..") if flag == 1:
else: await friend_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..")
if await requests_manager.refused(bot, id_, "group"): requests_manager.delete_request(id_, "group")
await friend_handle.send("拒绝群聊请求成功..") elif flag == 2:
else: await friend_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..")
await friend_handle.send("拒绝群聊请求失败,可能是未找到此id的请求..") else:
else: await friend_handle.send(f"{cmd[:2]}群聊请求成功!")
await friend_handle.send("id必须为纯数字!") else:
await friend_handle.send("id必须为纯数字!")
@cls_request.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): @cls_request.handle()
_str = "" async def _():
for type_ in ["private", "group"]: _str = ""
msg = await requests_manager.show(type_) for type_ in ["private", "group"]:
if msg: msg = await requests_manager.show(type_)
_str += image(b64=msg) if msg:
else: _str += image(b64=msg)
_str += "没有任何好友请求.." if type_ == "private" else "没有任何群聊请求.." else:
if type_ == "private": _str += "没有任何好友请求.." if type_ == "private" else "没有任何群聊请求.."
_str += '\n--------------------\n' if type_ == "private":
await cls_request.send(Message(_str)) _str += '\n--------------------\n'
await cls_request.send(Message(_str))
@clear_request.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): @clear_request.handle()
requests_manager.clear() async def _():
await cls_request.send("已清空所有好友/群聊请求..") requests_manager.clear()
await cls_request.send("已清空所有好友/群聊请求..")
+66 -67
View File
@@ -1,67 +1,66 @@
from nonebot import on_command from nonebot import on_command
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.typing import T_State from configs.path_config import TEMP_PATH
from nonebot.adapters.cqhttp import Bot, MessageEvent from nonebot.rule import to_me
from configs.path_config import TEMP_PATH from utils.utils import scheduler
from nonebot.rule import to_me from services.log import logger
from utils.utils import scheduler from utils.manager import resources_manager
from services.log import logger import asyncio
from utils.manager import resources_manager import time
import asyncio import os
import time
import os __zx_plugin_name__ = "清理临时数据 [Superuser]"
__plugin_usage__ = """
__zx_plugin_name__ = "清理临时数据 [Superuser]" usage:
__plugin_usage__ = """ 清理临时数据
usage: 指令:
清理临时数据 清理临时数据
指令: """.strip()
清理临时数据 __plugin_des__ = "清理临时数据"
""".strip() __plugin_cmd__ = [
__plugin_des__ = "清理临时数据" "清理临时数据",
__plugin_cmd__ = [ ]
"清理临时数据", __plugin_version__ = 0.1
] __plugin_author__ = "HibiKier"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
clear_data = on_command(
"清理临时数据", rule=to_me(), permission=SUPERUSER, priority=1, block=True
clear_data = on_command( )
"清理临时数据", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
resources_manager.add_temp_dir(TEMP_PATH)
resources_manager.add_temp_dir(TEMP_PATH)
@clear_data.handle()
async def _():
@clear_data.handle() await clear_data.send("开始清理临时数据....")
async def _(bot: Bot, event: MessageEvent, state: T_State): size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
await clear_data.send("开始清理临时数据....") await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
def _clear_data() -> float:
size = 0
def _clear_data() -> float: for dir_ in resources_manager.get_temp_data_dir():
size = 0 if dir_.exists():
for dir_ in resources_manager.get_temp_data_dir(): for file in os.listdir(dir_):
if dir_.exists(): file = dir_ / file
for file in os.listdir(dir_): if file.is_file():
file = dir_ / file try:
try: if time.time() - os.path.getatime(file) > 300:
if time.time() - os.path.getatime(file) > 300: file_size = os.path.getsize(file)
file_size = os.path.getsize(file) file.unlink()
file.unlink() size += file_size
size += file_size except Exception as e:
except Exception as e: logger.error(f"清理临时数据错误...{type(e)}:{e}")
logger.error(f"清理临时数据错误...{type(e)}:{e}") return float(size)
return float(size)
@scheduler.scheduled_job(
@scheduler.scheduled_job( "cron",
"cron", hour=1,
hour=1, minute=1,
minute=1, )
) async def _():
async def _(): size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data) logger.info("自动清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
logger.info("自动清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
-74
View File
@@ -1,74 +0,0 @@
# async def open_remind(group: int, name: str) -> str:
# _name = ""
# if name == "zwa":
# _name = "早晚安"
# if name == "dz":
# _name = "地震播报"
# if name == "hy":
# _name = "群欢迎"
# if name == "kxcz":
# _name = "开箱重置提醒"
# if name == "gb":
# _name = "广播"
# if await GroupRemind.get_status(group, name):
# return f"该群已经开启过 {_name} 通知,请勿重复开启!"
# if await GroupRemind.set_status(group, name, True):
# return f"成功开启 {_name} 通知!0v0"
# else:
# return f"开启 {_name} 通知失败了..."
#
#
# async def close_remind(group: int, name: str) -> str:
# _name = ""
# if name == "zwa":
# _name = "早晚安"
# if name == "dz":
# _name = "地震播报"
# if name == "hy":
# _name = "群欢迎"
# if name == "kxcz":
# _name = "开箱重置提醒"
# if name == "gb":
# _name = "广播"
# if not await GroupRemind.get_status(group, name):
# return f"该群已经取消过 {_name} 通知,请勿重复取消!"
# if await GroupRemind.set_status(group, name, False):
# return f"成功关闭 {_name} 通知!0v0"
# else:
# return f"关闭 {_name} 通知失败了..."
# cmd_list = ['总开关', '签到', '发送图片', '色图', '黑白草图', 'coser', '鸡汤/语录', '骂我', '开箱', '鲁迅说', '假消息', '商店系统',
# '操作图片', '查询皮肤', '天气', '疫情', '识番', '搜番', '点歌', 'pixiv', 'rss', '方舟一井', '查干员', '骰子娘', '原神一井']
#
#
# def check_group_switch_json(group_id):
# if not os.path.exists(DATA_PATH + f'rule/group_switch/'):
# os.mkdir(DATA_PATH + f'rule/group_switch/')
# if not os.path.exists(DATA_PATH + f'rule/group_switch/{group_id}.json'):
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as f:
# data = {}
# for cmd in cmd_list:
# data[cmd] = True
# f.write(json.dumps(data, ensure_ascii=False))
# else:
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'r', encoding='utf8') as f:
# try:
# data = json.load(f)
# except ValueError:
# data = {}
# if len(data.keys()) - 1 != len(cmd_list):
# for cmd in cmd_list:
# if cmd not in data.keys():
# data[cmd] = True
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as wf:
# wf.write(json.dumps(data, ensure_ascii=False))
# reload(data)
# for file in os.listdir(DATA_PATH + 'group_help'):
# os.remove(DATA_PATH + f'group_help/{file}')
def reload(data):
static_group_dict = data
+37
View File
@@ -0,0 +1,37 @@
from nonebot.adapters.onebot.v11 import Message
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from services.db_context import db
from nonebot.params import CommandArg
from services.log import logger
__zx_plugin_name__ = "执行sql [Superuser]"
__plugin_usage__ = """
usage:
执行一段sql语句
指令:
exec [sql语句]
""".strip()
__plugin_des__ = "执行一段sql语句"
__plugin_cmd__ = [
"exec [sql语句]",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
exec_ = on_command("exec", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
@exec_.handle()
async def _(arg: Message = CommandArg()):
sql = arg.extract_plain_text().strip()
async with db.transaction():
try:
query = db.text(sql)
await db.first(query)
await exec_.send("执行 sql 语句成功.")
except Exception as e:
await exec_.send(f"执行 sql 语句失败 {type(e)}:{e}")
logger.error(f"执行 sql 语句失败 {type(e)}:{e}")
+204 -200
View File
@@ -1,200 +1,204 @@
from nonebot import on_command, on_regex from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GROUP, GroupMessageEvent, Message
from nonebot.permission import SUPERUSER from nonebot import on_command, on_regex
from nonebot.typing import T_State from nonebot.permission import SUPERUSER
from nonebot.adapters.cqhttp import Bot, MessageEvent, GROUP, GroupMessageEvent from nonebot.typing import T_State
from nonebot.rule import to_me from nonebot.rule import to_me
from utils.utils import get_message_text, is_number from utils.utils import is_number
from utils.manager import group_manager, plugins2settings_manager 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.cqhttp.exception import ActionFailed from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.params import Command, CommandArg
from typing import Tuple
__zx_plugin_name__ = "管理群操作 [Superuser]"
__plugin_usage__ = """
usage: __zx_plugin_name__ = "管理群操作 [Superuser]"
群权限 | 群白名单 | 退出群 操作 __plugin_usage__ = """
指令: usage:
退群 [group_id] 群权限 | 群白名单 | 退出群 操作
修改群权限 [group_id] [等级] 指令:
添加群白名单 *[group_id] 退群 [group_id]
删除群白名单 *[group_id] 修改群权限 [group_id] [等级]
添加群认证 *[group_id] 添加群白名单 *[group_id]
删除群认证 *[group_id] 删除群白名单 *[group_id]
查看群白名单 添加群认证 *[group_id]
""".strip() 删除群认证 *[group_id]
__plugin_des__ = "管理群操作" 查看群白名单
__plugin_cmd__ = [ """.strip()
"退群 [group_id]", __plugin_des__ = "管理群操作"
"修改群权限 [group_id] [等级]", __plugin_cmd__ = [
"添加群白名单 *[group_id]", "退群 [group_id]",
"删除群白名单 *[group_id]", "修改群权限 [group_id] [等级]",
"添加群认证 *[group_id]", "添加群白名单 *[group_id]",
"删除群认证 *[group_id]", "删除群白名单 *[group_id]",
"查看群白名单", "添加群认证 *[group_id]",
] "删除群认证 *[group_id]",
__plugin_version__ = 0.1 "查看群白名单",
__plugin_author__ = "HibiKier" ]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
del_group = on_command("退群", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
add_group_level = on_command("修改群权限", priority=1, permission=SUPERUSER, block=True) del_group = on_command("退群", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
my_group_level = on_command(
"查看群权限", aliases={"群权限"}, priority=5, permission=GROUP, block=True add_group_level = on_command("修改群权限", priority=1, permission=SUPERUSER, block=True)
) my_group_level = on_command(
what_up_group_level = on_regex( "查看群权限", aliases={"群权限"}, priority=5, permission=GROUP, block=True
".*?(提高|提升|升高|增加|加上)(.*?)群权限.*?", )
rule=to_me(), what_up_group_level = on_regex(
priority=5, ".*?(提高|提升|升高|增加|加上)(.*?)群权限.*?",
permission=GROUP, rule=to_me(),
block=True, priority=5,
) permission=GROUP,
manager_group_whitelist = on_command( block=True,
"添加群白名单", aliases={"删除群白名单"}, priority=1, permission=SUPERUSER, block=True )
) manager_group_whitelist = on_command(
"添加群白名单", aliases={"删除群白名单"}, priority=1, permission=SUPERUSER, block=True
show_group_whitelist = on_command( )
"查看群白名单", priority=1, permission=SUPERUSER, block=True
) show_group_whitelist = on_command(
"查看群白名单", priority=1, permission=SUPERUSER, block=True
group_auth = on_command( )
"添加群认证", aliases={"删除群认证"}, priority=1, permission=SUPERUSER, block=True
) group_auth = on_command(
"添加群认证", aliases={"删除群认证"}, priority=1, permission=SUPERUSER, block=True
)
@del_group.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
group_id = get_message_text(event.json()) @del_group.handle()
if group_id: async def _(bot: Bot, arg: Message = CommandArg()):
if is_number(group_id): group_id = arg.extract_plain_text().strip()
try: if group_id:
await bot.set_group_leave(group_id=int(group_id)) if is_number(group_id):
logger.info(f"退出群聊 {group_id} 成功") try:
await del_group.send(f"退出群聊 {group_id} 成功", at_sender=True) await bot.set_group_leave(group_id=int(group_id))
group_manager.delete_group(int(group_id)) logger.info(f"退出群聊 {group_id} 成功")
await GroupInfo.delete_group_info(int(group_id)) await del_group.send(f"退出群聊 {group_id} 成功", at_sender=True)
except Exception as e: group_manager.delete_group(int(group_id))
logger.info(f"退出群聊 {group_id} 失败 e:{e}") await GroupInfo.delete_group_info(int(group_id))
else: except Exception as e:
await del_group.finish(f"请输入正确的群号", at_sender=True) logger.info(f"退出群聊 {group_id} 失败 e:{e}")
else: else:
await del_group.finish(f"请输入群号", at_sender=True) await del_group.finish(f"请输入正确的群号", at_sender=True)
else:
await del_group.finish(f"请输入群号", at_sender=True)
@add_group_level.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json()) @add_group_level.handle()
group_id = 0 async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
level = 0 msg = arg.extract_plain_text().strip()
if not msg: group_id = 0
await add_group_level.finish("用法:修改群权限 [group] [level]") level = 0
msg = msg.split(" ") if not msg:
if len(msg) < 2: await add_group_level.finish("用法:修改群权限 [group] [level]")
await add_group_level.finish("参数不完全..[group] [level]") msg = msg.split(" ")
if is_number(msg[0]) and is_number(msg[1]): if len(msg) < 2:
group_id = msg[0] await add_group_level.finish("参数不完全..[group] [level]")
level = int(msg[1]) if is_number(msg[0]) and is_number(msg[1]):
else: group_id = msg[0]
await add_group_level.finish("参数错误...group和level必须是数字..") level = int(msg[1])
old_level = group_manager.get_group_level(group_id) else:
group_manager.set_group_level(group_id, level) await add_group_level.finish("参数错误...group和level必须是数字..")
await add_group_level.send("修改成功...", at_sender=True) old_level = group_manager.get_group_level(group_id)
if level > -1: group_manager.set_group_level(group_id, level)
await bot.send_group_msg( await add_group_level.send("修改成功...", at_sender=True)
group_id=int(group_id), message=f"管理员修改了此群权限:{old_level} -> {level}" if level > -1:
) await bot.send_group_msg(
logger.info(f"{event.user_id} 修改了 {group_id} 的权限:{level}") group_id=int(group_id), message=f"管理员修改了此群权限:{old_level} -> {level}"
)
logger.info(f"{event.user_id} 修改了 {group_id} 的权限:{level}")
@my_group_level.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
level = group_manager.get_group_level(event.group_id) @my_group_level.handle()
tmp = "" async def _(event: GroupMessageEvent):
data = plugins2settings_manager.get_data() level = group_manager.get_group_level(event.group_id)
for module in data: tmp = ""
if data[module]["level"] > level: data = plugins2settings_manager.get_data()
plugin_name = data[module]["cmd"][0] for module in data:
if plugin_name == "pixiv": if data[module]["level"] > level:
plugin_name = "搜图 p站排行" plugin_name = data[module]["cmd"][0]
tmp += f"{plugin_name}\n" if plugin_name == "pixiv":
if tmp: plugin_name = "搜图 p站排行"
tmp = "\n目前无法使用的功能:\n" + tmp tmp += f"{plugin_name}\n"
await my_group_level.finish(f"当前群权限:{level}{tmp}") if tmp:
tmp = "\n目前无法使用的功能:\n" + tmp
await my_group_level.finish(f"当前群权限:{level}{tmp}")
@what_up_group_level.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await what_up_group_level.finish( @what_up_group_level.handle()
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限" async def _():
) await what_up_group_level.finish(
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限"
)
@manager_group_whitelist.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json()).split() @manager_group_whitelist.handle()
all_group = [ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id)) cmd = cmd[0]
] msg = arg.extract_plain_text().strip()
group_list = [] all_group = [
for group in msg: g["group_id"] for g in await bot.get_group_list()
if is_number(group) and int(group) in all_group: ]
group_list.append(int(group)) group_list = []
if group_list: for group in msg:
for group in group_list: if is_number(group) and int(group) in all_group:
if state["_prefix"]["raw_command"] in ["添加群白名单"]: group_list.append(int(group))
group_manager.add_group_white_list(group) if group_list:
else: for group in group_list:
group_manager.delete_group_white_list(group) if cmd in ["添加群白名单"]:
group_list = [str(x) for x in group_list] group_manager.add_group_white_list(group)
await manager_group_whitelist.send( else:
"已成功将 " + "\n".join(group_list) + " " + state["_prefix"]["raw_command"] group_manager.delete_group_white_list(group)
) group_list = [str(x) for x in group_list]
else: await manager_group_whitelist.send(
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名") "已成功将 " + "\n".join(group_list) + " " + cmd
)
else:
@show_group_whitelist.handle() await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
async def _(bot: Bot, event: MessageEvent, state: T_State):
x = group_manager.get_group_white_list()
x = [str(g) for g in x] @show_group_whitelist.handle()
if x: async def _():
await show_group_whitelist.send("目前的群白名单:\n" + "\n".join(x)) x = group_manager.get_group_white_list()
else: x = [str(g) for g in x]
await show_group_whitelist.send("没有任何群在群白名单...") if x:
await show_group_whitelist.send("目前的群白名单:\n" + "\n".join(x))
else:
@group_auth.handle() await show_group_whitelist.send("没有任何群在群白名单...")
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json()).split()
for group_id in msg: @group_auth.handle()
if not is_number(group_id): async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
await group_auth.send(f"{group_id}非纯数字,已跳过该项..") cmd = cmd[0]
group_id = int(group_id) msg = arg.extract_plain_text().strip().split()
if state["_prefix"]["raw_command"][:2] == "添加": for group_id in msg:
if await GroupInfo.get_group_info(group_id): if not is_number(group_id):
await GroupInfo.set_group_flag(group_id, 1) await group_auth.send(f"{group_id}非纯数字,已跳过该项..")
else: group_id = int(group_id)
try: if cmd[:2] == "添加":
group_info = await bot.get_group_info(group_id=group_id) if await GroupInfo.get_group_info(group_id):
except ActionFailed: await GroupInfo.set_group_flag(group_id, 1)
group_info = { else:
"group_id": group_id, try:
"group_name": "_", group_info = await bot.get_group_info(group_id=group_id)
"max_member_count": -1, except ActionFailed:
"member_count": -1, group_info = {
} "group_id": group_id,
await GroupInfo.add_group_info( "group_name": "_",
group_info["group_id"], "max_member_count": -1,
group_info["group_name"], "member_count": -1,
group_info["max_member_count"], }
group_info["member_count"], await GroupInfo.add_group_info(
1, group_info["group_id"],
) group_info["group_name"],
else: group_info["max_member_count"],
if await GroupInfo.get_group_info(group_id): group_info["member_count"],
await GroupInfo.set_group_flag(group_id, 0) 1,
await group_auth.send( )
f'已为 {group_id} {state["_prefix"]["raw_command"][:2]}群认证..' else:
) if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 0)
await group_auth.send(
f'已为 {group_id} {cmd[:2]}群认证..'
)
+72 -40
View File
@@ -1,40 +1,72 @@
from nonebot import on_command from nonebot import on_command
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.rule import to_me from nonebot.rule import to_me
from utils.manager import ( from utils.manager import (
plugins2cd_manager, plugins2cd_manager,
plugins2settings_manager, plugins2settings_manager,
plugins2block_manager, plugins2block_manager,
group_manager, group_manager,
) )
from nonebot.typing import T_State from configs.config import Config
from nonebot.adapters.cqhttp import Bot, MessageEvent from services.log import logger
from utils.utils import scheduler
__zx_plugin_name__ = "重载插件配置 [Superuser]"
__plugin_usage__ = """ __zx_plugin_name__ = "重载插件配置 [Superuser]"
usage: __plugin_usage__ = """
重载插件配置 usage:
指令: 重载插件配置
重载插件配置 plugins2settings,
""".strip() plugins2cd
__plugin_des__ = "重载插件配置" plugins2block
__plugin_cmd__ = [ group_manager
"重载插件配置", 指令:
] 重载插件配置
__plugin_version__ = 0.1 """.strip()
__plugin_author__ = "HibiKier" __plugin_des__ = "重载插件配置"
__plugin_cmd__ = [
"重载插件配置",
reload_plugins_manager = on_command( ]
"重载插件限制", rule=to_me(), permission=SUPERUSER, priority=1, block=True __plugin_version__ = 0.1
) __plugin_author__ = "HibiKier"
__plugin_configs__ = {
"AUTO_RELOAD": {
@reload_plugins_manager.handle() "value": False,
async def _(bot: Bot, event: MessageEvent, state: T_State): "help": "自动重载配置文件",
plugins2settings_manager.reload() "default_value": False
plugins2cd_manager.reload() },
plugins2block_manager.reload() "AUTO_RELOAD_TIME": {
group_manager.reload() "value": 180,
await reload_plugins_manager.send("重载完成...") "help": "控制自动重载配置文件时长",
"default_value": 180
}
}
reload_plugins_manager = on_command(
"重载配置", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
@reload_plugins_manager.handle()
async def _():
plugins2settings_manager.reload()
plugins2cd_manager.reload()
plugins2block_manager.reload()
group_manager.reload()
Config.reload()
await reload_plugins_manager.send("重载完成...")
@scheduler.scheduled_job(
'interval',
seconds=Config.get_config("reload_setting", "AUTO_RELOAD_TIME", 180),
)
async def _():
if Config.get_config("reload_setting", "AUTO_RELOAD"):
plugins2settings_manager.reload()
plugins2cd_manager.reload()
plugins2block_manager.reload()
group_manager.reload()
Config.reload()
logger.debug("已自动重载所有配置文件...")
+101 -89
View File
@@ -1,89 +1,101 @@
from nonebot import on_command from nonebot import on_command
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from models.level_user import LevelUser from models.level_user import LevelUser
from nonebot.typing import T_State from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, Message from utils.utils import get_message_at, is_number
from utils.utils import get_message_at, get_message_text, is_number from services.log import logger
from services.log import logger from utils.message_builder import at
from utils.message_builder import at from nonebot.params import Command, CommandArg
from typing import Tuple
__zx_plugin_name__ = "用户权限管理 [Superuser]"
__plugin_usage__ = """ __zx_plugin_name__ = "用户权限管理 [Superuser]"
usage: __plugin_usage__ = """
增删改用户的权限 usage:
指令: 增删改用户的权限
添加权限 [at] [权限] 指令:
添加权限 [qq] [group_id] [权限] 添加权限 [at] [权限]
删除权限 [at] 添加权限 [qq] [group_id] [权限]
""".strip() 删除权限 [at]
__plugin_des__ = "增删改用户的权限" """.strip()
__plugin_cmd__ = [ __plugin_des__ = "增删改用户的权限"
"添加权限 [at] [权限]", __plugin_cmd__ = [
"添加权限 [qq] [group_id] [权限]", "添加权限 [at] [权限]",
"删除权限 [at]", "添加权限 [qq] [group_id] [权限]",
] "删除权限 [at]",
__plugin_version__ = 0.1 ]
__plugin_author__ = "HibiKier" __plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
super_cmd = on_command(
"添加管理", super_cmd = on_command(
aliases={"删除管理", "添加权限", "删除权限"}, "添加管理",
priority=1, aliases={"删除管理", "添加权限", "删除权限"},
permission=SUPERUSER, priority=1,
block=True, permission=SUPERUSER,
) block=True,
)
@super_cmd.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @super_cmd.handle()
group_id = -1 async def _(
level = 0 bot: Bot,
try: event: MessageEvent,
args = get_message_text(event.json()).strip().split() cmd: Tuple[str, ...] = Command(),
qq = get_message_at(event.json()) arg: Message = CommandArg(),
flag = -1 ):
if not qq: group_id = event.group_id if isinstance(event, GroupMessageEvent) else -1
if len(args) > 2: level = None
if is_number(args[0]) and is_number(args[1]) and is_number(args[2]): args = arg.extract_plain_text().strip().split()
qq = int(args[0]) qq = get_message_at(event.json())
group_id = int(args[1]) flag = 2
level = int(args[2]) try:
flag = 1 if qq:
else: qq = qq[0]
await super_cmd.finish("所有参数必须是数字!", at_sender=True) if cmd[0][:2] == "添加" and args and is_number(args[0]):
else: level = int(args[0])
await super_cmd.finish( else:
"权限参数不完全\n\t格式:添加/删除权限 [at] [level]" if cmd[0][:2] == "添加":
"\n\t格式:添加/删除权限 [qq] [group] [level]", if (
at_sender=True, len(args) > 2
) and is_number(args[0])
else: and is_number(args[1])
qq = qq[0] and is_number(args[2])
group_id = event.group_id ):
flag = 2 qq = int(args[0])
if state["_prefix"]["raw_command"][:2] == "添加": group_id = int(args[1])
if is_number(args[0]): level = int(args[2])
level = int(args[0]) else:
else: if len(args) > 1 and is_number(args[0]) and is_number(args[1]):
await super_cmd.finish("权限等级必须是数字!", at_sender=True) qq = int(args[0])
if await LevelUser.set_level(qq, group_id, level, 1): group_id = int(args[1])
result = "添加管理成功, 权限: " + str(level) flag = 1
else: level = -1 if cmd[0][:2] == "删除" else level
result = "管理已存在, 更新权限: " + str(level) if group_id == -1 or not level or not qq:
else: raise IndexError()
if await LevelUser.delete_level(qq, event.group_id): except IndexError:
result = "删除管理成功!" await super_cmd.finish(__plugin_usage__)
else: try:
result = "该账号无管理权限!" if cmd[0][:2] == "添加":
if flag == 2: if await LevelUser.set_level(qq, group_id, level, 1):
await super_cmd.send(result) result = f"添加管理成功, 权限: {level}"
elif flag == 1: else:
await bot.send_group_msg( result = f"管理已存在, 更新权限: {level}"
group_id=group_id, else:
message=Message(f"{at(qq)}管理员修改了你的权限" f"\n--------\n你当前的权限等级:{level}"), if await LevelUser.delete_level(qq, event.group_id):
) result = "删除管理成功!"
await super_cmd.send("修改成功") else:
except Exception as e: result = "该账号无管理权限!"
await super_cmd.send("执行指令失败!") if flag == 2:
logger.error(f"执行指令失败 e:{e}") await super_cmd.send(result)
elif flag == 1:
await bot.send_group_msg(
group_id=group_id,
message=Message(
f"{at(qq)}管理员修改了你的权限"
f"\n--------\n你当前的权限等级:{level if level != -1 else 0}"
),
)
await super_cmd.send("修改成功")
except Exception as e:
await super_cmd.send("执行指令失败!")
logger.error(f"执行指令失败 e:{e}")
+57 -55
View File
@@ -1,56 +1,58 @@
from nonebot import on_command from nonebot import on_command
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.typing import T_State from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message
from nonebot.adapters.cqhttp import Bot, MessageEvent from nonebot.rule import to_me
from nonebot.rule import to_me from utils.utils import is_number
from utils.utils import get_message_text, is_number from services.log import logger
from services.log import logger from utils.manager import group_manager
from utils.manager import group_manager from nonebot.params import Command, CommandArg
from typing import Tuple
__zx_plugin_name__ = "超级用户被动开关 [Superuser]"
__plugin_usage__ = """ __zx_plugin_name__ = "超级用户被动开关 [Superuser]"
usage: __plugin_usage__ = """
超级用户被动开关 usage:
指令: 超级用户被动开关
开启/关闭广播通知 指令:
""".strip() 开启/关闭广播通知
__plugin_des__ = "超级用户被动开关" """.strip()
__plugin_cmd__ = [ __plugin_des__ = "超级用户被动开关"
"开启/关闭广播通知", __plugin_cmd__ = [
] "开启/关闭广播通知",
__plugin_version__ = 0.1 ]
__plugin_author__ = "HibiKier" __plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
oc_gb = on_command(
"开启广播通知", oc_gb = on_command(
aliases={"关闭广播通知"}, "开启广播通知",
rule=to_me(), aliases={"关闭广播通知"},
permission=SUPERUSER, rule=to_me(),
priority=1, permission=SUPERUSER,
block=True, priority=1,
) block=True,
)
@oc_gb.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): @oc_gb.handle()
group = get_message_text(event.json()) async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
if group: cmd = cmd[0]
if is_number(group): group = arg.extract_plain_text().strip()
group = int(group) if group:
for g in await bot.get_group_list(): if is_number(group):
if g["group_id"] == group: group = int(group)
break for g in await bot.get_group_list():
else: if g["group_id"] == group:
await oc_gb.finish("没有加入这个群...", at_sender=True) break
if state["_prefix"]["raw_command"] == "开启广播通知": else:
logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播") await oc_gb.finish("没有加入这个群...", at_sender=True)
await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True) if cmd == "开启广播通知":
else: logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播")
logger.info(f"USER {event.user_id} 关闭了 GROUP {group} 的广播") await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True)
await oc_gb.finish(await group_manager.close_group_task(group, "broadcast"), at_sender=True) else:
else: logger.info(f"USER {event.user_id} 关闭了 GROUP {group} 的广播")
await oc_gb.finish("请输入正确的群号", at_sender=True) await oc_gb.finish(await group_manager.close_group_task(group, "broadcast"), at_sender=True)
else: else:
await oc_gb.finish("请输入正确的群号", at_sender=True)
else:
await oc_gb.finish("请输入要关闭广播的群号", at_sender=True) await oc_gb.finish("请输入要关闭广播的群号", at_sender=True)
+69 -71
View File
@@ -1,71 +1,69 @@
from nonebot import on_command from nonebot import on_command
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.typing import T_State from nonebot.rule import to_me
from nonebot.adapters.cqhttp import Bot, MessageEvent from utils.utils import get_bot
from nonebot.rule import to_me from services.log import logger
from utils.utils import get_bot from models.group_info import GroupInfo
from services.log import logger from models.friend_user import FriendUser
from models.group_info import GroupInfo
from models.friend_user import FriendUser
__zx_plugin_name__ = "更新群/好友信息 [Superuser]"
__plugin_usage__ = """
__zx_plugin_name__ = "更新群/好友信息 [Superuser]" usage:
__plugin_usage__ = """ 更新群/好友信息
usage: 指令:
更新群/好友信息 更新群信息
指令: 更新好友信息
更新群信息 """.strip()
更新好友信息 __plugin_des__ = "更新群/好友信息"
""".strip() __plugin_cmd__ = [
__plugin_des__ = "更新群/好友信息" "更新群信息",
__plugin_cmd__ = [ "更新好友信息",
"更新群信息", ]
"更新好友信息", __plugin_version__ = 0.1
] __plugin_author__ = "HibiKier"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier" update_group_info = on_command(
"更新群信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
update_group_info = on_command( )
"更新群信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True update_friend_info = on_command(
) "更新好友信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
update_friend_info = on_command( )
"更新好友信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
@update_group_info.handle()
async def _():
@update_group_info.handle() bot = get_bot()
async def _(bot: Bot, event: MessageEvent, state: T_State): gl = await bot.get_group_list()
bot = get_bot() gl = [g["group_id"] for g in gl]
gl = await bot.get_group_list() num = 0
gl = [g["group_id"] for g in gl] rst = ""
num = 0 for g in gl:
rst = "" group_info = await bot.get_group_info(group_id=g)
for g in gl: if await GroupInfo.add_group_info(
group_info = await bot.get_group_info(group_id=g) group_info["group_id"],
if await GroupInfo.add_group_info( group_info["group_name"],
group_info["group_id"], group_info["max_member_count"],
group_info["group_name"], group_info["member_count"],
group_info["max_member_count"], ):
group_info["member_count"], num += 1
): logger.info(f"自动更新群组 {g} 信息成功")
num += 1 else:
logger.info(f"自动更新群组 {g} 信息成功") logger.info(f"自动更新群组 {g} 信息失败")
else: rst += f"{g} 更新失败\n"
logger.info(f"自动更新群组 {g} 信息失败") await update_group_info.send(f"成功更新了 {num} 个群的信息\n{rst[:-1]}")
rst += f"{g} 更新失败\n"
await update_group_info.send(f"成功更新了 {num} 个群的信息\n{rst[:-1]}")
@update_friend_info.handle()
async def _():
@update_friend_info.handle() num = 0
async def _(bot: Bot, event: MessageEvent, state: T_State): rst = ""
num = 0 fl = await get_bot().get_friend_list()
rst = "" for f in fl:
fl = await get_bot().get_friend_list() if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
for f in fl: logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
if await FriendUser.add_friend_info(f["user_id"], f["nickname"]): num += 1
logger.info(f'自动更新好友 {f["user_id"]} 信息成功') else:
num += 1 logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
else: rst += f'{f["user_id"]} 更新失败\n'
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败') await update_friend_info.send(f"成功更新了 {num} 个好友的信息\n{rst[:-1]}")
rst += f'{f["user_id"]} 更新失败\n'
await update_friend_info.send(f"成功更新了 {num} 个好友的信息\n{rst[:-1]}")
+27 -30
View File
@@ -1,30 +1,27 @@
from nonebot import on_command from nonebot import on_command
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.typing import T_State from nonebot.rule import to_me
from nonebot.adapters import Bot, Event from configs.path_config import IMAGE_PATH
from nonebot.rule import to_me from utils.message_builder import image
from configs.path_config import IMAGE_PATH from .data_source import create_help_image
from utils.message_builder import image
from .data_source import create_help_image
from pathlib import Path __zx_plugin_name__ = '超级用户帮助 [Superuser]'
__zx_plugin_name__ = '超级用户帮助 [Superuser]' superuser_help_image = IMAGE_PATH / 'superuser_help.png'
if superuser_help_image.exists():
superuser_help_image = Path(IMAGE_PATH) / 'superuser_help.png' superuser_help_image.unlink()
if superuser_help_image.exists(): super_help = on_command(
superuser_help_image.unlink() "超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True
)
super_help = on_command(
"超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True
) @super_help.handle()
async def _():
if not superuser_help_image.exists():
@super_help.handle() await create_help_image()
async def _(bot: Bot, event: Event, state: T_State): x = image(superuser_help_image)
if not superuser_help_image.exists(): await super_help.finish(x)
await create_help_image()
x = image(superuser_help_image)
await super_help.finish(x)
+9 -10
View File
@@ -1,9 +1,8 @@
from utils.image_utils import CreateImg from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from services.log import logger from services.log import logger
from utils.utils import get_matchers from utils.utils import get_matchers
from nonebot.adapters.cqhttp import Bot from nonebot.adapters.onebot.v11 import Bot
from pathlib import Path
from nonebot import Driver from nonebot import Driver
import asyncio import asyncio
import nonebot import nonebot
@@ -11,9 +10,9 @@ import nonebot
driver: Driver = nonebot.get_driver() driver: Driver = nonebot.get_driver()
background = Path(IMAGE_PATH) / "background" / "0.png" background = IMAGE_PATH / "background" / "0.png"
superuser_help_image = Path(IMAGE_PATH) / "superuser_help.png" superuser_help_image = IMAGE_PATH / "superuser_help.png"
@driver.on_bot_connect @driver.on_bot_connect
@@ -32,11 +31,11 @@ def _create_help_image():
_plugin_name_list = [] _plugin_name_list = []
width = 0 width = 0
help_str = "超级用户帮助\n\n* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" help_str = "超级用户帮助\n\n* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n"
tmp_img = CreateImg(0, 0, plain_text='1', font_size=24) tmp_img = BuildImage(0, 0, plain_text='1', font_size=24)
for matcher in _matchers: for matcher in _matchers:
plugin_name = "" plugin_name = ""
try: try:
_plugin = nonebot.plugin.get_plugin(matcher.module) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
_module = _plugin.module _module = _plugin.module
try: try:
plugin_name = _module.__getattribute__("__zx_plugin_name__") plugin_name = _module.__getattribute__("__zx_plugin_name__")
@@ -68,12 +67,12 @@ def _create_help_image():
width = width if width > x else x width = width if width > x else x
except Exception as e: except Exception as e:
logger.warning( logger.warning(
f"获取超级用户插件 {matcher.module}: {plugin_name} 设置失败... {type(e)}:{e}" f"获取超级用户插件 {matcher.plugin_name}: {plugin_name} 设置失败... {type(e)}:{e}"
) )
height = len(help_str.split("\n")) * 33 height = len(help_str.split("\n")) * 33
width += 500 width += 500
A = CreateImg(width, height, font_size=24) A = BuildImage(width, height, font_size=24)
_background = CreateImg(width, height, background=background) _background = BuildImage(width, height, background=background)
A.text((300, 140), help_str) A.text((300, 140), help_str)
A.paste(_background, alpha=True) A.paste(_background, alpha=True)
A.save(superuser_help_image) A.save(superuser_help_image)
Regular → Executable
+33 -35
View File
@@ -1,35 +1,33 @@
from nonebot import on_command from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, Event from utils.message_builder import image
from nonebot.typing import T_State
from utils.message_builder import image
__zx_plugin_name__ = "更新信息"
__plugin_usage__ = """
__zx_plugin_name__ = "更新信息" usage:
__plugin_usage__ = """ 更新信息
usage: 指令:
更新信息 更新信息
指令: """.strip()
更新信息 __plugin_des__ = "当前版本的更新信息"
""".strip() __plugin_cmd__ = ["更新信息"]
__plugin_des__ = "当前版本的更新信息" __plugin_version__ = 0.1
__plugin_cmd__ = ["更新信息"] __plugin_author__ = "HibiKier"
__plugin_version__ = 0.1 __plugin_settings__ = {
__plugin_author__ = "HibiKier" "level": 5,
__plugin_settings__ = { "default_status": True,
"level": 5, "limit_superuser": False,
"default_status": True, "cmd": ["更新信息"],
"limit_superuser": False, }
"cmd": ["更新信息"],
}
update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, block=True)
update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, block=True)
@update_info.handle()
async def _():
@update_info.handle() img = image("update_info.png")
async def _(bot: Bot, event: Event, state: T_State): if img:
img = image("update_info.png") await update_info.finish(image("update_info.png"))
if img: else:
await update_info.finish(image("update_info.png")) await update_info.finish("目前没有更新信息哦")
else:
await update_info.finish("目前没有更新信息哦")
+5 -4
View File
@@ -1,18 +1,19 @@
import nonebot import nonebot
from nonebot.adapters.cqhttp import Bot as CQHTTPBot from nonebot.adapters.onebot.v11 import Adapter
from services.db_context import init, disconnect from services.db_context import init, disconnect
nonebot.init() nonebot.init()
driver = nonebot.get_driver() driver = nonebot.get_driver()
driver.register_adapter("cqhttp", CQHTTPBot) driver.register_adapter(Adapter)
config = driver.config config = driver.config
driver.on_startup(init) driver.on_startup(init)
driver.on_shutdown(disconnect) 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("basic_plugins/hooks")
if __name__ == "__main__": if __name__ == "__main__":
+2 -2
View File
@@ -17,8 +17,8 @@ address: str = "" # 数据库地址
port: str = "" # 数据库端口 port: str = "" # 数据库端口
database: str = "" # 数据库名称 database: str = "" # 数据库名称
# 全局代理,例如 "http://127.0.0.1:7890" # 代理,例如 "http://127.0.0.1:7890"
SYSTEM_PROXY: Optional[str] = None SYSTEM_PROXY: Optional[str] = None # 全局代理
Config = ConfigsManager(Path() / "data" / "configs" / "plugins2config.yaml") Config = ConfigsManager(Path() / "data" / "configs" / "plugins2config.yaml")
+25 -21
View File
@@ -1,41 +1,45 @@
from pathlib import Path from pathlib import Path
import os
# 图片路径 # 图片路径
IMAGE_PATH = Path("resources/img/") IMAGE_PATH = Path() / "resources" / "image"
# 音频路径 # 语音路径
VOICE_PATH = Path("resources/voice/") RECORD_PATH = Path() / "resources" / "record"
# 文本路径 # 文本路径
TEXT_PATH = Path("resources/txt/") TEXT_PATH = Path() / "resources" / "text"
# 日志路径 # 日志路径
LOG_PATH = Path("log/") LOG_PATH = Path() / "log"
# 字体路径 # 字体路径
FONT_PATH = Path("resources/ttf/") FONT_PATH = Path() / "resources" / "font"
# 数据路径 # 数据路径
DATA_PATH = Path("data/") DATA_PATH = Path() / "data"
# 临时图片路径 # 临时数据路径
TEMP_PATH = Path("resources/img/temp/") TEMP_PATH = Path() / "resources" / "temp"
def init_path(): def load_path():
global IMAGE_PATH, VOICE_PATH, TEXT_PATH, LOG_PATH, FONT_PATH, DATA_PATH, TEMP_PATH old_img_dir = Path() / "resources" / "img"
if not IMAGE_PATH.exists() and old_img_dir.exists():
os.rename(old_img_dir, IMAGE_PATH)
old_voice_dir = Path() / "resources" / "voice"
if not RECORD_PATH.exists() and old_voice_dir.exists():
os.rename(old_voice_dir, RECORD_PATH)
old_ttf_dir = Path() / "resources" / "ttf"
if not FONT_PATH.exists() and old_ttf_dir.exists():
os.rename(old_ttf_dir, FONT_PATH)
old_txt_dir = Path() / "resources" / "txt"
if not TEXT_PATH.exists() and old_txt_dir.exists():
os.rename(old_txt_dir, TEXT_PATH)
IMAGE_PATH.mkdir(parents=True, exist_ok=True) IMAGE_PATH.mkdir(parents=True, exist_ok=True)
VOICE_PATH.mkdir(parents=True, exist_ok=True) RECORD_PATH.mkdir(parents=True, exist_ok=True)
TEXT_PATH.mkdir(parents=True, exist_ok=True) TEXT_PATH.mkdir(parents=True, exist_ok=True)
LOG_PATH.mkdir(parents=True, exist_ok=True) LOG_PATH.mkdir(parents=True, exist_ok=True)
FONT_PATH.mkdir(parents=True, exist_ok=True) FONT_PATH.mkdir(parents=True, exist_ok=True)
DATA_PATH.mkdir(parents=True, exist_ok=True) DATA_PATH.mkdir(parents=True, exist_ok=True)
TEMP_PATH.mkdir(parents=True, exist_ok=True) TEMP_PATH.mkdir(parents=True, exist_ok=True)
IMAGE_PATH = str(IMAGE_PATH.absolute()) + '/'
VOICE_PATH = str(VOICE_PATH.absolute()) + '/'
TEXT_PATH = str(TEXT_PATH.absolute()) + '/'
LOG_PATH = str(LOG_PATH.absolute()) + '/'
FONT_PATH = str(FONT_PATH.absolute()) + '/'
DATA_PATH = str(DATA_PATH.absolute()) + '/'
TEMP_PATH = str(TEMP_PATH.absolute()) + '/'
load_path()
init_path()
+55 -9
View File
@@ -11,14 +11,19 @@ class ConfigsManager:
def __init__(self, file: Path): def __init__(self, file: Path):
self._data: dict = {} self._data: dict = {}
self._simple_data: dict = {}
self._admin_level_data = [] self._admin_level_data = []
self._simple_file = Path() / "configs" / "config.yaml"
if file: if file:
file.parent.mkdir(exist_ok=True, parents=True) file.parent.mkdir(exist_ok=True, parents=True)
self.file = file self.file = file
_yaml = YAML()
if file.exists(): if file.exists():
_yaml = YAML()
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 self._simple_file.exists():
with open(self._simple_file, "r", encoding="utf8") as f:
self._simple_data = _yaml.load(f)
def add_plugin_config( def add_plugin_config(
self, self,
@@ -29,7 +34,7 @@ class ConfigsManager:
name: Optional[str] = None, name: Optional[str] = None,
help_: Optional[str] = None, help_: Optional[str] = None,
default_value: Optional[str] = None, default_value: Optional[str] = None,
_override: bool = False _override: bool = False,
): ):
""" """
为插件添加一个配置,不会被覆盖,只有第一个生效 为插件添加一个配置,不会被覆盖,只有第一个生效
@@ -61,6 +66,7 @@ class ConfigsManager:
"name": name.strip() if isinstance(name, str) else name, "name": name.strip() if isinstance(name, str) else name,
"help": help_.strip() if isinstance(help_, str) else help_, "help": help_.strip() if isinstance(help_, str) else help_,
"default_value": default_value, "default_value": default_value,
"level_module": _module,
} }
def remove_plugin_config(self, module: str): def remove_plugin_config(self, module: str):
@@ -70,6 +76,7 @@ class ConfigsManager:
""" """
if module in self._data.keys(): if module in self._data.keys():
del self._data[module] del self._data[module]
self.save()
def set_config(self, module: str, key: str, value: str): def set_config(self, module: str, key: str, value: str):
""" """
@@ -79,8 +86,10 @@ class ConfigsManager:
:param value: 值 :param value: 值
""" """
if module in self._data.keys(): if module in self._data.keys():
if self._data[module].get(key) is not None: if self._data[module].get(key) is not None and self._data[module][key] != value:
self._data[module][key]["value"] = value self._data[module][key]["value"] = value
self._simple_data[module][key] = value
self.save()
def set_help(self, module: str, key: str, help_: str): def set_help(self, module: str, key: str, help_: str):
""" """
@@ -92,6 +101,7 @@ class ConfigsManager:
if module in self._data.keys(): if module in self._data.keys():
if self._data[module].get(key) is not None: if self._data[module].get(key) is not None:
self._data[module][key]["help"] = help_ self._data[module][key]["help"] = help_
self.save()
def set_default_value(self, module: str, key: str, value: str): def set_default_value(self, module: str, key: str, value: str):
""" """
@@ -103,21 +113,37 @@ class ConfigsManager:
if module in self._data.keys(): if module in self._data.keys():
if self._data[module].get(key) is not None: if self._data[module].get(key) is not None:
self._data[module][key]["default_value"] = value self._data[module][key]["default_value"] = value
self.save()
def get_config(self, module: str, key: str) -> Optional[Any]: def get_config(self, module: str, key: str, default: Optional[Any] = None) -> Optional[Any]:
""" """
获取指定配置值 获取指定配置值
:param module: 模块名 :param module: 模块名
:param key: 配置名称 :param key: 配置名称
:param default: 没有key值内容的默认返回值
""" """
key = key.upper() key = key.upper()
if module in self._data.keys(): if module in self._data.keys():
if self._data[module].get(key) is not None: for key in [key, f"{key} [LEVEL]"]:
if self._data[module][key]["value"] is None: if self._data[module].get(key) is not None:
return self._data[module][key]["default_value"] if self._data[module][key]["value"] is None:
return self._data[module][key]["value"] return self._data[module][key]["default_value"]
return self._data[module][key]["value"]
if default is not None:
return default
return None return None
def get_level2module(self, module: str, key: str) -> Optional[str]:
"""
获取指定key所绑定的module,一般为权限等级
:param module: 模块名
:param key: 配置名称
:return:
"""
if self._data.get(module) is not None:
if self._data[module].get(key) is not None:
return self._data[module][key].get("level_module")
def get(self, key: str): def get(self, key: str):
""" """
获取插件配置数据 获取插件配置数据
@@ -126,17 +152,37 @@ class ConfigsManager:
if key in self._data.keys(): if key in self._data.keys():
return self._data[key] return self._data[key]
def save(self, path: Union[str, Path] = None): def save(self, path: Union[str, Path] = None, save_simple_data: bool = False):
""" """
保存数据 保存数据
:param path: 路径 :param path: 路径
:param save_simple_data: 同时保存至config.yaml
""" """
if save_simple_data:
with open(self._simple_file, "w", encoding="utf8") as f:
yaml.dump(
self._simple_data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
path = path if path else self.file path = path if path else self.file
with open(path, "w", encoding="utf8") as f: with open(path, "w", encoding="utf8") as f:
yaml.dump( yaml.dump(
self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
) )
def reload(self):
"""
重新加载配置文件
"""
_yaml = YAML()
temp_file = Path() / "configs" / "config.yaml"
if temp_file.exists():
with open(temp_file, "r", encoding="utf8") as f:
temp = _yaml.load(f)
for key in temp.keys():
for k in temp[key].keys():
self._data[key][k]["value"] = temp[key][k]
self.save()
def get_admin_level_data(self): def get_admin_level_data(self):
""" """
获取管理插件等级 获取管理插件等级
Binary file not shown.

After

Width:  |  Height:  |  Size: 772 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 694 KiB

Regular → Executable
+105 -110
View File
@@ -1,38 +1,39 @@
from services.db_context import db from services.db_context import db
from typing import Dict
from typing import Optional, List from typing import Optional, List
from services.log import logger
class BagUser(db.Model): class BagUser(db.Model):
__tablename__ = "bag_users" __tablename__ = "bag_users"
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False) user_qq = db.Column(db.BigInteger(), nullable=False)
belonging_group = db.Column(db.BigInteger(), nullable=False) group_id = db.Column(db.BigInteger(), nullable=False)
gold = db.Column(db.Integer(), default=100) gold = db.Column(db.Integer(), default=100)
props = db.Column(db.TEXT(), nullable=False, default="") props = db.Column(db.TEXT(), nullable=False, default="") # 旧道具字段(废弃)
spend_total_gold = db.Column(db.Integer(), default=0) spend_total_gold = db.Column(db.Integer(), default=0)
get_total_gold = db.Column(db.Integer(), default=0) get_total_gold = db.Column(db.Integer(), default=0)
get_today_gold = db.Column(db.Integer(), default=0) get_today_gold = db.Column(db.Integer(), default=0)
spend_today_gold = db.Column(db.Integer(), default=0) spend_today_gold = db.Column(db.Integer(), default=0)
property = db.Column(db.JSON(), nullable=False, default={}) # 新道具字段
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "belonging_group", unique=True) _idx1 = db.Index("bag_group_users_idx1", "user_qq", "group_id", unique=True)
@classmethod @classmethod
async def get_my_total_gold(cls, user_qq: int, belonging_group: int) -> str: async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
""" """
说明: 说明:
获取金币概况 获取金币概况
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 所在群号 :param group_id: 所在群号
""" """
query = cls.query.where( query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
user = await query.gino.first() user = await query.gino.first()
if not user: if not user:
user = await cls.create( user = await cls.create(
user_qq=user_qq, user_qq=user_qq,
belonging_group=belonging_group, group_id=group_id,
) )
return ( return (
f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}" f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}"
@@ -41,179 +42,173 @@ class BagUser(db.Model):
) )
@classmethod @classmethod
async def get_gold(cls, user_qq: int, belonging_group: int) -> int: async def get_gold(cls, user_qq: int, group_id: int) -> int:
""" """
说明: 说明:
获取当前金币 获取当前金币
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 所在群号 :param group_id: 所在群号
""" """
query = cls.query.where( query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
user = await query.gino.first() user = await query.gino.first()
if user: if user:
return user.gold return user.gold
else: else:
await cls.create( await cls.create(
user_qq=user_qq, user_qq=user_qq,
belonging_group=belonging_group, group_id=group_id,
) )
return 100 return 100
@classmethod @classmethod
async def get_props(cls, user_qq: int, belonging_group: int) -> str: async def get_property(cls, user_qq: int, group_id: int) -> Dict[str, int]:
""" """
说明: 说明:
获取当前道具 获取当前道具
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 所在群号 :param group_id: 所在群号
""" """
query = cls.query.where( query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
user = await query.gino.first() user = await query.gino.first()
if user: if user:
return user.props return user.property
else: else:
await cls.create( await cls.create(
user_qq=user_qq, user_qq=user_qq,
belonging_group=belonging_group, group_id=group_id,
) )
return "" return {}
@classmethod @classmethod
async def add_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool: async def add_gold(cls, user_qq: int, group_id: int, num: int):
""" """
说明: 说明:
增加金币 增加金币
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 所在群号 :param group_id: 所在群号
:param num: 金币数量 :param num: 金币数量
""" """
query = cls.query.where( query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = query.with_for_update() query = query.with_for_update()
user = await query.gino.first() user = await query.gino.first()
try: if user:
if user: await user.update(
await user.update( gold=user.gold + num,
gold=user.gold + num, get_total_gold=user.get_total_gold + num,
get_total_gold=user.get_total_gold + num, get_today_gold=user.get_today_gold + num,
get_today_gold=user.get_today_gold + num, ).apply()
).apply() else:
else: await cls.create(
await cls.create( user_qq=user_qq,
user_qq=user_qq, group_id=group_id,
belonging_group=belonging_group, gold=100 + num,
gold=100 + num, get_total_gold=num,
get_total_gold=num, get_today_gold=num,
get_today_gold=num, )
)
return True
except Exception:
return False
@classmethod @classmethod
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool: async def spend_gold(cls, user_qq: int, group_id: int, num: int):
""" """
说明: 说明:
花费金币 花费金币
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 所在群号 :param group_id: 所在群号
:param num: 金币数量 :param num: 金币数量
""" """
query = cls.query.where( query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = query.with_for_update() query = query.with_for_update()
user = await query.gino.first() user = await query.gino.first()
try: if user:
if user: await user.update(
await user.update( gold=user.gold - num,
gold=user.gold - num, spend_total_gold=user.spend_total_gold + num,
spend_total_gold=user.spend_total_gold + num, spend_today_gold=user.spend_today_gold + num,
spend_today_gold=user.spend_today_gold + num, ).apply()
).apply() else:
else: await cls.create(
await cls.create( user_qq=user_qq,
user_qq=user_qq, group_id=group_id,
belonging_group=belonging_group, gold=100 - num,
gold=100 - num, spend_total_gold=num,
spend_total_gold=num, spend_today_gold=num,
spend_today_gold=num, )
)
return True
except Exception:
return False
@classmethod @classmethod
async def add_props(cls, user_qq: int, belonging_group: int, name: str) -> bool: async def add_property(cls, user_qq: int, group_id: int, name: str):
""" """
说明: 说明:
增加道具 增加道具
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 所在群号 :param group_id: 所在群号
:param name: 道具名称 :param name: 道具名称
""" """
query = cls.query.where( query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = query.with_for_update() query = query.with_for_update()
user = await query.gino.first() user = await query.gino.first()
try: if user:
if user: p = user.property
await user.update(props=user.props + f"{name},").apply() if p.get(name) is None:
p[name] = 1
else: else:
await cls.create( p[name] += 1
user_qq=user_qq, belonging_group=belonging_group, props=f"{name}," await user.update(property=p).apply()
) else:
return True await cls.create(user_qq=user_qq, group_id=group_id, property={name: 1})
except Exception:
return False
@classmethod @classmethod
async def del_props(cls, user_qq: int, belonging_group: int, name: str) -> bool: async def delete_property(
cls, user_qq: int, group_id: int, name: str, num: int = 1
) -> bool:
""" """
说明: 说明:
使用道具 使用/删除 道具
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 所在群号 :param group_id: 所在群号
:param name: 道具名称 :param name: 道具名称
:param num: 使用个数
""" """
query = cls.query.where( query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
query = query.with_for_update() query = query.with_for_update()
user = await query.gino.first() user = await query.gino.first()
try: if user:
if user: property_ = user.property
rst = "" if name in property_:
props = user.props if property_.get(name) == num:
if props.find(name) != -1: del property_[name]
props = props.split(",")
try:
index = props.index(name)
except ValueError:
return False
props = props[:index] + props[index + 1 :]
for p in props:
if p != "":
rst += p + ","
await user.update(props=rst).apply()
return True
else: else:
return False property_[name] -= num
else: await user.update(property=property_).apply()
return False return True
except Exception: return False
@classmethod
async def buy_property(
cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int
) -> bool:
"""
说明:
购买道具
参数:
:param user_qq: 用户qq
:param group_id: 所在群聊
:param goods: 商品
:param goods_num: 商品数量
"""
try:
# 折扣后金币
spend_gold = goods.goods_discount * goods.goods_price * goods_num
await BagUser.spend_gold(user_qq, group_id, spend_gold)
for _ in range(goods_num):
await BagUser.add_property(user_qq, group_id, goods.goods_name)
return True
except Exception as e:
logger.error(f"buy_property 发生错误 {type(e)}:{e}")
return False return False
@classmethod @classmethod
@@ -227,5 +222,5 @@ class BagUser(db.Model):
if not group_id: if not group_id:
query = await cls.query.gino.all() query = await cls.query.gino.all()
else: else:
query = await cls.query.where((cls.belonging_group == group_id)).gino.all() query = await cls.query.where((cls.group_id == group_id)).gino.all()
return query return query
Regular → Executable
+1 -1
View File
@@ -82,7 +82,7 @@ class BanUser(db.Model):
参数: 参数:
:param user_qq: 目标用户qq号 :param user_qq: 目标用户qq号
:param ban_level: 使用ban命令用户的权限 :param ban_level: 使用ban命令用户的权限
:param duration: ban时长 :param duration: ban时长,秒
""" """
query = cls.query.where((cls.user_qq == user_qq)) query = cls.query.where((cls.user_qq == user_qq))
query = query.with_for_update() query = query.with_for_update()
+123
View File
@@ -0,0 +1,123 @@
from datetime import datetime, timedelta
from typing import List, Literal, Optional
from services.db_context import db
class ChatHistory(db.Model):
__tablename__ = "chat_history"
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger())
text = db.Column(db.Text())
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
@classmethod
async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str):
await cls.create(
user_qq=user_qq, group_id=group_id, text=text, create_time=datetime.now()
)
@classmethod
async def get_user_msg(
cls,
uid: int,
msg_type: Optional[Literal["private", "group"]],
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取用户消息
参数:
:param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊
:param days: 限制日期
"""
return await cls._get_msg(uid, None, "user", msg_type, days).gino.all()
@classmethod
async def get_user_msg_count(
cls,
uid: int,
msg_type: Optional[Literal["private", "group"]],
days: Optional[int] = None,
) -> int:
"""
说明:
获取用户消息数量
参数:
:param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊
:param days: 限制日期
"""
return (await cls._get_msg(uid, None, "user", msg_type, days, True).gino.first())[0]
@classmethod
async def get_group_msg(
cls,
gid: int,
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊消息
参数:
:param gid: 用户qq
:param days: 限制日期
"""
return await cls._get_msg(None, gid, "group", None, days).gino.all()
@classmethod
async def get_group_msg_count(
cls,
gid: int,
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊消息数量
参数:
:param gid: 用户qq
:param days: 限制日期
"""
return (await cls._get_msg(None, gid, "group", None, days, True).gino.first())[0]
@classmethod
def _get_msg(
cls,
uid: Optional[int],
gid: Optional[int],
type_: Literal["user", "group"],
msg_type: Optional[Literal["private", "group"]],
days: Optional[int],
is_select_count: bool = False
):
"""
说明:
获取消息查询query
参数:
:param uid: 用户qq
:param gid: 群号
:param type_: 类型,私聊或群聊
:param msg_type: 消息类型,用户或群聊
:param days: 限制日期
"""
if is_select_count:
setattr(ChatHistory, 'count', db.func.count(cls.id).label('count'))
query = cls.select('count')
else:
query = cls.query
if type_ == "user":
query = query.where(cls.user_qq == uid)
if msg_type == "private":
query = query.where(cls.group_id == None)
elif msg_type == "group":
query = query.where(cls.group_id != None)
else:
query = query.where(cls.group_id == gid)
if days:
query = query.where(
cls.create_time >= datetime.now() - timedelta(days=days)
)
return query
Regular → Executable
+7 -1
View File
@@ -1,4 +1,5 @@
from services.db_context import db from services.db_context import db
from configs.config import Config
class FriendUser(db.Model): class FriendUser(db.Model):
@@ -80,7 +81,12 @@ class FriendUser(db.Model):
user = await query.gino.first() user = await query.gino.first()
if user: if user:
if user.nickname: if user.nickname:
return user.nickname _tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
for x in user.nickname:
_tmp += "*" if x in black_word else x
return _tmp
return "" return ""
@classmethod @classmethod
@@ -1,5 +1,6 @@
from services.db_context import db from services.db_context import db
from typing import Optional, List from typing import Optional, List
from services.log import logger
class GoodsInfo(db.Model): class GoodsInfo(db.Model):
@@ -34,16 +35,18 @@ class GoodsInfo(db.Model):
:param goods_limit_time: 商品限时 :param goods_limit_time: 商品限时
""" """
try: try:
await cls.create( if not await cls.get_goods_info(goods_name):
goods_name=goods_name, await cls.create(
goods_price=goods_price, goods_name=goods_name,
goods_description=goods_description, goods_price=goods_price,
goods_discount=goods_discount, goods_description=goods_description,
goods_limit_time=goods_limit_time, goods_discount=goods_discount,
) goods_limit_time=goods_limit_time,
return True )
except Exception: return True
return False except Exception as e:
logger.error(f"GoodsInfo add_goods 发生错误 {type(e)}:{e}")
return False
@classmethod @classmethod
async def delete_goods(cls, goods_name: str) -> bool: async def delete_goods(cls, goods_name: str) -> bool:
@@ -99,7 +102,8 @@ class GoodsInfo(db.Model):
if goods_limit_time: if goods_limit_time:
await query.update(goods_limit_time=goods_limit_time).apply() await query.update(goods_limit_time=goods_limit_time).apply()
return True return True
except Exception: except Exception as e:
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
return False return False
@classmethod @classmethod
Regular → Executable
View File
Regular → Executable
+47 -29
View File
@@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from configs.config import Config
from services.db_context import db from services.db_context import db
from typing import List, Optional from typing import List, Optional
@@ -10,18 +10,18 @@ class GroupInfoUser(db.Model):
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False) user_qq = db.Column(db.BigInteger(), nullable=False)
user_name = db.Column(db.Unicode(), nullable=False) user_name = db.Column(db.Unicode(), nullable=False)
belonging_group = db.Column(db.BigInteger(), nullable=False) group_id = db.Column(db.BigInteger(), nullable=False)
user_join_time = db.Column(db.DateTime(), nullable=False) user_join_time = db.Column(db.DateTime(), nullable=False)
nickname = db.Column(db.Unicode()) nickname = db.Column(db.Unicode())
uid = db.Column(db.BigInteger()) uid = db.Column(db.BigInteger())
_idx1 = db.Index("info_group_users_idx1", "user_qq", "belonging_group", unique=True) _idx1 = db.Index("info_group_users_idx1", "user_qq", "group_id", unique=True)
@classmethod @classmethod
async def add_member_info( async def add_member_info(
cls, cls,
user_qq: int, user_qq: int,
belonging_group: int, group_id: int,
user_name: str, user_name: str,
user_join_time: datetime, user_join_time: datetime,
uid: Optional[int] = None, uid: Optional[int] = None,
@@ -31,20 +31,20 @@ class GroupInfoUser(db.Model):
添加群内用户信息 添加群内用户信息
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 群号 :param group_id: 群号
:param user_name: 用户名称 :param user_name: 用户名称
:param user_join_time: 入群时间 :param user_join_time: 入群时间
:param uid: 用户唯一 id(自动生成) :param uid: 用户唯一 id(自动生成)
""" """
query = cls.query.where( query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group) (cls.user_qq == user_qq) & (cls.group_id == group_id)
) )
try: try:
if not await query.gino.first(): if not await query.gino.first():
await cls.create( await cls.create(
user_qq=user_qq, user_qq=user_qq,
user_name=user_name, user_name=user_name,
belonging_group=belonging_group, group_id=group_id,
user_join_time=user_join_time, user_join_time=user_join_time,
uid=uid uid=uid
) )
@@ -54,31 +54,31 @@ class GroupInfoUser(db.Model):
@classmethod @classmethod
async def get_member_info( async def get_member_info(
cls, user_qq: int, belonging_group: int cls, user_qq: int, group_id: int
) -> "GroupInfoUser": ) -> "GroupInfoUser":
""" """
说明: 说明:
查询群员信息 查询群员信息
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 群号 :param group_id: 群号
""" """
query = cls.query.where( query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group) (cls.user_qq == user_qq) & (cls.group_id == group_id)
) )
return await query.gino.first() return await query.gino.first()
@classmethod @classmethod
async def delete_member_info(cls, user_qq: int, belonging_group: int) -> bool: async def delete_member_info(cls, user_qq: int, group_id: int) -> bool:
""" """
说明: 说明:
删除群员信息 删除群员信息
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 群号 :param group_id: 群号
""" """
query = cls.query.where( query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group) (cls.user_qq == user_qq) & (cls.group_id == group_id)
) )
query = query.with_for_update() query = query.with_for_update()
user = await query.gino.first() user = await query.gino.first()
@@ -87,40 +87,40 @@ class GroupInfoUser(db.Model):
return True return True
else: else:
await cls.delete.where( await cls.delete.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group) (cls.user_qq == user_qq) & (cls.group_id == group_id)
).gino.status() ).gino.status()
return True return True
except Exception: except Exception:
return False return False
@classmethod @classmethod
async def get_group_member_id_list(cls, belonging_group: int) -> List[int]: async def get_group_member_id_list(cls, group_id: int) -> List[int]:
""" """
说明: 说明:
获取该群所有用户qq 获取该群所有用户qq
参数: 参数:
:param belonging_group: 群号 :param group_id: 群号
""" """
member_list = [] member_list = []
query = cls.query.where((cls.belonging_group == belonging_group)) query = cls.query.where((cls.group_id == group_id))
for user in await query.gino.all(): for user in await query.gino.all():
member_list.append(user.user_qq) member_list.append(user.user_qq)
return member_list return member_list
@classmethod @classmethod
async def set_group_member_nickname( async def set_group_member_nickname(
cls, user_qq: int, belonging_group: int, nickname: str cls, user_qq: int, group_id: int, nickname: str
) -> bool: ) -> bool:
""" """
说明: 说明:
设置群员在该群内的昵称 设置群员在该群内的昵称
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 群号 :param group_id: 群号
:param nickname: 昵称 :param nickname: 昵称
""" """
query = cls.query.where( query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group) (cls.user_qq == user_qq) & (cls.group_id == group_id)
) )
user = await query.with_for_update().gino.first() user = await query.with_for_update().gino.first()
if user: if user:
@@ -129,30 +129,48 @@ class GroupInfoUser(db.Model):
return False return False
@classmethod @classmethod
async def get_group_member_nickname(cls, user_qq: int, belonging_group: int) -> str: async def get_user_all_group(cls, user_qq: int) -> List[int]:
"""
说明:
获取该用户所在的所有群聊
参数:
:param user_qq: 用户qq
"""
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
if query:
query = [x.group_id for x in query]
return query
@classmethod
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
""" """
说明: 说明:
获取用户在该群的昵称 获取用户在该群的昵称
参数: 参数:
:param user_qq: qq号 :param user_qq: qq号
:param belonging_group: 群号 :param group_id: 群号
""" """
query = cls.query.where( query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group) (cls.user_qq == user_qq) & (cls.group_id == group_id)
) )
user = await query.gino.first() user = await query.gino.first()
if user: if user:
if user.nickname: if user.nickname:
return user.nickname _tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
for x in user.nickname:
_tmp += "*" if x in black_word else x
return _tmp
return "" return ""
@classmethod @classmethod
async def get_group_member_uid(cls, user_qq: int, belonging_group: int) -> Optional[str]: async def get_group_member_uid(cls, user_qq: int, group_id: int) -> Optional[str]:
query = cls.query.where( query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group) (cls.user_qq == user_qq) & (cls.group_id == group_id)
) )
user = await query.gino.first() user = await query.gino.first()
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.belonging_group == 114514)).with_for_update() _max_uid = cls.query.where((cls.user_qq == 114514) & (cls.group_id == 114514)).with_for_update()
_max_uid_user = await _max_uid.gino.first() _max_uid_user = await _max_uid.gino.first()
_max_uid = _max_uid_user.uid _max_uid = _max_uid_user.uid
if not user or not user.uid: if not user or not user.uid:
@@ -162,9 +180,9 @@ class GroupInfoUser(db.Model):
return x.uid return x.uid
else: else:
if not user: if not user:
await GroupInfoUser.add_member_info(user_qq, belonging_group, '', datetime.min) await GroupInfoUser.add_member_info(user_qq, group_id, '', datetime.min)
user = await cls.query.where( user = await cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group) (cls.user_qq == user_qq) & (cls.group_id == group_id)
).gino.first() ).gino.first()
await user.update( await user.update(
uid=_max_uid + 1, uid=_max_uid + 1,
Regular → Executable
View File
Regular → Executable
+39 -12
View File
@@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import List
from services.db_context import db from services.db_context import db
@@ -8,8 +8,7 @@ class SignGroupUser(db.Model):
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False) user_qq = db.Column(db.BigInteger(), nullable=False)
belonging_group = db.Column(db.BigInteger(), nullable=False) group_id = db.Column(db.BigInteger(), nullable=False)
checkin_count = db.Column(db.Integer(), nullable=False) checkin_count = db.Column(db.Integer(), nullable=False)
checkin_time_last = db.Column(db.DateTime(timezone=True), nullable=False) checkin_time_last = db.Column(db.DateTime(timezone=True), nullable=False)
impression = db.Column(db.Numeric(scale=3, asdecimal=False), nullable=False) impression = db.Column(db.Numeric(scale=3, asdecimal=False), nullable=False)
@@ -20,28 +19,56 @@ class SignGroupUser(db.Model):
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0 db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
) )
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "belonging_group", unique=True) _idx1 = db.Index("sign_group_users_idx1", "user_qq", "group_id", unique=True)
@classmethod @classmethod
async def ensure( async def ensure(
cls, user_qq: int, belonging_group: int, for_update: bool = False cls, user_qq: int, group_id: int, for_update: bool = False
) -> "SignGroupUser": ) -> "SignGroupUser":
"""
说明:
获取签到用户
参数:
:param user_qq: 用户qq
:param group_id: 所在群聊
:param for_update: 是否存在修改数据
"""
query = cls.query.where( query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group) (cls.user_qq == user_qq) & (cls.group_id == group_id)
) )
if for_update: if for_update:
query = query.with_for_update() query = query.with_for_update()
user = await query.gino.first() user = await query.gino.first()
return user or await cls.create( return user or await cls.create(
user_qq=user_qq, user_qq=user_qq,
belonging_group=belonging_group, group_id=group_id,
checkin_count=0, checkin_count=0,
checkin_time_last=datetime.min, # 从未签到过 checkin_time_last=datetime.min, # 从未签到过
impression=0, impression=0,
) )
@classmethod
async def get_user_all_data(cls, user_qq: int) -> List["SignGroupUser"]:
"""
说明:
获取某用户所有数据
参数:
:param user_qq: 用户qq
"""
query = cls.query.where(cls.user_qq == user_qq)
query = query.with_for_update()
return await query.gino.all()
@classmethod @classmethod
async def sign(cls, user: "SignGroupUser", impression: float, checkin_time_last: datetime): async def sign(cls, user: "SignGroupUser", impression: float, checkin_time_last: datetime):
"""
说明:
签到
说明:
:param user: 用户
:param impression: 增加的好感度
:param checkin_time_last: 签到时间
"""
await user.update( await user.update(
checkin_count=user.checkin_count + 1, checkin_count=user.checkin_count + 1,
checkin_time_last=checkin_time_last, checkin_time_last=checkin_time_last,
@@ -51,22 +78,22 @@ class SignGroupUser(db.Model):
).apply() ).apply()
@classmethod @classmethod
async def get_all_impression(cls, belonging_group: int) -> "list, list, list": async def get_all_impression(cls, group_id: int) -> "list, list, list":
""" """
说明: 说明:
获取该群所有用户 id 及对应 好感度 获取该群所有用户 id 及对应 好感度
参数: 参数:
:param belonging_group: 群号 :param group_id: 群号
""" """
impression_list = [] impression_list = []
user_qq_list = [] user_qq_list = []
user_group = [] user_group = []
if belonging_group: if group_id:
query = cls.query.where(cls.belonging_group == belonging_group) query = cls.query.where(cls.group_id == group_id)
else: else:
query = cls.query query = cls.query
for user in await query.gino.all(): for user in await query.gino.all():
impression_list.append(user.impression) impression_list.append(user.impression)
user_qq_list.append(user.user_qq) user_qq_list.append(user.user_qq)
user_group.append(user.belonging_group) user_group.append(user.group_id)
return user_qq_list, impression_list, user_group return user_qq_list, impression_list, user_group
View File
Regular → Executable
View File
+43
View File
@@ -0,0 +1,43 @@
from nonebot import on_regex
from nonebot.rule import to_me
from pathlib import Path
__zx_plugin_name__ = "关于"
__plugin_usage__ = """
usage:
想要更加了解真寻吗
指令:
关于
""".strip()
__plugin_des__ = "想要更加了解真寻吗"
__plugin_cmd__ = ["关于"]
__plugin_version__ = 0.1
__plugin_type__ = ("其他",)
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 1,
"default_status": True,
"limit_superuser": False,
"cmd": ["关于"],
}
about = on_regex("^关于$", priority=5, block=True, rule=to_me())
@about.handle()
async def _():
ver_file = Path() / '__version__'
version = None
if ver_file.exists():
with open(ver_file, 'r', encoding='utf8') as f:
version = f.read().split(':')[-1].strip()
msg = f"""
『绪山真寻Bot』
版本:{version}
简介:基于Nonebot2与go-cqhttp开发,是一个非常可爱的Bot呀,希望与大家要好好相处
项目地址:https://github.com/HibiKier/zhenxun_bot
文档地址:https://hibikier.github.io/zhenxun_bot/
""".strip()
await about.send(msg)
Regular → Executable
+9 -10
View File
@@ -1,15 +1,14 @@
import random
from nonebot import on_keyword
import os
from utils.message_builder import image from utils.message_builder import image
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from nonebot import on_command from nonebot import on_command
from nonebot.rule import to_me from nonebot.rule import to_me
from nonebot.typing import T_State from nonebot.adapters.onebot.v11 import GroupMessageEvent
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.adapters.cqhttp.permission import GROUP
from utils.utils import FreqLimiter from utils.utils import FreqLimiter
from configs.config import NICKNAME from configs.config import NICKNAME
import random
from nonebot import on_keyword
import os
__zx_plugin_name__ = "基本设置 [Hidden]" __zx_plugin_name__ = "基本设置 [Hidden]"
@@ -25,12 +24,12 @@ config_play_game = on_keyword({"打游戏"}, permission=GROUP, priority=1, block
@config_play_game.handle() @config_play_game.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): async def _(event: GroupMessageEvent):
if not _flmt.check(event.group_id): if not _flmt.check(event.group_id):
return return
_flmt.start_cd(event.group_id) _flmt.start_cd(event.group_id)
await config_play_game.finish( await config_play_game.finish(
image(random.choice(os.listdir(IMAGE_PATH + "dayouxi/")), "dayouxi") image(random.choice(os.listdir(IMAGE_PATH / "dayouxi")), "dayouxi")
) )
@@ -40,7 +39,7 @@ self_introduction = on_command(
@self_introduction.handle() @self_introduction.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): async def _():
if NICKNAME.find('真寻') != -1: if NICKNAME.find('真寻') != -1:
result = ( result = (
"我叫绪山真寻\n" "我叫绪山真寻\n"
@@ -57,6 +56,6 @@ my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True)
@my_wife.handle() @my_wife.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): async def _():
await my_wife.finish(image("laopo.jpg", "other")) await my_wife.finish(image("laopo.jpg", "other"))
Regular → Executable
+18 -24
View File
@@ -1,17 +1,15 @@
from nonebot import on_message from nonebot import on_message
from nonebot.adapters.cqhttp import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
GroupMessageEvent, GroupMessageEvent,
Message, Message,
MessageEvent, MessageEvent,
) )
from nonebot.rule import to_me from nonebot.rule import to_me
from nonebot.typing import T_State
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 services.log import logger from services.log import logger
from utils.utils import get_message_text, get_message_imgs from utils.utils import get_message_img, get_message_text
from .data_source import get_chat_result, hello, no_result from .data_source import get_chat_result, hello, no_result
from configs.config import NICKNAME, Config from configs.config import NICKNAME, Config
@@ -21,42 +19,35 @@ usage:
与{NICKNAME}普普通通的对话吧! 与{NICKNAME}普普通通的对话吧!
""" """
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = 'HibiKier' __plugin_author__ = "HibiKier"
__plugin_settings__ = { __plugin_settings__ = {
"level": 5, "level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["Ai", "ai", "AI", "aI"], "cmd": ["Ai", "ai", "AI", "aI"],
} }
__plugin_configs__ = { __plugin_configs__ = {
"TL_KEY": { "TL_KEY": {"value": [], "help": "图灵Key"},
"value": [], "ALAPI_AI_CHECK": {"value": False, "help": "是否检测青云客骂娘回复", "default_value": False},
"help": "图灵Key" "TEXT_FILTER": {
"value": ["鸡", "口交"],
"help": "文本过滤器,将敏感词更改为*",
"default_value": [],
}, },
"ALAPI_AI_CHECK": {
"value": False,
"help": "是否检测青云客骂娘回复",
"default_value": False
}
} }
Config.add_plugin_config( Config.add_plugin_config(
"alapi", "alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token"
"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=8)
@ai.handle() @ai.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): async def _(bot: Bot, event: MessageEvent):
msg = get_message_text(event.json()) msg = get_message_text(event.json())
imgs = get_message_imgs(event.json()) img = get_message_img(event.json())
if "CQ:xml" in str(event.get_message()): if "CQ:xml" in str(event.get_message()):
return return
# 打招呼 # 打招呼
if (not msg and not imgs) or msg in [ if (not msg and not img) or msg in [
"你好啊", "你好啊",
"你好", "你好",
"在吗", "在吗",
@@ -67,7 +58,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
"在", "在",
]: ]:
await ai.finish(hello()) await ai.finish(hello())
img = imgs[0] if imgs else "" img = img[0] if img else ""
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname( nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id event.user_id, event.group_id
@@ -76,7 +67,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
nickname = await FriendUser.get_friend_nickname(event.user_id) nickname = await FriendUser.get_friend_nickname(event.user_id)
if not nickname: if not nickname:
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
nickname = event.sender.card if event.sender.card else event.sender.nickname nickname = event.sender.card or event.sender.nickname
else: else:
nickname = event.sender.nickname nickname = event.sender.nickname
result = await get_chat_result(msg, img, event.user_id, nickname) result = await get_chat_result(msg, img, event.user_id, nickname)
@@ -85,6 +76,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
f"问题:{msg} ---- 回答:{result}" f"问题:{msg} ---- 回答:{result}"
) )
if result: if result:
result = str(result)
for t in Config.get_config("ai", "TEXT_FILTER"):
result = result.replace(t, "*")
await ai.finish(Message(result)) await ai.finish(Message(result))
else: else:
await ai.finish(no_result()) await ai.finish(no_result())
Regular → Executable
+69 -68
View File
@@ -1,13 +1,12 @@
import os import os
import random import random
import re import re
from utils.http_utils import AsyncHttpx
import aiohttp
from aiohttp.client import ClientSession
from configs.path_config import IMAGE_PATH, DATA_PATH from configs.path_config import IMAGE_PATH, DATA_PATH
from services.log import logger from services.log import logger
from utils.message_builder import image, face from utils.message_builder import image, face
from configs.config import Config, NICKNAME from configs.config import Config, NICKNAME
from .utils import ai_message_manager
try: try:
import ujson as json import ujson as json
@@ -21,12 +20,12 @@ check_url = "https://v2.alapi.cn/api/censor/text"
index = 0 index = 0
anime_data = json.load(open(DATA_PATH + "anime.json", "r", encoding="utf8")) anime_data = json.load(open(DATA_PATH / "anime.json", "r", encoding="utf8"))
async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) -> str: async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) -> str:
""" """
获取 AI 返回值,顺序:图灵 -> 青云客 获取 AI 返回值,顺序: 特殊回复 -> 图灵 -> 青云客
:param text: 问题 :param text: 问题
:param img_url: 图片链接 :param img_url: 图片链接
:param user_id: 用户id :param user_id: 用户id
@@ -34,6 +33,11 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str)
:return: 回答 :return: 回答
""" """
global index global index
ai_message_manager.add_message(user_id, text)
special_rst = await ai_message_manager.get_result(user_id, nickname)
if special_rst:
ai_message_manager.add_result(user_id, special_rst)
return special_rst
if index == 5: if index == 5:
index = 0 index = 0
if len(text) < 6 and random.random() < 0.6: if len(text) < 6 and random.random() < 0.6:
@@ -41,10 +45,9 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str)
for key in keys: for key in keys:
if text.find(key) != -1: if text.find(key) != -1:
return random.choice(anime_data[key]).replace("你", nickname) return random.choice(anime_data[key]).replace("你", nickname)
async with aiohttp.ClientSession() as sess: rst = await tu_ling(text, img_url, user_id)
rst = await tu_ling(text, img_url, user_id, sess) if not rst:
if not rst: rst = await xie_ai(text)
rst = await xie_ai(text, sess)
if not rst: if not rst:
return no_result() return no_result()
if nickname: if nickname:
@@ -54,22 +57,25 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str)
if random.random() < 0.2: if random.random() < 0.2:
if nickname.find("大人") == -1: if nickname.find("大人") == -1:
nickname += "大~人~" nickname += "大~人~"
rst = rst.replace("小主人", nickname).replace("小朋友", nickname) rst = str(rst).replace("小主人", nickname).replace("小朋友", nickname)
ai_message_manager.add_result(user_id, rst)
return rst return rst
# 图灵接口 # 图灵接口
async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession) -> str: async def tu_ling(text: str, img_url: str, user_id: int) -> str:
""" """
获取图灵接口的回复 获取图灵接口的回复
:param text: 问题 :param text: 问题
:param img_url: 图片链接 :param img_url: 图片链接
:param user_id: 用户id :param user_id: 用户id
:param sess: AIOHTTP SESSION
:return: 图灵回复 :return: 图灵回复
""" """
global index global index
TL_KEY = Config.get_config("ai", "TL_KEY") TL_KEY = Config.get_config("ai", "TL_KEY")
req = None
if not TL_KEY:
return ""
try: try:
if text: if text:
req = { req = {
@@ -96,62 +102,59 @@ async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession) ->
index = 0 index = 0
return "" return ""
text = "" text = ""
async with sess.post(url, json=req) as response: response = await AsyncHttpx.post(url, json=req)
if response.status != 200: if response.status_code != 200:
return no_result() return no_result()
resp_payload = json.loads(await response.text()) resp_payload = json.loads(response.text)
if int(resp_payload["intent"]["code"]) in [4003]: if int(resp_payload["intent"]["code"]) in [4003]:
return "" return ""
if resp_payload["results"]: if resp_payload["results"]:
for result in resp_payload["results"]: for result in resp_payload["results"]:
if result["resultType"] == "text": if result["resultType"] == "text":
text = result["values"]["text"] text = result["values"]["text"]
if "请求次数超过" in text: if "请求次数超过" in text:
text = "" text = ""
return text return text
# 屑 AI # 屑 AI
async def xie_ai(text: str, sess: ClientSession) -> str: async def xie_ai(text: str) -> str:
""" """
获取青云客回复 获取青云客回复
:param text: 问题 :param text: 问题
:param sess: AIOHTTP SESSION
:return: 青云可回复 :return: 青云可回复
""" """
async with sess.get( res = await AsyncHttpx.get(f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}")
f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}" content = ""
) as res: data = json.loads(res.text)
content = "" if data["result"] == 0:
data = json.loads(await res.text()) content = data["content"]
if data["result"] == 0: if "菲菲" in content:
content = data["content"] content = content.replace("菲菲", NICKNAME)
if "菲菲" in content: if "艳儿" in content:
content = content.replace("菲菲", NICKNAME) content = content.replace("艳儿", NICKNAME)
if "艳儿" in content: if "公众号" in content:
content = content.replace("艳儿", NICKNAME) content = ""
if "公众号" in content: if "{br}" in content:
content = "" content = content.replace("{br}", "\n")
if "{br}" in content: if "提示" in content:
content = content.replace("{br}", "\n") content = content[: content.find("提示")]
if "提示" in content: if "淘宝" in content or "taobao.com" in content:
content = content[: content.find("提示")] return ""
if "淘宝" in content: while True:
return "" r = re.search("{face:(.*)}", content)
while True: if r:
r = re.search("{face:(.*)}", content) id_ = r.group(1)
if r: content = content.replace(
id_ = r.group(1) "{" + f"face:{id_}" + "}", str(face(int(id_)))
content = content.replace( )
"{" + f"face:{id_}" + "}", str(face(int(id_))) else:
) break
else: return (
break content
return ( if not content and not Config.get_config("ai", "ALAPI_AI_CHECK")
content else await check_text(content)
if not content and not Config.get_config("ai", "ALAPI_AI_CHECK") )
else await check_text(content, sess)
)
def hello() -> str: def hello() -> str:
@@ -167,7 +170,7 @@ def hello() -> str:
"呼呼,叫俺干嘛", "呼呼,叫俺干嘛",
) )
) )
img = random.choice(os.listdir(IMAGE_PATH + "zai/")) img = random.choice(os.listdir(IMAGE_PATH / "zai"))
if img[-4:] == ".gif": if img[-4:] == ".gif":
result += image(img, "zai") result += image(img, "zai")
else: else:
@@ -190,25 +193,23 @@ def no_result() -> str:
"我!不!知!道!", "我!不!知!道!",
] ]
) )
+ image(random.choice(os.listdir(IMAGE_PATH + "noresult/")), "noresult") + image(random.choice(os.listdir(IMAGE_PATH / "noresult")), "noresult")
) )
async def check_text(text: str, sess: ClientSession) -> str: async def check_text(text: str) -> str:
""" """
ALAPI文本检测,主要针对青云客API,检测为恶俗文本改为无回复的回答 ALAPI文本检测,主要针对青云客API,检测为恶俗文本改为无回复的回答
:param text: 回复 :param text: 回复
:param sess: AIOHTTP SESSION
""" """
if not Config.get_config("alapi", "ALAPI_TOKEN"): if not Config.get_config("alapi", "ALAPI_TOKEN"):
return text return text
params = {"token": Config.get_config("alapi", "ALAPI_TOKEN"), "text": text} params = {"token": Config.get_config("alapi", "ALAPI_TOKEN"), "text": text}
try: try:
async with sess.get(check_url, timeout=2, params=params) as response: data = (await AsyncHttpx.get(check_url, timeout=2, params=params)).json()
data = await response.json() if data["code"] == 200:
if data["code"] == 200: if data["data"]["conclusion_type"] == 2:
if data["data"]["conclusion_type"] == 2: return ""
return ""
except Exception as e: except Exception as e:
logger.error(f"检测违规文本错误...{type(e)}:{e}") logger.error(f"检测违规文本错误...{type(e)}:{e}")
return text return text
+140
View File
@@ -0,0 +1,140 @@
from utils.manager import StaticData
from configs.config import NICKNAME
from models.ban_user import BanUser
from typing import Optional
import random
import time
class AiMessageManager(StaticData):
def __init__(self):
super().__init__(None)
self._same_message = [
"为什么要发一样的话?",
"请不要再重复对我说一句话了,不然我就要生气了!",
"别再发这句话了,我已经知道了...",
"你是只会说这一句话吗?",
"[*],你发我也发!",
"[uname],[*]",
f"救命!有笨蛋一直给{NICKNAME}发一样的话!",
"这句话你已经给我发了{}次了,再发就生气!",
]
self._repeat_message = [
f"请不要学{NICKNAME}说话",
f"为什么要一直学{NICKNAME}说话?",
"你再学!你再学我就生气了!",
f"呜呜,你是想欺负{NICKNAME}嘛..",
"[uname]不要再学我说话了!",
"再学我说话,我就把你拉进黑名单(生气",
"你再学![uname]是个笨蛋!",
"你已经学我说话{}次了!别再学了!",
]
def add_message(self, user_id: int, message: str):
"""
添加用户消息
:param user_id: 用户id
:param message: 消息内容
"""
if message:
if self._data.get(user_id) is None:
self._data[user_id] = {
"time": time.time(),
"message": [],
"result": [],
"repeat_count": 0,
}
if time.time() - self._data[user_id]["time"] > 60 * 10:
self._data[user_id]["message"].clear()
self._data[user_id]["time"] = time.time()
self._data[user_id]["message"].append(message.strip())
def add_result(self, user_id: int, message: str):
"""
添加回复用户的消息
:param user_id: 用户id
:param message: 回复消息内容
"""
if message:
if self._data.get(user_id) is None:
self._data[user_id] = {
"time": time.time(),
"message": [],
"result": [],
"repeat_count": 0,
}
if time.time() - self._data[user_id]["time"] > 60 * 10:
self._data[user_id]["result"].clear()
self._data[user_id]["repeat_count"] = 0
self._data[user_id]["time"] = time.time()
self._data[user_id]["result"].append(message.strip())
async def get_result(self, user_id: int, nickname: str) -> Optional[str]:
"""
特殊消息特殊回复
:param user_id: 用户id
:param nickname: 用户昵称
"""
try:
if len(self._data[user_id]["message"]) < 2:
return None
except KeyError:
return None
msg = await self._get_user_repeat_message_result(user_id)
if not msg:
msg = await self._get_user_same_message_result(user_id)
if msg:
if "[uname]" in msg:
msg = msg.replace("[uname]", nickname)
if not msg.startswith("生气了!你好烦,闭嘴!") and "[*]" in msg:
msg = msg.replace("[*]", self._data[user_id]["message"][-1])
return msg
async def _get_user_same_message_result(self, user_id: int) -> Optional[str]:
"""
重复消息回复
:param user_id: 用户id
"""
msg = self._data[user_id]["message"][-1]
cnt = 0
_tmp = self._data[user_id]["message"][:-1]
_tmp.reverse()
for s in _tmp:
if s == msg:
cnt += 1
else:
break
if cnt > 1:
if random.random() < 0.5 and cnt > 3:
rand = random.randint(60, 300)
await BanUser.ban(user_id, 9, rand)
self._data[user_id]["message"].clear()
return f"生气了!你好烦,闭嘴!给我老实安静{rand}秒"
return random.choice(self._same_message).format(cnt)
return None
async def _get_user_repeat_message_result(self, user_id: int) -> Optional[str]:
"""
复读真寻的消息回复
:param user_id: 用户id
"""
msg = self._data[user_id]["message"][-1]
if self._data[user_id]["result"]:
rst = self._data[user_id]["result"][-1]
else:
return None
if msg == rst:
self._data[user_id]["repeat_count"] += 1
cnt = self._data[user_id]["repeat_count"]
if cnt > 1:
if random.random() < 0.5 and cnt > 3:
rand = random.randint(60, 300)
await BanUser.ban(user_id, 9, rand)
self._data[user_id]["result"].clear()
self._data[user_id]["repeat_count"] = 0
return f"生气了!你好烦,闭嘴!给我老实安静{rand}秒"
return random.choice(self._repeat_message).format(cnt)
return None
ai_message_manager = AiMessageManager()
Regular → Executable
+4 -1
View File
@@ -1,7 +1,6 @@
from configs.config import Config from configs.config import Config
import nonebot import nonebot
nonebot.load_plugins("plugins/alapi")
Config.add_plugin_config( Config.add_plugin_config(
"alapi", "alapi",
@@ -9,3 +8,7 @@ Config.add_plugin_config(
None, None,
help_="在https://admin.alapi.cn/user/login登录后获取token" help_="在https://admin.alapi.cn/user/login登录后获取token"
) )
nonebot.load_plugins("plugins/alapi")
+49
View File
@@ -0,0 +1,49 @@
from nonebot.adapters.onebot.v11 import MessageSegment
from utils.image_utils import BuildImage
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from typing import Optional, Tuple, Union
from configs.config import Config
from utils.http_utils import AsyncHttpx
async def get_data(url: str, params: Optional[dict] = None) -> Tuple[Union[dict, str], int]:
"""
获取ALAPI数据
:param url: 请求链接
:param params: 参数
"""
if not params:
params = {}
params["token"] = Config.get_config("alapi", "ALAPI_TOKEN")
try:
data = (await AsyncHttpx.get(url, params=params, timeout=5)).json()
if data["code"] == 200:
if not data["data"]:
return "没有搜索到...", 997
return data, 200
else:
return f'发生了错误...code:{data["code"]}', 999
except TimeoutError:
return "超时了....", 998
def gen_wbtop_pic(data: dict) -> MessageSegment:
"""
生成微博热搜图片
:param data: 微博热搜数据
"""
bk = 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())
Regular → Executable
+45 -46
View File
@@ -1,46 +1,45 @@
from nonebot import on_command from nonebot import on_regex
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from nonebot.typing import T_State from ._data_source import get_data
from .data_source import get_data from services.log import logger
from services.log import logger
__zx_plugin_name__ = "网易云热评"
__zx_plugin_name__ = "网易云热评" __plugin_usage__ = """
__plugin_usage__ = """ usage:
usage: 到点了,还是防不了下塔
到点了,还是防不了下塔 指令:
指令: 网易云热评/到点了/12点了
网易云热评/到点了/12点了 """.strip()
""".strip() __plugin_des__ = "生了个人,我很抱歉"
__plugin_des__ = "生了个人,我很抱歉" __plugin_cmd__ = ["网易云热评", "到点了", "12点了"]
__plugin_cmd__ = ["网易云热评", "到点了", "12点了"] __plugin_version__ = 0.1
__plugin_version__ = 0.1 __plugin_author__ = "HibiKier"
__plugin_author__ = "HibiKier" __plugin_settings__ = {
__plugin_settings__ = { "level": 5,
"level": 5, "default_status": True,
"default_status": True, "limit_superuser": False,
"limit_superuser": False, "cmd": ["网易云热评", "网易云评论", "到点了", "12点了"],
"cmd": ["网易云热评", "网易云评论", "到点了", "12点了"], }
}
comments_163 = on_regex(
comments_163 = on_command( "^(网易云热评|网易云评论|到点了|12点了)$", priority=5, block=True
"网易云热评", aliases={"网易云评论", "到点了", "12点了"}, priority=5, block=True )
)
comments_163_url = "https://v2.alapi.cn/api/comment"
comments_163_url = "https://v2.alapi.cn/api/comment"
@comments_163.handle()
@comments_163.handle() async def _(event: MessageEvent):
async def _(bot: Bot, event: MessageEvent, state: T_State): data, code = await get_data(comments_163_url)
data, code = await get_data(comments_163_url) if code != 200:
if code != 200: await comments_163.finish(data, at_sender=True)
await comments_163.finish(data, at_sender=True) data = data["data"]
data = data["data"] comment = data["comment_content"]
comment = data["comment_content"] song_name = data["title"]
song_name = data["title"] await comments_163.send(f"{comment}\n\t——《{song_name}》")
await comments_163.send(f"{comment}\n\t——《{song_name}》") logger.info(
logger.info( f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f" 发送网易云热评: {comment} \n\t\t————{song_name}"
f" 发送网易云热评: {comment} \n\t\t————{song_name}" )
)
Regular → Executable
+47 -48
View File
@@ -1,48 +1,47 @@
from nonebot import on_command from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent
from nonebot.typing import T_State from utils.message_builder import image
from utils.message_builder import image from nonebot.params import CommandArg
from utils.utils import get_message_text from ._data_source import get_data
from .data_source import get_data from services.log import logger
from services.log import logger
__zx_plugin_name__ = "b封面"
__zx_plugin_name__ = "b封面" __plugin_usage__ = """
__plugin_usage__ = """ usage:
usage: b封面 [链接/av/bv/cv/直播id]
b封面 [链接/av/bv/cv/直播id] 示例:b封面 av86863038
示例:b封面 av86863038 """.strip()
""".strip() __plugin_des__ = "快捷的b站视频封面获取方式"
__plugin_des__ = "快捷的b站视频封面获取方式" __plugin_cmd__ = ["b封面/B封面"]
__plugin_cmd__ = ["b封面/B封面"] __plugin_type__ = ("一些工具",)
__plugin_type__ = ("一些工具",) __plugin_version__ = 0.1
__plugin_version__ = 0.1 __plugin_author__ = "HibiKier"
__plugin_author__ = "HibiKier" __plugin_settings__ = {
__plugin_settings__ = { "level": 5,
"level": 5, "default_status": True,
"default_status": True, "limit_superuser": False,
"limit_superuser": False, "cmd": ["b封面", "B封面"],
"cmd": ["b封面", "B封面"], }
}
cover = on_command("b封面", aliases={"B封面"}, priority=5, block=True)
cover = on_command("b封面", aliases={"B封面"}, priority=5, block=True)
cover_url = "https://v2.alapi.cn/api/bilibili/cover"
cover_url = "https://v2.alapi.cn/api/bilibili/cover"
@cover.handle()
@cover.handle() async def _(event: MessageEvent, arg: Message = CommandArg()):
async def _(bot: Bot, event: MessageEvent, state: T_State): msg = arg.extract_plain_text().strip()
msg = get_message_text(event.json()) params = {"c": msg}
params = {"c": msg} data, code = await get_data(cover_url, params)
data, code = await get_data(cover_url, params) if code != 200:
if code != 200: await cover.finish(data, at_sender=True)
await cover.finish(data, at_sender=True) data = data["data"]
data = data["data"] title = data["title"]
title = data["title"] img = data["cover"]
img = data["cover"] await cover.send(Message(f"title:{title}\n{image(img)}"))
await cover.send(Message(f"title:{title}\n{image(img)}")) logger.info(
logger.info( f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f" 获取b站封面: {title} url:{img}"
f" 获取b站封面: {title} url:{img}" )
)
-51
View File
@@ -1,51 +0,0 @@
from nonebot.adapters.cqhttp import MessageSegment
from utils.image_utils import CreateImg
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from typing import Optional
from configs.config import Config
import aiohttp
async def get_data(url: str, params: Optional[dict] = None) -> "Union[dict, str], int":
"""
获取ALAPI数据
:param url: 请求链接
:param params: 参数
"""
if not params:
params = {}
params["token"] = Config.get_config("alapi", "ALAPI_TOKEN")
async with aiohttp.ClientSession() as session:
try:
async with session.get(url, timeout=2, params=params) as response:
data = await response.json()
if data["code"] == 200:
if not data["data"]:
return "没有搜索到...", 997
return data, 200
else:
return f'发生了错误...code:{data["code"]}', 999
except TimeoutError:
return "超时了....", 998
def gen_wbtop_pic(data: dict) -> MessageSegment:
"""
生成微博热搜图片
:param data: 微博热搜数据
"""
bk = CreateImg(700, 32 * 50 + 280, 700, 32, color="#797979")
wbtop_bk = CreateImg(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
bk.paste(wbtop_bk)
text_bk = CreateImg(700, 32 * 50, 700, 32, color="#797979")
for i, data in enumerate(data):
title = f"{i+1}. {data['hot_word']}"
hot = data["hot_word_num"]
img = CreateImg(700, 30, font_size=20)
w, h = img.getsize(title)
img.text((10, int((30 - h) / 2)), title)
img.text((580, int((30 - h) / 2)), hot)
text_bk.paste(img)
bk.paste(text_bk, (0, 280))
return image(b64=bk.pic2bs4())
+45
View File
@@ -0,0 +1,45 @@
from nonebot import on_regex
from services.log import logger
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from ._data_source import get_data
__zx_plugin_name__ = "鸡汤"
__plugin_usage__ = """
usage:
不喝点什么感觉有点不舒服
指令:
鸡汤
""".strip()
__plugin_des__ = "喏,亲手为你煮的鸡汤"
__plugin_cmd__ = ["鸡汤"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["鸡汤", "毒鸡汤"],
}
url = "https://v2.alapi.cn/api/soul"
jitang = on_regex("^毒?鸡汤$", priority=5, block=True)
@jitang.handle()
async def _(event: MessageEvent):
try:
data, code = await get_data(url)
if code != 200:
await jitang.finish(data, at_sender=True)
await jitang.send(data["data"]["content"])
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送鸡汤:" + data["data"]["content"]
)
except Exception as e:
await jitang.send("鸡汤煮坏掉了...")
logger.error(f"鸡汤煮坏掉了 {type(e)}:{e}")
Regular → Executable
+41 -42
View File
@@ -1,42 +1,41 @@
from nonebot import on_command from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from nonebot.typing import T_State from services.log import logger
from services.log import logger from ._data_source import get_data
from .data_source import get_data
__zx_plugin_name__ = "古诗"
__zx_plugin_name__ = "古诗" __plugin_usage__ = """usage:
__plugin_usage__ = """usage: 平白无故念首诗
平白无故念首诗 示例:念诗/来首诗/念首诗
示例:念诗/来首诗/念首诗 """
""" __plugin_des__ = "为什么突然文艺起来了!"
__plugin_des__ = "为什么突然文艺起来了!" __plugin_cmd__ = ["念诗/来首诗/念首诗"]
__plugin_cmd__ = ["念诗/来首诗/念首诗"] __plugin_version__ = 0.1
__plugin_version__ = 0.1 __plugin_author__ = "HibiKier"
__plugin_author__ = "HibiKier" __plugin_settings__ = {
__plugin_settings__ = { "level": 5,
"level": 5, "default_status": True,
"default_status": True, "limit_superuser": False,
"limit_superuser": False, "cmd": ["念诗", "来首诗", "念首诗"],
"cmd": ["念诗", "来首诗", "念首诗"], }
}
poetry = on_command("念诗", aliases={"来首诗", "念首诗"}, priority=5, block=True)
poetry = on_command("念诗", aliases={"来首诗", "念首诗"}, priority=5, block=True)
poetry_url = "https://v2.alapi.cn/api/shici"
poetry_url = "https://v2.alapi.cn/api/shici"
@poetry.handle()
@poetry.handle() async def _(event: MessageEvent):
async def _(bot: Bot, event: MessageEvent, state: T_State): data, code = await get_data(poetry_url)
data, code = await get_data(poetry_url) if code != 200:
if code != 200: await poetry.finish(data, at_sender=True)
await poetry.finish(data, at_sender=True) data = data["data"]
data = data["data"] content = data["content"]
content = data["content"] title = data["origin"]
title = data["origin"] author = data["author"]
author = data["author"] await poetry.send(f"{content}\n\t——{author}《{title}》")
await poetry.send(f"{content}\n\t——{author}《{title}》") logger.info(
logger.info( f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f" 发送古诗: f'{content}\n\t--{author}《{title}》'"
f" 发送古诗: f'{content}\n\t--{author}《{title}》'" )
)
Regular → Executable
+70 -76
View File
@@ -1,76 +1,70 @@
from nonebot import on_command from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
from nonebot.typing import T_State from nonebot.params import CommandArg
from services.log import logger from services.log import logger
from .data_source import get_data, gen_wbtop_pic from ._data_source import get_data, gen_wbtop_pic
from utils.browser import get_browser from utils.utils import is_number
from utils.utils import get_message_text, is_number from configs.path_config import IMAGE_PATH
from configs.path_config import IMAGE_PATH from utils.http_utils import AsyncPlaywright
from utils.message_builder import image import asyncio
import asyncio
__zx_plugin_name__ = "微博热搜"
__zx_plugin_name__ = '微博热搜' __plugin_usage__ = """
__plugin_usage__ = """ usage:
usage: 在QQ上吃个瓜
在QQ上吃个瓜 指令:
指令: 微博热搜:发送实时热搜
微博热搜:发送实时热搜 微博热搜 [id]:截图该热搜页面
微博热搜 [id]:截图该热搜页面 示例:微博热搜 5
示例:微博热搜 5 """.strip()
""".strip() __plugin_des__ = "刚买完瓜,在吃瓜现场"
__plugin_des__ = '刚买完瓜,在吃瓜现场' __plugin_cmd__ = ["微博热搜", "微博热搜 [id]"]
__plugin_cmd__ = ['微博热搜', '微博热搜 [id]'] __plugin_version__ = 0.1
__plugin_version__ = 0.1 __plugin_author__ = "HibiKier"
__plugin_author__ = 'HibiKier' __plugin_settings__ = {
__plugin_settings__ = { "level": 5,
"level": 5, "default_status": True,
"default_status": True, "limit_superuser": False,
"limit_superuser": False, "cmd": ["微博热搜"],
"cmd": ['微博热搜'], }
}
wbtop = on_command("wbtop", aliases={"微博热搜"}, priority=5, block=True)
wbtop = on_command("wbtop", aliases={'微博热搜'}, priority=5, block=True)
wbtop_url = "https://v2.alapi.cn/api/new/wbtop"
wbtop_url = 'https://v2.alapi.cn/api/new/wbtop'
wbtop_data = []
wbtop_data = []
@wbtop.handle()
@wbtop.handle() async def _(event: MessageEvent, arg: Message = CommandArg()):
async def _(bot: Bot, event: MessageEvent, state: T_State): global wbtop_data
global wbtop_data msg = arg.extract_plain_text().strip()
msg = get_message_text(event.json()) if not wbtop_data or not msg:
if not wbtop_data or not msg: data, code = await get_data(wbtop_url)
data, code = await get_data(wbtop_url) if code != 200:
if code != 200: await wbtop.finish(data, at_sender=True)
await wbtop.finish(data, at_sender=True) wbtop_data = data["data"]
wbtop_data = data['data'] if not msg:
if not msg: img = await asyncio.get_event_loop().run_in_executor(
img = await asyncio.get_event_loop().run_in_executor(None, gen_wbtop_pic, wbtop_data) None, gen_wbtop_pic, wbtop_data
await wbtop.send(img) )
logger.info( await wbtop.send(img)
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" logger.info(
f" 查询微博热搜") f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
if is_number(msg) and 0 < int(msg) <= 50: f" 查询微博热搜"
url = wbtop_data[int(msg) - 1]['url'] )
browser = await get_browser() if is_number(msg) and 0 < int(msg) <= 50:
page = None url = wbtop_data[int(msg) - 1]["url"]
try: await wbtop.send("开始截取数据...")
if not browser: img = await AsyncPlaywright.screenshot(
logger.warning('获取 browser 失败,请部署至 linux 环境....') url,
await wbtop.finish('获取 browser 对象失败...') f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png",
page = await browser.new_page() "#pl_feedlist_index",
await page.goto(url, wait_until='networkidle', timeout=10000) wait_time=5
await page.set_viewport_size({"width": 2560, "height": 1080}) )
await asyncio.sleep(5) if img:
div = await page.query_selector("#pl_feedlist_index") await wbtop.send(img)
await div.screenshot(path=f'{IMAGE_PATH}/temp/wbtop_{event.user_id}.png', timeout=100000) else:
await page.close() await wbtop.send("发生了一些错误.....")
await wbtop.send(image(f'wbtop_{event.user_id}.png', 'temp'))
except Exception as e:
logger.error(f'微博热搜截图出错... {type(e)}: {e}')
if page:
await page.close()
await wbtop.send('发生了一些错误.....')
Regular → Executable
+241 -235
View File
@@ -1,235 +1,241 @@
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.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from .data_source import ( from .data_source import (
add_live_sub, add_live_sub,
delete_sub, delete_sub,
add_up_sub, add_up_sub,
add_season_sub, add_season_sub,
get_media_id, get_media_id,
get_sub_status, get_sub_status,
SubManager, SubManager,
BilibiliSub BilibiliSub,
) )
from models.level_user import LevelUser from models.level_user import LevelUser
from configs.config import Config from configs.config import Config
from utils.utils import get_message_text, is_number, scheduler, get_bot from utils.utils import is_number, scheduler, get_bot
from typing import Optional from typing import Optional
from services.log import logger from services.log import logger
from nonebot import Driver from nonebot import Driver
import nonebot from nonebot.params import CommandArg, ArgStr
import nonebot
__zx_plugin_name__ = "B站订阅"
__plugin_usage__ = """ __zx_plugin_name__ = "B站订阅"
usage: __plugin_usage__ = """
B站直播,番剧,UP动态开播等提醒 usage:
主播订阅相当于 直播间订阅 + UP订阅 B站直播,番剧,UP动态开播等提醒
指令:[示例Id乱打的,仅做示例] 主播订阅相当于 直播间订阅 + UP订阅
添加订阅 ['主播'/'UP'/'番剧'] [id/链接/番名] 指令:[示例Id乱打的,仅做示例]
删除订阅 [id] 添加订阅 ['主播'/'UP'/'番剧'] [id/链接/番名]
查看订阅 删除订阅 [id]
示例:添加订阅主播 2345344 <-(直播房间id) 查看订阅
示例:添加订阅UP 2355543 <-(个人主页id) 示例:添加订阅主播 2345344 <-(直播房间id)
示例:添加订阅番剧 史莱姆 <-(支持模糊搜索) 示例:添加订阅UP 2355543 <-(个人主页id)
示例:添加订阅番剧 125344 <-(番剧id) 示例:添加订阅番剧 史莱姆 <-(支持模糊搜索)
示例:删除订阅 2324344 <-(任意id,通过查看订阅获取) 示例:添加订阅番剧 125344 <-(番剧id)
""".strip() 示例:删除订阅 2324344 <-(任意id,通过查看订阅获取)
__plugin_des__ = "非常便利的B站订阅通知" """.strip()
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"] __plugin_des__ = "非常便利的B站订阅通知"
__plugin_version__ = 0.1 __plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"]
__plugin_author__ = "HibiKier" __plugin_version__ = 0.1
__plugin_settings__ = { __plugin_author__ = "HibiKier"
"level": 5, __plugin_settings__ = {
"default_status": True, "level": 5,
"limit_superuser": False, "default_status": True,
"cmd": ["B站订阅", "b站订阅", "添加订阅", "删除订阅", "查看订阅"], "limit_superuser": False,
} "cmd": ["B站订阅", "b站订阅", "添加订阅", "删除订阅", "查看订阅"],
__plugin_configs__ = { }
"GROUP_BILIBILI_SUB_LEVEL": { __plugin_configs__ = {
"value": 5, "GROUP_BILIBILI_SUB_LEVEL": {
"help": "群内bilibili订阅需要管理的权限", "value": 5,
"default_value": 5, "help": "群内bilibili订阅需要管理的权限",
} "default_value": 5,
} }
}
add_sub = on_command("添加订阅", priority=5, block=True)
del_sub = on_command("删除订阅", priority=5, block=True) add_sub = on_command("添加订阅", priority=5, block=True)
show_sub_info = on_command("查看订阅", priority=5, block=True) del_sub = on_command("删除订阅", priority=5, block=True)
show_sub_info = on_command("查看订阅", priority=5, block=True)
driver: Driver = nonebot.get_driver()
driver: Driver = nonebot.get_driver()
sub_manager: Optional[SubManager] = None
sub_manager: Optional[SubManager] = None
@driver.on_startup
async def _(): @driver.on_startup
global sub_manager async def _():
sub_manager = SubManager() global sub_manager
sub_manager = SubManager()
@add_sub.args_parser
async def _(bot: Bot, event: MessageEvent, state: T_State): @add_sub.handle()
season_data = state["season_data"] async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()):
msg = get_message_text(event.json()) msg = arg.extract_plain_text().strip().split()
if not is_number(msg) or int(msg) < 1 or int(msg) > len(season_data): if len(msg) < 2:
await add_sub.reject("Id必须为数字且在范围内!请重新输入...") await add_sub.finish("参数不完全,请查看订阅帮助...")
state["id"] = season_data[int(msg) - 1]["media_id"] sub_type = msg[0]
id_ = ""
if isinstance(event, GroupMessageEvent):
@add_sub.handle() if not await LevelUser.check_level(
async def _(bot: Bot, event: MessageEvent, state: T_State): event.user_id,
msg = get_message_text(event.json()).split() event.group_id,
if len(msg) < 2: Config.get_config("bilibili_sub", "GROUP_BILIBILI_SUB_LEVEL"),
await add_sub.finish("参数不完全,请查看订阅帮助...") ):
sub_type = msg[0] await add_sub.finish(
id_ = "" f"您的权限不足,群内订阅的需要 {Config.get_config('bilibili_sub', 'GROUP_BILIBILI_SUB_LEVEL')} 级权限..",
if isinstance(event, GroupMessageEvent): at_sender=True,
if not await LevelUser.check_level( )
event.user_id, sub_user = f"{event.user_id}:{event.group_id}"
event.group_id, else:
Config.get_config("bilibili_sub", "GROUP_BILIBILI_SUB_LEVEL"), sub_user = f"{event.user_id}"
): state["sub_type"] = sub_type
await add_sub.finish( state["sub_user"] = sub_user
f"您的权限不足,群内订阅的需要 {Config.get_config('bilibili_sub', 'GROUP_BILIBILI_SUB_LEVEL')} 级权限..", if len(msg) > 1:
at_sender=True, if "http" in msg[1]:
) msg[1] = msg[1].split("?")[0]
sub_user = f"{event.user_id}:{event.group_id}" msg[1] = msg[1][:-1] if msg[1][-1] == "/" else msg[1]
else: msg[1] = msg[1].split("/")[-1]
sub_user = f"{event.user_id}" id_ = msg[1][2:] if msg[1].startswith("md") else msg[1]
state["sub_type"] = sub_type if not is_number(id_):
state["sub_user"] = sub_user if sub_type in ["season", "动漫", "番剧"]:
if len(msg) > 1: rst = "*以为您找到以下番剧,请输入Id选择:*\n"
if "http" in msg[1]: state["season_data"] = await get_media_id(id_)
msg[1] = msg[1].split("?")[0] if len(state["season_data"]) == 0:
msg[1] = msg[1][:-1] if msg[1][-1] == "/" else msg[1] await add_sub.finish(f"未找到番剧:{msg}")
msg[1] = msg[1].split("/")[-1] for i, x in enumerate(state["season_data"]):
id_ = msg[1][2:] if msg[1].startswith("md") else msg[1] rst += f'{i + 1}.{state["season_data"][x]["title"]}\n----------\n'
if not is_number(id_): await add_sub.send("\n".join(rst.split("\n")[:-1]))
if sub_type in ["season", "动漫", "番剧"]: else:
rst = "*以为您找到以下番剧,请输入Id选择:*\n" await add_sub.finish("Id 必须为全数字!")
state["season_data"] = await get_media_id(id_) else:
if len(state["season_data"]) == 0: state["id"] = int(id_)
await add_sub.finish(f"未找到番剧:{msg}")
for i, x in enumerate(state["season_data"]):
rst += f'{i + 1}.{state["season_data"][x]["title"]}\n----------\n' @add_sub.got("sub_type")
await add_sub.send("\n".join(rst.split("\n")[:-1])) @add_sub.got("sub_user")
else: @add_sub.got("id")
await add_sub.finish("Id 必须为全数字!") async def _(
else: event: MessageEvent,
state["id"] = int(id_) state: T_State,
id_: str = ArgStr("id"),
sub_type: str = ArgStr("sub_type"),
@add_sub.got("id") sub_user: str = ArgStr("sub_user"),
async def _(bot: Bot, event: MessageEvent, state: T_State): ):
sub_type = state["sub_type"] if sub_type in ["season", "动漫", "番剧"] and state.get("season_data"):
sub_user = state["sub_user"] season_data = state["season_data"]
id_ = state["id"] if not is_number(id_) or int(id_) < 1 or int(id_) > len(season_data):
if sub_type in ["主播", "直播"]: await add_sub.reject_arg("id", "Id必须为数字且在范围内!请重新输入...")
await add_sub.send(await add_live_sub(id_, sub_user)) id_ = season_data[int(id_) - 1]["media_id"]
elif sub_type.lower() in ["up", "用户"]: id_ = int(id_)
await add_sub.send(await add_up_sub(id_, sub_user)) if sub_type in ["主播", "直播"]:
elif sub_type in ["season", "动漫", "番剧"]: await add_sub.send(await add_live_sub(id_, sub_user))
await add_sub.send(await add_season_sub(id_, sub_user)) elif sub_type.lower() in ["up", "用户"]:
else: await add_sub.send(await add_up_sub(id_, sub_user))
await add_sub.finish("参数错误,第一参数必须为:主播/up/番剧!") elif sub_type in ["season", "动漫", "番剧"]:
logger.info( await add_sub.send(await add_season_sub(id_, sub_user))
f"(USER {event.user_id}, GROUP " else:
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" await add_sub.finish("参数错误,第一参数必须为:主播/up/番剧!")
f" 添加订阅:{sub_type} -> {sub_user} -> {id_}" logger.info(
) f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 添加订阅:{sub_type} -> {sub_user} -> {id_}"
@del_sub.handle() )
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if not is_number(msg): @del_sub.handle()
await del_sub.finish("Id必须为数字!", at_sender=True) async def _(event: MessageEvent, arg: Message = CommandArg()):
id_ = ( msg = arg.extract_plain_text().strip()
f"{event.user_id}:{event.group_id}" if not is_number(msg):
if isinstance(event, GroupMessageEvent) await del_sub.finish("Id必须为数字!", at_sender=True)
else f"{event.user_id}" id_ = (
) f"{event.user_id}:{event.group_id}"
if await BilibiliSub.delete_bilibili_sub(int(msg), id_): if isinstance(event, GroupMessageEvent)
await del_sub.send(f"删除订阅id:{msg} 成功...") else f"{event.user_id}"
logger.info( )
f"(USER {event.user_id}, GROUP " if await BilibiliSub.delete_bilibili_sub(int(msg), id_):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" await del_sub.send(f"删除订阅id:{msg} 成功...")
f" 删除订阅 {id_}" logger.info(
) f"(USER {event.user_id}, GROUP "
else: f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
await del_sub.send(f"删除订阅id:{msg} 失败...") f" 删除订阅 {id_}"
)
else:
@show_sub_info.handle() await del_sub.send(f"删除订阅id:{msg} 失败...")
async def _(bot: Bot, event: MessageEvent, state: T_State):
id_ = (
f"{event.user_id}:{event.group_id}" @show_sub_info.handle()
if isinstance(event, GroupMessageEvent) async def _(event: MessageEvent):
else f"{event.user_id}" if isinstance(event, GroupMessageEvent):
) id_ = f"{event.group_id}"
data = await BilibiliSub.get_sub_data(id_) else:
live_rst = "" id_ = f"{event.user_id}"
up_rst = "" data = await BilibiliSub.get_sub_data(id_)
season_rst = "" live_rst = ""
for x in data: up_rst = ""
if x.sub_type == "live": season_rst = ""
live_rst += ( for x in data:
f"\t直播间id:{x.sub_id}\n" f"\t名称:{x.uname}\n" f"------------------\n" if x.sub_type == "live":
) live_rst += (
if x.sub_type == "up": f"\t直播间id:{x.sub_id}\n" f"\t名称:{x.uname}\n" f"------------------\n"
up_rst += f"\tUP:{x.uname}\n" f"\tuid:{x.uid}\n" f"------------------\n" )
if x.sub_type == "season": if x.sub_type == "up":
season_rst += ( up_rst += f"\tUP:{x.uname}\n" f"\tuid:{x.uid}\n" f"------------------\n"
f"\t番名:{x.season_name}\n" if x.sub_type == "season":
f"\t当前集数:{x.season_current_episode}\n" season_rst += (
f"------------------\n" f"\t番剧id:{x.sub_id}\n"
) f"\t番名:{x.season_name}\n"
live_rst = "当前订阅的直播:\n" + live_rst if live_rst else live_rst f"\t当前集数:{x.season_current_episode}\n"
up_rst = "当前订阅的UP:\n" + up_rst if up_rst else up_rst f"------------------\n"
season_rst = "当前订阅的番剧:\n" + season_rst if season_rst else season_rst )
if not live_rst and not up_rst and not season_rst: live_rst = "当前订阅的直播:\n" + live_rst if live_rst else live_rst
live_rst = "您目前没有任何订阅..." up_rst = "当前订阅的UP:\n" + up_rst if up_rst else up_rst
await show_sub_info.send(live_rst + up_rst + season_rst) season_rst = "当前订阅的番剧:\n" + season_rst if season_rst else season_rst
if not live_rst and not up_rst and not season_rst:
live_rst = (
# 推送 "该群目前没有任何订阅..." if isinstance(event, GroupMessageEvent) else "您目前没有任何订阅..."
@scheduler.scheduled_job( )
"interval", await show_sub_info.send(live_rst + up_rst + season_rst)
seconds=30,
)
async def _(): # 推送
bot = get_bot() @scheduler.scheduled_job(
sub = None "interval",
if bot: seconds=30,
try: )
await sub_manager.reload_sub_data() async def _():
sub = await sub_manager.random_sub_data() bot = get_bot()
if sub: sub = None
rst = await get_sub_status(sub.sub_id, sub.sub_type) if bot:
await send_sub_msg(rst, sub, bot) try:
if sub.sub_type == "live": await sub_manager.reload_sub_data()
rst = await get_sub_status(sub.sub_id, "up") sub = await sub_manager.random_sub_data()
await send_sub_msg(rst, sub, bot) if sub:
except Exception as e: logger.debug(f"Bilibili订阅开始检测:{sub.sub_id}")
logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id if sub else 0} {type(e)}:{e}") rst = await get_sub_status(sub.sub_id, sub.sub_type)
await send_sub_msg(rst, sub, bot)
if sub.sub_type == "live":
async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot): rst = await get_sub_status(sub.sub_id, "up")
""" await send_sub_msg(rst, sub, bot)
推送信息 except Exception as e:
:param rst: 回复 logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id if sub else 0} {type(e)}:{e}")
:param sub: BilibiliSub
:param bot: Bot
""" async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
if rst: """
for x in sub.sub_users.split(",")[:-1]: 推送信息
try: :param rst: 回复
if ":" in x: :param sub: BilibiliSub
await bot.send_group_msg( :param bot: Bot
group_id=int(x.split(":")[1]), message=Message(rst) """
) if rst:
else: for x in sub.sub_users.split(",")[:-1]:
await bot.send_private_msg(user_id=int(x), message=Message(rst)) try:
except Exception as e: if ":" in x:
logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id} {type(e)}:{e}") await bot.send_group_msg(
group_id=int(x.split(":")[1]), message=Message(rst)
)
else:
await bot.send_private_msg(user_id=int(x), message=Message(rst))
except Exception as e:
logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id} {type(e)}:{e}")
+400 -394
View File
@@ -1,394 +1,400 @@
from bilibili_api.exceptions.ResponseCodeException import ResponseCodeException from bilibili_api.exceptions.ResponseCodeException import ResponseCodeException
from utils.manager import resources_manager from utils.manager import resources_manager
from asyncio.exceptions import TimeoutError from asyncio.exceptions import TimeoutError
from .model import BilibiliSub from .model import BilibiliSub
from bilibili_api.live import LiveRoom from bilibili_api.live import LiveRoom
from bilibili_api import bangumi from bilibili_api import bangumi
from utils.message_builder import image from utils.message_builder import image
from bilibili_api.user import User from bilibili_api.user import User
from bilibili_api import user from bilibili_api import user
from typing import Optional from typing import Optional
from pathlib import Path 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 from services.db_context import db
from services.db_context import db from services.log import logger
from services.log import logger from utils.http_utils import AsyncHttpx
import aiohttp import random
import random
bilibili_search_url = "https://api.bilibili.com/x/web-interface/search/all/v2"
bilibili_search_url = "https://api.bilibili.com/x/web-interface/search/all/v2"
dynamic_path = IMAGE_PATH / "bilibili_sub" / "dynamic"
dynamic_path = Path(IMAGE_PATH) / "bilibili_sub" / "dynamic" dynamic_path.mkdir(exist_ok=True, parents=True)
dynamic_path.mkdir(exist_ok=True, parents=True)
resources_manager.add_temp_dir(dynamic_path)
resources_manager.add_temp_dir(dynamic_path)
async def add_live_sub(live_id: int, sub_user: str) -> str:
async def add_live_sub(live_id: int, sub_user: str) -> str: """
""" 添加直播订阅
添加直播订阅 :param live_id: 直播房间号
:param live_id: 直播房间号 :param sub_user: 订阅用户 id # 7384933:private or 7384933:2342344(group)
:param sub_user: 订阅用户 id # 7384933:private or 7384933:2342344(group) :return:
:return: """
""" try:
try: async with db.transaction():
async with db.transaction(): try:
try: live = LiveRoom(live_id)
live = LiveRoom(live_id) live_info = (await live.get_room_info())["room_info"]
live_info = (await live.get_room_info())["room_info"] except ResponseCodeException:
except ResponseCodeException: 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"] short_id = live_info["short_id"]
short_id = live_info["short_id"] title = live_info["title"]
title = live_info["title"] live_status = live_info["live_status"]
live_status = live_info["live_status"] if await BilibiliSub.add_bilibili_sub(
if await BilibiliSub.add_bilibili_sub( room_id,
room_id, "live",
"live", sub_user,
sub_user, uid=uid,
uid=uid, live_short_id=short_id,
live_short_id=short_id, live_status=live_status,
live_status=live_status, ):
): await _get_up_status(live_id)
await _get_up_status(live_id) uname = (await BilibiliSub.get_sub(live_id)).uname
uname = (await BilibiliSub.get_sub(live_id)).uname return (
return ( "已成功订阅主播:\n"
"已成功订阅主播:\n" f"\ttitle:{title}\n"
f"\ttitle:{title}\n" f"\tname: {uname}\n"
f"\tname: {uname}\n" f"\tlive_id:{live_id}\n"
f"\tlive_id:{live_id}\n" f"\tuid:{uid}"
f"\tuid:{uid}" )
) else:
else: return "添加订阅失败..."
return "添加订阅失败..." except Exception as e:
except Exception as e: logger.error(f"订阅主播live_id:{live_id} 发生了错误 {type(e)}:{e}")
logger.error(f"订阅主播live_id:{live_id} 发生了错误 {type(e)}:{e}") return "添加订阅失败..."
return "添加订阅失败..."
async def add_up_sub(uid: int, sub_user: str) -> str:
async def add_up_sub(uid: int, sub_user: str) -> str: """
""" 添加订阅 UP
添加订阅 UP :param uid: UP uid
:param uid: UP uid :param sub_user: 订阅用户
:param sub_user: 订阅用户 """
""" try:
try: async with db.transaction():
async with db.transaction(): try:
try: u = user.User(uid)
u = user.User(uid) user_info = await u.get_user_info()
user_info = await u.get_user_info() except ResponseCodeException:
except ResponseCodeException: 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)
dynamic_info = await u.get_dynamics(0) 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()
video_info = await u.get_videos() 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"] if await BilibiliSub.add_bilibili_sub(
if await BilibiliSub.add_bilibili_sub( uid,
uid, "up",
"up", sub_user,
sub_user, uid=uid,
uid=uid, uname=uname,
uname=uname, dynamic_upload_time=dynamic_upload_time,
dynamic_upload_time=dynamic_upload_time, latest_video_created=latest_video_created,
latest_video_created=latest_video_created, ):
): return "已成功订阅UP:\n" f"\tname: {uname}\n" f"\tuid:{uid}"
return "已成功订阅UP:\n" f"\tname: {uname}\n" f"\tuid:{uid}" else:
else: return "添加订阅失败..."
return "添加订阅失败..." except Exception as e:
except Exception as e: logger.error(f"订阅Up uid:{uid} 发生了错误 {type(e)}:{e}")
logger.error(f"订阅Up uid:{uid} 发生了错误 {type(e)}:{e}") return "添加订阅失败..."
return "添加订阅失败..."
async def add_season_sub(media_id: int, sub_user: str) -> str:
async def add_season_sub(media_id: int, sub_user: str) -> str: """
""" 添加订阅 UP
添加订阅 UP :param media_id: 番剧 media_id
:param media_id: 番剧 media_id :param sub_user: 订阅用户
:param sub_user: 订阅用户 """
""" try:
try: async with db.transaction():
async with db.transaction(): try:
try: season_info = await bangumi.get_meta(media_id)
season_info = await bangumi.get_meta(media_id) except ResponseCodeException:
except ResponseCodeException: 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"] season_name = season_info["media"]["title"]
season_name = season_info["media"]["title"] if await BilibiliSub.add_bilibili_sub(
if await BilibiliSub.add_bilibili_sub( media_id,
media_id, "season",
"season", sub_user,
sub_user, season_name=season_name,
season_name=season_name, season_id=season_id,
season_id=season_id, season_current_episode=season_current_episode,
season_current_episode=season_current_episode, ):
): return (
return ( "已成功订阅番剧:\n"
"已成功订阅番剧:\n" f"\ttitle: {season_name}\n"
f"\ttitle: {season_name}\n" f"\tcurrent_episode: {season_current_episode}"
f"\tcurrent_episode: {season_current_episode}" )
) else:
else: return "添加订阅失败..."
return "添加订阅失败..." except Exception as e:
except Exception as e: logger.error(f"订阅番剧 media_id:{media_id} 发生了错误 {type(e)}:{e}")
logger.error(f"订阅番剧 media_id:{media_id} 发生了错误 {type(e)}:{e}") return "添加订阅失败..."
return "添加订阅失败..."
async def delete_sub(sub_id: str, sub_user: str) -> str:
async def delete_sub(sub_id: str, sub_user: str) -> str: """
""" 删除订阅
删除订阅 :param sub_id: 订阅 id
:param sub_id: 订阅 id :param sub_user: 订阅用户 id # 7384933:private or 7384933:2342344(group)
:param sub_user: 订阅用户 id # 7384933:private or 7384933:2342344(group) """
""" if await BilibiliSub.delete_bilibili_sub(int(sub_id), sub_user):
if await BilibiliSub.delete_bilibili_sub(sub_id, sub_user): return f"已成功取消订阅:{sub_id}"
return f"已成功取消订阅:{sub_id}" else:
else: return f"取消订阅:{sub_id} 失败,请检查是否订阅过该Id...."
return f"取消订阅:{sub_id} 失败,请检查是否订阅过该Id...."
async def get_media_id(keyword: str) -> dict:
async def get_media_id(keyword: str) -> dict: """
""" 获取番剧的 media_id
获取番剧的 media_id :param keyword: 番剧名称
:param keyword: 番剧名称 """
""" params = {"keyword": keyword}
params = {"keyword": keyword} for _ in range(3):
async with aiohttp.ClientSession() as session: try:
for _ in range(3): _season_data = {}
try: response = await AsyncHttpx.get(
_season_data = {} bilibili_search_url, params=params, timeout=5
async with session.get( )
bilibili_search_url, timeout=5, params=params if response.status_code == 200:
) as response: data = response.json()
if response.status == 200: if data.get("data"):
data = await response.json() for item in data["data"]["result"]:
if data.get("data"): if item["result_type"] == "media_bangumi":
for item in data["data"]["result"]: idx = 0
if item["result_type"] == "media_bangumi": for x in item["data"]:
idx = 0 _season_data[idx] = {
for x in item["data"]: "media_id": x["media_id"],
_season_data[idx] = { "title": x["title"]
"media_id": x["media_id"], .replace('<em class="keyword">', "")
"title": x["title"] .replace("</em>", ""),
.replace('<em class="keyword">', "") }
.replace("</em>", ""), idx += 1
} return _season_data
idx += 1 except TimeoutError:
return _season_data pass
except TimeoutError: return {}
pass
return {}
async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
"""
async def get_sub_status(id_: int, sub_type: str) -> Optional[str]: 获取订阅状态
""" :param id_: 订阅 id
获取订阅状态 :param sub_type: 订阅类型
:param id_: 订阅 id """
:param sub_type: 订阅类型 try:
:return: if sub_type == "live":
""" return await _get_live_status(id_)
try: elif sub_type == "up":
if sub_type == "live": return await _get_up_status(id_)
return await _get_live_status(id_) elif sub_type == "season":
elif sub_type == "up": return await _get_season_status(id_)
return await _get_up_status(id_) except ResponseCodeException:
elif sub_type == "season": return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
return await _get_season_status(id_) # except Exception as e:
except ResponseCodeException: # logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
return "获取信息失败...请检查订阅Id是否存在或稍后再试..." # return "发生了预料之外的错误..请稍后再试或联系管理员....."
# except Exception as e:
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
# return "发生了预料之外的错误..请稍后再试或联系管理员....." async def _get_live_status(id_: int) -> Optional[str]:
"""
获取直播订阅状态
async def _get_live_status(id_: int) -> Optional[str]: :param id_: 直播间 id
""" """
获取直播订阅状态 live = LiveRoom(id_)
:param id_: 直播间 id live_info = (await live.get_room_info())["room_info"]
""" title = live_info["title"]
live = LiveRoom(id_) room_id = live_info["room_id"]
live_info = (await live.get_room_info())["room_info"] live_status = live_info["live_status"]
title = live_info["title"] cover = live_info["cover"]
room_id = live_info["room_id"] sub = await BilibiliSub.get_sub(id_)
live_status = live_info["live_status"] if sub.live_status != live_status:
cover = live_info["cover"] await BilibiliSub.update_sub_info(id_, live_status=live_status)
sub = await BilibiliSub.get_sub(id_) if sub.live_status == 0 and live_status == 1:
if sub.live_status != live_status: return (
await BilibiliSub.update_sub_info(id_, live_status=live_status) f"{image(cover)}\n"
if sub.live_status == 0 and live_status == 1: f"{sub.uname} 开播啦!\n"
return ( f"标题:{title}\n"
f"{image(cover)}\n" f"直链:https://live.bilibili.com/{room_id}"
f"{sub.uname} 开播啦!\n" )
f"标题:{title}\n" return None
f"直链:https://live.bilibili.com/{room_id}"
)
return None async def _get_up_status(id_: int) -> Optional[str]:
"""
获取用户投稿状态
async def _get_up_status(id_: int) -> Optional[str]: :param id_: 用户 id
""" :return:
获取用户投稿状态 """
:param id_: 用户 id _user = await BilibiliSub.get_sub(id_)
:return: u = user.User(_user.uid)
""" user_info = await u.get_user_info()
_user = await BilibiliSub.get_sub(id_) uname = user_info["name"]
u = user.User(_user.uid) video_info = await u.get_videos()
user_info = await u.get_user_info() latest_video_created = 0
uname = user_info["name"] video = None
video_info = await u.get_videos() if _user.uname != uname:
latest_video_created = 0 await BilibiliSub.update_sub_info(id_, uname=uname)
video = None dynamic_img, dynamic_upload_time = await get_user_dynamic(u, _user)
if _user.uname != uname: if video_info["list"].get("vlist"):
await BilibiliSub.update_sub_info(id_, uname=uname) video = video_info["list"]["vlist"][0]
dynamic_img, dynamic_upload_time = await get_user_dynamic(u, _user) latest_video_created = video["created"]
if video_info["list"].get("vlist"): rst = ""
video = video_info["list"]["vlist"][0] if dynamic_img:
latest_video_created = video["created"] await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
rst = "" rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n"
if dynamic_img: if (
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time) latest_video_created
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n" and _user.latest_video_created
if _user.latest_video_created != latest_video_created and video: and video
rst = rst + "-------------\n" if rst else rst and _user.latest_video_created < latest_video_created
await BilibiliSub.update_sub_info( ):
id_, latest_video_created=latest_video_created rst = rst + "-------------\n" if rst else rst
) await BilibiliSub.update_sub_info(
rst += ( id_, latest_video_created=latest_video_created
f'{image(video["pic"])}\n' )
f"{uname} 投稿了新视频啦\n" rst += (
f'标题:{video["title"]}\n' f'{image(video["pic"])}\n'
f'Bvid:{video["bvid"]}\n' f"{uname} 投稿了新视频啦\n"
f'直链:https://www.bilibili.com/video/{video["bvid"]}' f'标题:{video["title"]}\n'
) f'Bvid:{video["bvid"]}\n'
rst = None if rst == "-------------\n" else rst f'直链:https://www.bilibili.com/video/{video["bvid"]}'
return rst )
rst = None if rst == "-------------\n" else rst
return rst
async def _get_season_status(id_) -> Optional[str]:
"""
获取 番剧 更新状态 async def _get_season_status(id_) -> Optional[str]:
:param id_: 番剧 id """
""" 获取 番剧 更新状态
season_info = await bangumi.get_meta(id_) :param id_: 番剧 id
title = season_info["media"]["title"] """
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode season_info = await bangumi.get_meta(id_)
new_ep = season_info["media"]["new_ep"]["index"] title = season_info["media"]["title"]
if new_ep != _idx: _idx = (await BilibiliSub.get_sub(id_)).season_current_episode
await BilibiliSub.update_sub_info( new_ep = season_info["media"]["new_ep"]["index"]
id_, season_current_episode=new_ep, season_update_time=datetime.now() if new_ep != _idx:
) await BilibiliSub.update_sub_info(
return ( id_, season_current_episode=new_ep, season_update_time=datetime.now()
f'{image(season_info["media"]["cover"])}\n' )
f"[{title}]更新啦\n" return (
f"最新集数:{new_ep}" f'{image(season_info["media"]["cover"])}\n'
) f"[{title}]更新啦\n"
return None f"最新集数:{new_ep}"
)
return None
async def get_user_dynamic(
u: User, local_user: BilibiliSub
) -> "Optional[MessageSegment], int": async def get_user_dynamic(
""" u: User, local_user: BilibiliSub
获取用户动态 ) -> "Optional[MessageSegment], int":
:param u: 用户类 """
:param local_user: 数据库存储的用户数据 获取用户动态
:return: 最新动态截图与时间 :param u: 用户类
""" :param local_user: 数据库存储的用户数据
dynamic_info = await u.get_dynamics(0) :return: 最新动态截图与时间
browser = await get_browser() """
if dynamic_info.get("cards") and browser: dynamic_info = await u.get_dynamics(0)
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"] browser = await get_browser()
if local_user.dynamic_upload_time != dynamic_upload_time: if dynamic_info.get("cards") and browser:
page = await browser.new_page() dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
await page.goto( if local_user.dynamic_upload_time < dynamic_upload_time:
f"https://space.bilibili.com/{local_user.uid}/dynamic", page = await browser.new_page()
wait_until="networkidle", try:
timeout=10000, await page.goto(
) f"https://space.bilibili.com/{local_user.uid}/dynamic",
await page.set_viewport_size({"width": 2560, "height": 1080}) wait_until="networkidle",
# 删除置顶 timeout=10000,
await page.evaluate( )
""" await page.set_viewport_size({"width": 2560, "height": 1080})
xs = document.getElementsByClassName('first-card-with-title'); # 删除置顶
for (x of xs) { await page.evaluate(
x.remove(); """
} xs = document.getElementsByClassName('first-card-with-title');
""" for (x of xs) {
) x.remove();
card = await page.query_selector(".card") }
# 截图并保存 """
await card.screenshot( )
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg", card = await page.query_selector(".card")
timeout=100000, # 截图并保存
) await card.screenshot(
await page.close() path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
return ( timeout=100000,
image( )
f"{local_user.sub_id}_{dynamic_upload_time}.jpg", except Exception as e:
"bilibili_sub/dynamic", logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
), finally:
dynamic_upload_time, await page.close()
) return (
return None, None image(
f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
"bilibili_sub/dynamic",
class SubManager: ),
def __init__(self): dynamic_upload_time,
self.live_data = [] )
self.up_data = [] return None, None
self.season_data = []
self.current_index = -1
class SubManager:
async def reload_sub_data(self): def __init__(self):
""" self.live_data = []
重载数据 self.up_data = []
""" self.season_data = []
if not self.live_data or not self.up_data or not self.season_data: self.current_index = -1
(
_live_data, async def reload_sub_data(self):
_up_data, """
_season_data, 重载数据
) = await BilibiliSub.get_all_sub_data() """
if not self.live_data: if not self.live_data or not self.up_data or not self.season_data:
self.live_data = _live_data (
if not self.up_data: _live_data,
self.up_data = _up_data _up_data,
if not self.season_data: _season_data,
self.season_data = _season_data ) = await BilibiliSub.get_all_sub_data()
if not self.live_data:
async def random_sub_data(self) -> Optional[BilibiliSub]: self.live_data = _live_data
""" if not self.up_data:
随机获取一条数据 self.up_data = _up_data
:return: if not self.season_data:
""" self.season_data = _season_data
sub = None
if not self.live_data and not self.up_data and not self.season_data: async def random_sub_data(self) -> Optional[BilibiliSub]:
return sub """
self.current_index += 1 随机获取一条数据
if self.current_index == 0: :return:
if self.live_data: """
sub = random.choice(self.live_data) sub = None
self.live_data.remove(sub) if not self.live_data and not self.up_data and not self.season_data:
elif self.current_index == 1: return sub
if self.up_data: self.current_index += 1
sub = random.choice(self.up_data) if self.current_index == 0:
self.up_data.remove(sub) if self.live_data:
elif self.current_index == 2: sub = random.choice(self.live_data)
if self.season_data: self.live_data.remove(sub)
sub = random.choice(self.season_data) elif self.current_index == 1:
self.season_data.remove(sub) if self.up_data:
else: sub = random.choice(self.up_data)
self.current_index = -1 self.up_data.remove(sub)
if sub: elif self.current_index == 2:
return sub if self.season_data:
await self.reload_sub_data() sub = random.choice(self.season_data)
return await self.random_sub_data() self.season_data.remove(sub)
else:
self.current_index = -1
if sub:
return sub
await self.reload_sub_data()
return await self.random_sub_data()
Regular → Executable
+249 -249
View File
@@ -1,249 +1,249 @@
from services.log import logger from services.log import logger
from services.db_context import db from services.db_context import db
from datetime import datetime from datetime import datetime
from typing import Optional, List from typing import Optional, List
class BilibiliSub(db.Model): class BilibiliSub(db.Model):
__tablename__ = "bilibili_sub" __tablename__ = "bilibili_sub"
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
sub_id = db.Column(db.Integer(), nullable=False) sub_id = db.Column(db.Integer(), nullable=False)
sub_type = db.Column(db.String(), nullable=False) sub_type = db.Column(db.String(), nullable=False)
# 订阅用户 # 订阅用户
sub_users = db.Column(db.String(), nullable=False) sub_users = db.Column(db.String(), nullable=False)
# 直播 # 直播
live_short_id = db.Column(db.Integer()) live_short_id = db.Column(db.Integer())
live_status = db.Column(db.Integer) live_status = db.Column(db.Integer)
# 主播/UP # 主播/UP
uid = db.Column(db.BigInteger()) uid = db.Column(db.BigInteger())
uname = db.Column(db.String()) uname = db.Column(db.String())
latest_video_created = db.Column(db.BigInteger()) # 视频上传时间 latest_video_created = db.Column(db.BigInteger()) # 视频上传时间
dynamic_upload_time = db.Column(db.BigInteger(), default=0) # 动态发布时间 dynamic_upload_time = db.Column(db.BigInteger(), default=0) # 动态发布时间
# 番剧 # 番剧
season_name = db.Column(db.String()) season_name = db.Column(db.String())
season_id = db.Column(db.Integer()) season_id = db.Column(db.Integer())
season_current_episode = db.Column(db.String()) season_current_episode = db.Column(db.String())
season_update_time = db.Column(db.DateTime()) season_update_time = db.Column(db.DateTime())
_idx1 = db.Index("bilibili_sub_idx1", "sub_id", "sub_type", unique=True) _idx1 = db.Index("bilibili_sub_idx1", "sub_id", "sub_type", unique=True)
@classmethod @classmethod
async def add_bilibili_sub( async def add_bilibili_sub(
cls, cls,
sub_id: int, sub_id: int,
sub_type: str, sub_type: str,
sub_user: str, sub_user: str,
*, *,
live_short_id: Optional[int] = None, live_short_id: Optional[int] = None,
live_status: Optional[int] = None, live_status: Optional[int] = None,
dynamic_upload_time: Optional[int] = None, dynamic_upload_time: Optional[int] = None,
uid: Optional[int] = None, uid: Optional[int] = None,
uname: Optional[str] = None, uname: Optional[str] = None,
latest_video_created: Optional[int] = None, latest_video_created: Optional[int] = None,
season_name: Optional[str] = None, season_name: Optional[str] = None,
season_id: Optional[int] = None, season_id: Optional[int] = None,
season_current_episode: Optional[str] = None, season_current_episode: Optional[str] = None,
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: 订阅此条目的用户
:param live_short_id: 直接短 id :param live_short_id: 直接短 id
:param live_status: 主播开播状态 :param live_status: 主播开播状态
:param dynamic_upload_time: 主播/UP最新动态时间 :param dynamic_upload_time: 主播/UP最新动态时间
:param uid: 主播/UP uid :param uid: 主播/UP uid
:param uname: 用户名称 :param uname: 用户名称
:param latest_video_created: 最新视频上传时间 :param latest_video_created: 最新视频上传时间
:param season_name: 番剧名称 :param season_name: 番剧名称
:param season_id: 番剧 season_id :param season_id: 番剧 season_id
:param season_current_episode: 番剧最新集数 :param season_current_episode: 番剧最新集数
:param season_update_time: 番剧更新时间 :param season_update_time: 番剧更新时间
""" """
try: try:
async with db.transaction(): async with db.transaction():
query = ( query = (
await cls.query.where(cls.sub_id == sub_id) await cls.query.where(cls.sub_id == sub_id)
.with_for_update() .with_for_update()
.gino.first() .gino.first()
) )
sub_user = sub_user if sub_user[-1] == "," else f"{sub_user}," sub_user = sub_user if sub_user[-1] == "," else f"{sub_user},"
if query: if query:
if sub_user not in query.sub_users: if sub_user not in query.sub_users:
sub_users = query.sub_users + sub_user sub_users = query.sub_users + sub_user
await query.update(sub_users=sub_users).apply() await query.update(sub_users=sub_users).apply()
else: else:
sub = await cls.create( sub = await cls.create(
sub_id=sub_id, sub_type=sub_type, sub_users=sub_user sub_id=sub_id, sub_type=sub_type, sub_users=sub_user
) )
await sub.update( await sub.update(
live_short_id=live_short_id live_short_id=live_short_id
if live_short_id if live_short_id
else sub.live_short_id, else sub.live_short_id,
live_status=live_status if live_status else sub.live_status, live_status=live_status if live_status else sub.live_status,
dynamic_upload_time=dynamic_upload_time dynamic_upload_time=dynamic_upload_time
if dynamic_upload_time if dynamic_upload_time
else sub.dynamic_upload_time, else sub.dynamic_upload_time,
uid=uid if uid else sub.uid, uid=uid if uid else sub.uid,
uname=uname if uname else sub.uname, uname=uname if uname else sub.uname,
latest_video_created=latest_video_created latest_video_created=latest_video_created
if latest_video_created if latest_video_created
else sub.latest_video_created, else sub.latest_video_created,
season_update_time=season_update_time season_update_time=season_update_time
if season_update_time if season_update_time
else sub.season_update_time, else sub.season_update_time,
season_current_episode=season_current_episode season_current_episode=season_current_episode
if season_current_episode if season_current_episode
else sub.season_current_episode, else sub.season_current_episode,
season_id=season_id if season_id else sub.season_id, season_id=season_id if season_id else sub.season_id,
season_name=season_name if season_name else sub.season_name, season_name=season_name if season_name else sub.season_name,
).apply() ).apply()
return True return True
except Exception as e: except Exception as e:
logger.info(f"bilibili_sub 添加订阅错误 {type(e)}: {e}") logger.info(f"bilibili_sub 添加订阅错误 {type(e)}: {e}")
return False return False
@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: 删除此条目的用户
""" """
try: try:
async with db.transaction(): async with db.transaction():
query = ( query = (
await cls.query.where( await cls.query.where(
(cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user)) (cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user))
) )
.with_for_update() .with_for_update()
.gino.first() .gino.first()
) )
if not query: if not query:
return False return False
await query.update( await query.update(
sub_users=query.sub_users.replace(f"{sub_user},", "") sub_users=query.sub_users.replace(f"{sub_user},", "")
).apply() ).apply()
if not query.sub_users.strip(): if not query.sub_users.strip():
await query.delete() await query.delete()
return True return True
except Exception as e: except Exception as e:
logger.info(f"bilibili_sub 删除订阅错误 {type(e)}: {e}") logger.info(f"bilibili_sub 删除订阅错误 {type(e)}: {e}")
return False return False
@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()
@classmethod @classmethod
async def get_sub_data(cls, id_: str) -> List["BilibiliSub"]: async def get_sub_data(cls, id_: str) -> List["BilibiliSub"]:
""" """
获取 id_ 订阅的所有内容 获取 id_ 订阅的所有内容
:param id_: id :param id_: id
""" """
query = cls.query.where(cls.sub_users.contains(id_)) query = cls.query.where(cls.sub_users.contains(id_))
return await query.gino.all() return await query.gino.all()
@classmethod @classmethod
async def update_sub_info( async def update_sub_info(
cls, cls,
sub_id: int, sub_id: int,
*, *,
live_short_id: Optional[int] = None, live_short_id: Optional[int] = None,
live_status: Optional[int] = None, live_status: Optional[int] = None,
dynamic_upload_time: Optional[int] = None, dynamic_upload_time: Optional[int] = None,
uid: Optional[int] = None, uid: Optional[int] = None,
uname: Optional[str] = None, uname: Optional[str] = None,
latest_video_created: Optional[int] = None, latest_video_created: Optional[int] = None,
season_name: Optional[str] = None, season_name: Optional[str] = None,
season_id: Optional[int] = None, season_id: Optional[int] = None,
season_current_episode: Optional[str] = None, season_current_episode: Optional[str] = None,
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: 主播开播状态
:param dynamic_upload_time: 主播/UP最新动态时间 :param dynamic_upload_time: 主播/UP最新动态时间
:param uid: 主播/UP uid :param uid: 主播/UP uid
:param uname: 用户名称 :param uname: 用户名称
:param latest_video_created: 最新视频上传时间 :param latest_video_created: 最新视频上传时间
:param season_name: 番剧名称 :param season_name: 番剧名称
:param season_id: 番剧 season_id :param season_id: 番剧 season_id
:param season_current_episode: 番剧最新集数 :param season_current_episode: 番剧最新集数
:param season_update_time: 番剧更新时间 :param season_update_time: 番剧更新时间
""" """
try: try:
async with db.transaction(): async with db.transaction():
sub = ( sub = (
await cls.query.where(cls.sub_id == sub_id) await cls.query.where(cls.sub_id == sub_id)
.with_for_update() .with_for_update()
.gino.first() .gino.first()
) )
if sub: if sub:
await sub.update( await sub.update(
live_short_id=live_short_id live_short_id=live_short_id
if live_short_id is not None if live_short_id is not None
else sub.live_short_id, else sub.live_short_id,
live_status=live_status live_status=live_status
if live_status is not None if live_status is not None
else sub.live_status, else sub.live_status,
dynamic_upload_time=dynamic_upload_time dynamic_upload_time=dynamic_upload_time
if dynamic_upload_time is not None if dynamic_upload_time is not None
else sub.dynamic_upload_time, else sub.dynamic_upload_time,
uid=uid if uid is not None else sub.uid, uid=uid if uid is not None else sub.uid,
uname=uname if uname is not None else sub.uname, uname=uname if uname is not None else sub.uname,
latest_video_created=latest_video_created latest_video_created=latest_video_created
if latest_video_created is not None if latest_video_created is not None
else sub.latest_video_created, else sub.latest_video_created,
season_update_time=season_update_time season_update_time=season_update_time
if season_update_time is not None if season_update_time is not None
else sub.season_update_time, else sub.season_update_time,
season_current_episode=season_current_episode season_current_episode=season_current_episode
if season_current_episode is not None if season_current_episode is not None
else sub.season_current_episode, else sub.season_current_episode,
season_id=season_id if season_id is not None else sub.season_id, season_id=season_id if season_id is not None else sub.season_id,
season_name=season_name season_name=season_name
if season_name is not None if season_name is not None
else sub.season_name, else sub.season_name,
).apply() ).apply()
return True return True
except Exception as e: except Exception as e:
logger.info(f"bilibili_sub 更新订阅错误 {type(e)}: {e}") logger.info(f"bilibili_sub 更新订阅错误 {type(e)}: {e}")
return False return False
@classmethod @classmethod
async def get_all_sub_data( async def get_all_sub_data(
cls, cls,
) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]": ) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]":
""" """
说明: 说明:
分类获取所有数据 分类获取所有数据
""" """
live_data = [] live_data = []
up_data = [] up_data = []
season_data = [] season_data = []
query = await cls.query.gino.all() query = await cls.query.gino.all()
for x in query: for x in query:
if x.sub_type == "live": if x.sub_type == "live":
live_data.append(x) live_data.append(x)
if x.sub_type == "up": if x.sub_type == "up":
up_data.append(x) up_data.append(x)
if x.sub_type == "season": if x.sub_type == "season":
season_data.append(x) season_data.append(x)
return live_data, up_data, season_data return live_data, up_data, season_data

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