mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-09-29 00:32:06 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d55cba49bd | ||
|
|
0215abac30 | ||
|
|
2dcac5f009 | ||
|
|
0d8c64f7d1 | ||
|
|
55626645fb | ||
|
|
f7925fa259 | ||
|
|
c814ae08b1 | ||
|
|
24666368f7 | ||
|
|
a77e85b62d | ||
|
|
6319c7fce1 | ||
|
|
a45b95d5d4 | ||
|
|
188f6f0f99 | ||
|
|
a72f126d8f | ||
|
|
33eb1b83a8 | ||
|
|
2d9ebe2e6d | ||
|
|
262b098dec | ||
|
|
79d88065aa | ||
|
|
0f59895c3b | ||
|
|
610d588e34 | ||
|
|
f99abb2f98 | ||
|
|
b2b7560d05 | ||
|
|
07c16e5238 | ||
|
|
1741ea7d26 | ||
|
|
b5ce4fab31 | ||
|
|
062e4c2062 | ||
|
|
0adb66a8bf | ||
|
|
2aad517112 | ||
|
|
14d1512b1e | ||
|
|
3f533516af | ||
|
|
f1354308fd | ||
|
|
c06248e46b | ||
|
|
9c8eaed938 | ||
|
|
2081302e32 | ||
|
|
678fc19f2d | ||
|
|
adc2757e8e | ||
|
|
82a1261371 | ||
|
|
067da9dc57 | ||
|
|
0eb9f9fc6f | ||
|
|
aee1340714 | ||
|
|
a72a9bd8cb | ||
|
|
7250410653 | ||
|
|
12f55800b0 | ||
|
|
53b375b4b2 | ||
|
|
fba27abe29 | ||
|
|
4caa3dec04 | ||
|
|
516b0f5ccb | ||
|
|
b5098be08e | ||
|
|
5b08a4650c | ||
|
|
eb02157b94 | ||
|
|
222e1719a4 | ||
|
|
3c8983e753 | ||
|
|
1fe41dd823 | ||
|
|
e8df59203c | ||
|
|
0f6690606b | ||
|
|
a0115309dd | ||
|
|
ca18d45786 | ||
|
|
76df21036a | ||
|
|
c674d581b7 | ||
|
|
fc53c3c487 | ||
|
|
7a4e31df80 | ||
|
|
f1d308d559 | ||
|
|
b7914bac05 | ||
|
|
8c40d88cc4 | ||
|
|
b4ed6dcb5d | ||
|
|
0d3bd8a89c | ||
|
|
87f0189abd | ||
|
|
1c17ac1f9d | ||
|
|
f038763041 | ||
|
|
eaf6d54757 | ||
|
|
d7368c83bc | ||
|
|
4011620da1 | ||
|
|
6e0b91531e | ||
|
|
b8ca1d68aa | ||
|
|
2b9cda40a0 | ||
|
|
d8983bdcbf | ||
|
|
14bce52f2f | ||
|
|
a7b0f7da68 | ||
|
|
7dd68cf1ef | ||
|
|
ab443a21ec | ||
|
|
ed7e8a8a4c | ||
|
|
a1435e2fc4 | ||
|
|
44a80f89da | ||
|
|
164f6af30c | ||
|
|
9093a79101 | ||
|
|
14cce89a18 | ||
|
|
4bce20a0a9 | ||
|
|
f32d8b4eff | ||
|
|
685f2b8c53 | ||
|
|
1e63ca2549 | ||
|
|
c1bc4eff2b | ||
|
|
bc903d3813 | ||
|
|
80fc17b610 | ||
|
|
0efb2bbc60 | ||
|
|
95ad533b87 | ||
|
|
b6e3240df9 | ||
|
|
5ae41e1d38 | ||
|
|
8022ae1fb1 | ||
|
|
0163fc1d88 | ||
|
|
5d9ab40e35 | ||
|
|
b1ca7930bb | ||
|
|
40111261ed | ||
|
|
4cb91b47e6 | ||
|
|
30b56583bd | ||
|
|
5e5168f804 | ||
|
|
4a8122829e | ||
|
|
52ba2cf89a | ||
|
|
58957cdf44 | ||
|
|
71f860a500 | ||
|
|
9b4cde819e | ||
|
|
99637de1de | ||
|
|
19dbd3f2b0 | ||
|
|
7567794f74 | ||
|
|
df0d15c1b3 | ||
|
|
9a84c02bb5 | ||
|
|
e623c4f30f | ||
|
|
3fd7acffb2 | ||
|
|
71f8c16c26 | ||
|
|
b64699c4ab | ||
|
|
786d62bb2f | ||
|
|
ac48d3d542 | ||
|
|
c4d9523ec2 | ||
|
|
cb6549c297 | ||
|
|
29816ada2a | ||
|
|
dd12bdc028 | ||
|
|
2a52c0711b | ||
|
|
2653f67193 | ||
|
|
b892617824 | ||
|
|
a6fb05c91d | ||
|
|
ccfb9403c8 | ||
|
|
66fa194c7f | ||
|
|
65d8fae9ca | ||
|
|
58acb14859 | ||
|
|
b63c05a509 | ||
|
|
2a1a2ee8c5 |
+147
@@ -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/
|
||||
@@ -18,17 +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 '真寻帮助 指令'
|
||||
|
||||
## 普通帮助图片
|
||||

|
||||
|
||||
## 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>
|
||||
@@ -51,9 +72,13 @@
|
||||
- [x] 商店/我的金币/购买道具/使用道具
|
||||
- [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
|
||||
- [x] 我有一个朋友想问问..(借鉴pcrbot插件)
|
||||
- [x] 原神黄历 (使用[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
|
||||
- [x] 原神黄历
|
||||
- [x] 原神今日素材
|
||||
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
|
||||
- [x] 原神便笺查询
|
||||
- [x] 原神玩家查询
|
||||
- [x] 原神树脂提醒
|
||||
- [x] 原神签到/自动签到
|
||||
- [x] 金币红包
|
||||
- [x] 微博热搜
|
||||
- [x] B站主播/UP/番剧订阅
|
||||
@@ -89,6 +114,8 @@
|
||||
- [x] 通过PID获取图片
|
||||
- [x] 功能统计可视化
|
||||
|
||||
- [x] 关于
|
||||
|
||||
### 已实现的管理员功能
|
||||
- [x] 更新群组成员信息
|
||||
- [x] 95%的群功能开关
|
||||
@@ -101,6 +128,7 @@
|
||||
- [x] 删除图片 (同上)
|
||||
- [x] 群内B站订阅
|
||||
- [x] 群词条
|
||||
- [x] 休息吧/醒来
|
||||
|
||||
### 已实现的超级用户功能
|
||||
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
|
||||
@@ -126,6 +154,12 @@
|
||||
- [x] 功能开关(更多设置)
|
||||
- [x] 功能状态
|
||||
- [x] b了
|
||||
- [x] 执行sql
|
||||
- [x] 重载配置
|
||||
- [x] 清理临时数据
|
||||
- [x] 增删群认证
|
||||
- [x] 同意/拒绝好友/群聊请求
|
||||
- [x] 配置重载
|
||||
|
||||
#### 超级用户的被动技能
|
||||
- [x] 邀请入群提醒(别人邀请真寻入群)
|
||||
@@ -150,127 +184,7 @@
|
||||
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
|
||||
- [x] 群权限系统
|
||||
- [x] 定时更新权限
|
||||
</details>
|
||||
|
||||
## 功能具体指令
|
||||
<details>
|
||||
<summary>功能具体指令说明</summary>
|
||||
|
||||
### 常用功能
|
||||
|
||||
** [*]:表示该参数可有多个 [?]:表示参数可选 **
|
||||
|
||||
| 功能 | 指令 | 说明
|
||||
| ----------------------| :--------------------------------------:| :------------------------:
|
||||
| 签到 | 签到/我的签到/好感度排行/好感度总榜/好感度总榜\[显示我/屏蔽我] | 普通的签到插件,可以获得好感度和金币<br>好感度影响开箱次数和涩图触发概率,金币用于购买道具,俄罗斯轮盘赌注以及金币红包<br>好感度总榜,显示所有群的群员好感度排行,可通过命令好感度总榜\[显示我/屏蔽我] 来设置是否隐藏
|
||||
| 发送图片 | 美图/壁纸/萝莉 \[id]?(默认随机)/\[num]张图\[keyword] | 发送指定文件夹下的图片<br>示例:萝莉->发送img文件夹下luoli文件夹下的图片<br>在线搜索一些不色的图,示例:3张图米浴
|
||||
| 色图 | 色图/色图xx/n张色图/n张xx的色图/查色图(查询本地色图信息)/色图r【n<10】 | 色图r返回10张r18色图(仅私聊),并限制每日次数(默认5次)<br>其他示例:色图 真寻 <br>5张真寻的色图
|
||||
| 黑白草图 | 黑白草图/黑白图 \[文字] \[图片] | 整活生成器,示例:黑白图 我喜欢真寻 \[图片]
|
||||
| coser | coser/cos/括丝 | coser图片,说实话挺失望的,太色了
|
||||
| 骂我 | 骂我 | 就是发送钉宫的语音罢了
|
||||
| 戳一戳 | 戳一戳 | 随机发送钉宫语音 or 美图 or 萝莉图 or 文本
|
||||
| 模拟开箱 | 开箱 \[武器箱名称](默认随机)/N连开箱 \[武器箱名称](默认随机)/我的开箱/群开箱统计/我的金色 | 当不指定武器箱时默认随机,此功能需要先在/open_cases/config.py中编写指定武器箱数据,然后提前爬取价格,使用超级用户命令更新cookie后,再使用命令更新xx武器箱【注:未设置爬取频率,可能会被禁用api(请谨慎!!用小号!!)】
|
||||
| 鲁迅说过 | 鲁迅说过 \[文本] | 示例:鲁迅说过 真寻世界第一可爱
|
||||
| 假消息 | 假消息 \[网址] \[标题] \[内容]? \[图片]? | 构造虚假的分享消息
|
||||
| 商店系统 | 商店/我的金币/购买道具 \[名称或序号] \[数量](默认1)/使用道具 \[名称或序号] | 示例:<br>购买道具 1 3<br>购买道具 好感度双倍加持卡Ⅰ 3<br>使用道具 1<br>使用道具 好感度双倍加持卡Ⅰ
|
||||
| 抽卡系统 | 原神/明日方舟/赛马娘/坎公骑冠剑/碧蓝航线/阴阳师/公主连结(pcr)/FGO N抽/一井 | 详细帮助请查看: [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw) <br>示例:原神90抽
|
||||
| 我有一个朋友 | 我有一个朋友他说/想问问/\[文本] | 会将文本中的(他,她,它)替换成 '我'<br>示例:我有一个朋友想问问他喜不喜欢真寻
|
||||
| 昵称系统 | 以后叫我\[昵称]/以后请叫我\[昵称]/我是谁/我叫什么 | 此昵称会替换与真寻聊天中 '你' 的名称(群名片),群与群与私聊的昵称相互独立
|
||||
| 原神黄历 | 原神黄历 | 查看今日原神黄历,含有每日10:25的定时任务
|
||||
| 原神材料 | 今日素材 | 发送可莉特调的截图
|
||||
| 丘丘语翻译 | 丘丘翻译/丘丘一下/丘丘语翻译 | 示例:丘丘一下 mimi
|
||||
| 原神资源查询 | 原神资源查询 \[资源名称] \[路线]?/\[资源名称]在哪/哪里有\[资源名称]/原神资源列表 | 如果资源名称末尾添加‘路线’的话将生成残缺缺缺版的优先路径<br>示例:嘟嘟莲在哪<br>原神资源查询嘟嘟莲路线
|
||||
| 俄罗斯轮盘 | 装弹\[子弹数] \[金额](默认200)/开枪/结算/我的战绩/胜场排行/败场排行/欧洲人排行/慈善家排行 | 紧张刺激的群内小游戏,使用每日签到的金币作为赌注,具体玩法请发送 真寻帮助 俄罗斯轮盘
|
||||
| 红包系统 | 塞红包\[金额] \[数量](默认5)/抢/开/戳一戳/退回 | 仿微信明日方舟红包的样式(pil拼图大师!),每个红包金额随机生成,最多会是红包总金额的1/3,退回用于退回一分钟后还未开完的红包
|
||||
| 金币排行 | 金币排行 | 字面意思
|
||||
|网易云热评 | 到点了/12点了/网易云热评/网易云评论 | 防下塔
|
||||
| 古诗 | 念诗/念首诗/来首诗 | 突然文艺起来了
|
||||
|微博热搜 | 微博热搜/微博热搜[序号]? | 快捷热搜查询方式
|
||||
| pil对图片的操作 | 修改尺寸/等比压缩/旋转图片/水平翻转/铅笔滤镜/模糊效果/锐化效果/高斯模糊/边缘检测/底色替换 | 选项较多,请直接发送 真寻图片帮助
|
||||
| BUFF皮肤底价查询 | 查询皮肤 \[武器名称] \[皮肤名称] | 网络不友好的话会经常超时<br>示例:查询皮肤 沙漠之鹰 印花集
|
||||
| 天气查询 | \[城市]天气 | 非常常见的插件,第一个入门插件
|
||||
| 疫情查询 | 疫情/查询疫情 \[城市名或省份名] | 示例:疫情杭州
|
||||
| bt磁力搜索 | bt \[关键词] \[页数]?(默认第1页) | 该功能仅仅提供给私聊,因为可以搜到一些色色的东西,示例:bt钢铁侠 5
|
||||
| 上车 | 略 | 直接查看真寻帮助 上车,每日限制次数(默认5)
|
||||
| 以图识番 | 识番 \[图片] | 以图搜翻,图片越清晰越完整正确率越高
|
||||
| 以图搜图 | 识图 (asc)? \[图片] | 参数asc更换搜索引擎为ascii2d,默认为saucenao
|
||||
| 点歌 | 点歌 \[歌名] | 网易云点歌小助手
|
||||
| 搜番 | 搜番 \[关键字] | 群聊只返回5个结果,私聊返回20个结果
|
||||
| epic白嫖游戏通知 | epic | 通知你又到了白嫖游戏的时候,可以不玩,不能没有
|
||||
| P站排行榜 | p站排行 \[排行类型参数]? \[数量]? \[日期]?| 9种不同排行榜,r18类型仅可私聊,通过参数选择,查看真寻帮助p站排行<br>示例:p站排行榜 1 9 2018-4-25
|
||||
| 搜图 | 搜图 \[关键词] \[数量]? \[排序方式]? \[r18]?| r18仅可私聊,查看真寻帮助搜图
|
||||
| 通过PID搜索图片 | p搜 [pid] | 在群内使用此功能会在30秒内撤回
|
||||
| 翻译 | 英翻/日翻/韩翻/翻韩/翻日/翻英 \[文本] | 三种语言互相翻译
|
||||
| 获取b站视频封面 | b封面 [链接/av/bv/cv/直播id] | 快捷的封面获取方式
|
||||
| 群欢迎消息 | 群欢迎消息/查看群欢迎消息/查看当前群欢迎消息 | 查看给真寻设置的群欢迎消息
|
||||
| 自我介绍 | 自我介绍 | 没错,一份正经的真寻自我介绍
|
||||
| 我的权限 | 我的权限 | 真寻内部定义的一套权限系统
|
||||
| 我的信息 | 我的信息 | 唯一的作用就是看看什么时候加入群
|
||||
| 撤回 | 撤回 \[消息位置]?(默认为最新一条消息) | 按顺序撤回发送的消息,示例:撤回 1
|
||||
| 滴滴滴- | 滴滴滴- \[文本] | 用于用户联系真寻的超级用户
|
||||
|功能调用统计可视化 | 功能调用统计(自记录以来的功能调用统计)<br>周功能调用统计 [plugin_name]<br>月功能调用统计 [plugin_name]| 当plugin_name为空时为7天或30内的所有功能统计
|
||||
| pix | pix/PIX [tags/uid/pid:pid] [num] | 无参数时随机查看pix图库的图片(无r18),num数量默认=1,tags:查看相关tags图片,uid:查找相关画师图片,pid:pid:指定查看pid图片<br>示例:pix原神 3<br>pix23493844<br>pixpid:29429933
|
||||
| 添加pix关键词/uid/pid | 添加pix关键词/uid/pid *[关键词/uid/pid]| 添加关键词或uid或pid用于下次搜索,关键词搜索相关tag,uid会收录作者下收藏符合标准的作品,pid收录单张作品<br>示例:添加pix关键词 原神<br> 添加pixuid 123441<br>添加pixpid 2748937|
|
||||
| 查看pix图库 | 查看pix图库 [tags] | 查看已收录的tag相关图片数量<br>示例:查看pix图库 原神 莫娜
|
||||
|显示pix关键词 | 显示pix关键词 | 查看已收录的所有关键词/UID/PID
|
||||
| b了 | b了 [at] | 使真寻完全忽略一个用户的所有信息
|
||||
| B站订阅 | 添加订阅 [主播/UP/番剧] [id/链接/番名] / 删除订阅 [id] / 查看订阅 | 可以通过直接间链接或主播间id添加订阅主播开播提醒,动态和投稿,可以通过番名,番剧的id,或者番剧链接添加番剧订阅(是番剧id,md开头,不是集数id,ep开头的)更新, 可以通过UP个人id或UP主页链接订阅UP动态和投稿
|
||||
|
||||
### 管理员功能
|
||||
|
||||
**群主与群管理员默认5级权限**
|
||||
|
||||
| 功能 | 权限等级 | 指令 | 说明
|
||||
| -------------| --------------| :--------------------------------------:| :------------------------:
|
||||
| 更新群组成员信息 | 1 | 更新群组成员信息/更新群组成员列表 | 存储群员的基本信息,虽然有自动更新,但备个命令以防万一
|
||||
| 群功能开关 | 2 | 开启/关闭\[指令名]功能 | 群帮助中左边带有√的功能都可以通过此命令开启或关闭,示例:开启色图
|
||||
| 查看群被动技能 | 2 | 群通知状态 | 详细请查看被动技能列表
|
||||
| 被动技能开关 | 2 | 开启/关闭被动技能 | 有时候花里胡哨通知也会很烦人
|
||||
| 自定义群欢迎消息 | 2 | 自定义群欢迎消息 \[文本] \[图片] | 文本和图片至少需要一个,在文本内添加"\[at]"字符串可以用来设置艾特进群的新群员
|
||||
| 黑名单 | 5 | .ban/.unban \[at] \[小时]? \[分钟]?| 不提供具体时间的话则ban掉永久,且权限低的用户无法unban高权限用户的ban,同级权限也无法进行ban/unban <br>示例:.ban@笨蛋 1 50
|
||||
| 刷屏检测相关 | 5 | 刷屏检测设置/设置检测时间 \[文本]/设置检测次数 \[文本]/设置禁言时长 \[分钟]| 非常讨厌刷屏的人,打算给他们一点教训
|
||||
| 上传图片 | 6 | 上传图片 \[图库] \[图片]... | 上传图片至指定图库,虽然并不打算开放给群员,但还是写了,支持批量图片<br>示例:上传图片 美图 \[图片]..
|
||||
| 删除图片 | 6 | 删除图片 [图库] \[图片id] | 通过指定本地图片id来删除指定图库的图片<br>示例:删除图片 美图 1
|
||||
| 移动图片 | 6 | 移动图片 \[移出的图库] \[移入的图库] \[图片id] | 移动指定图库中的图片到指定的新图库中,移入的图片id更改为移入图库的最后一位,移除的图库中原本图片的id又最后一位图片替代<br>示例:移动图片 美图 萝莉 22
|
||||
|B站订阅 | 5 | 功能同上,就是在群中有权限限制 | 略
|
||||
|
||||
### 超级用户功能
|
||||
|
||||
| 功能 | 指令 | 说明
|
||||
| ----------------------| :--------------------------------------:| :------------------------:
|
||||
| 权限增删 | 添加/删除权限 \[at] \[level]<br>添加/删除权限 [qq] [group] [level] | 用于添加或修改权限等级,且该权限不会被自动更新取消
|
||||
| 所有群组/好友 | 所有群组/好友 | 查看真寻添加的群组与好友
|
||||
| 广播 | 广播- [文本] | 广播所有群组
|
||||
| 更新色图 | 更新色图 | 更新群友搜索色图时保存的url
|
||||
| 回复 | /t | 命令较多,请查看/t帮助,省略群号则私聊用户(必须要有用户的好友)
|
||||
| 更新cookie | 更新cookie \[cookie] | 用于更新开箱数据和查询buff皮肤
|
||||
| 开启广播通知 | 开启/关闭广播通知 \[群号] | 用于开启/关闭是否对某些群进行广播(上边的广播方法)
|
||||
| 退群 | 退群 \[群号] | 用于退出某一些群
|
||||
| 检查系统状态 | 自检 | 略
|
||||
| 更新好友/群组信息| 更新好友/群组信息 | 包含自动更新,被t出群等等有更好的可视信息
|
||||
| 重载卡池 | 略 | 重载抽卡的游戏卡池,请查看 \[nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw)
|
||||
| 添加商品 | 添加商品 \[名称]-\[价格]-\[描述]-\[折扣](小数)?-\[限时时间](分钟)? | 为真寻的商店添加一点点道具<br>示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60
|
||||
| 删除商品 | 删除商品 \[名称或序号] | 在真寻的商店中删除一点东西
|
||||
| 修改商品 | 修改商品 -name \[名称或序号] -price \[价格] -des \[描述] -discount \[折扣] -time \[限时]| 注意空格,不需要的参数可以不加<br>示例:修改商品 -name 1 -price 900 【修改序号为1的商品的价格为900】
|
||||
| 节日红包 | 节日红包 \[金额] \[数量] \[祝福语]? \[群号]?... | 群号支持批量,使用空格隔开,不使用群号则对所有群发送节日红包,节日红包有效时间为24小时,祝福语默认为“恭喜发财 大吉大利”<br>示例:节日红包 10000 15 真寻真可爱 123324423 23423423
|
||||
| 修改群权限 | 修改群权限 \[group] \[level] | 所以说这功能是对内鬼的无奈,默认群权限为5,默认无法使用 色图/coser/p站排行/搜图(这些功能都要9级权限)
|
||||
|更新原神今日素材| 更新原神今日素材 | 自动更新原神每日素材失败时可以手动触发
|
||||
|更新原神资源信息| 更新原神资源信息 | 除了每日自动更新的资源外,额外更新大地图
|
||||
| 清理数据 | 清理数据 | 清理 temp,rar,r18_rar 文件夹的文件数据
|
||||
|添加pix关键词/uid/pid | 添加pix关键词/uid/pid [keyword/pid:pid/uid:uid] [-f]? | 与普通功能相同,额外可以通过参数 -f 强制通过检测
|
||||
|删除pix关键词 | 删除pix关键词 *[keyword/uid/pid:pid] | 删除已收录的keyword/uid/pid
|
||||
|更新pix关键词 | 更新pix关键词 [keyword/pid:pid/uid:uid] [num]?| 更新keyword,uid,pid或指定uid,pid,未指定时,则更新全部,当num未指定时为keyword/uid/pid更新全部<br>示例:更新pix关键词<br>更新pix关键词uid 8<br>更新pix关键词pid:83457477<br>num:倒叙更新数量
|
||||
|删除pix图片 | 删除pix图片 [*pid] [-b]? | [-b]参数为删除的同时加入黑名单(不再更新),虽然是pid,但是_p也可以<br>示例:删除pix图片3458344 8235234_p1 -b
|
||||
|显示pix关键词 | 显示pix关键词 | 与普通功能相同,额外显示待收录和黑名单
|
||||
|pix检测更新 | pix检测更新 [update]? | 检测从未更新过的pid或uid,-update参数将在检测后直接更新未更新过的pid或uid<br>示例:pix检测更新 update
|
||||
| 检查更新真寻 | 检查更新真寻 | 不再需要麻烦的clone第一步
|
||||
| 关闭功能 | 关闭[功能] [group/private]/*[群号]? | 关闭色图:维护功能(关闭总开关)<br>关闭色图 g:在群内限制功能<br>关闭色图 p:在私聊限制功能<br>关闭色图 1234678:禁用12345678的色图功能
|
||||
| 群白名单 | 添加/删除群白名单 *[群号] / 查看群白名单 | 白名单内的群不会受到 维护 限制
|
||||
| 功能状态 | 功能状态 | 查看功能开关状态
|
||||
| pix | pix [-s/-r] [keyword] | 可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
|
||||
| 重载插件配置 |重载插件配置 |用于生效手动修改配文件
|
||||
|帮助 -super | 帮助[功能] -super | 显示该插件的超级用户帮助
|
||||
|
||||
- [x] 自动配置重载
|
||||
</details>
|
||||
|
||||
## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
|
||||
@@ -283,7 +197,7 @@
|
||||
# 配置gocq
|
||||
|
||||
在 https://github.com/Mrs4s/go-cqhttp 下载Releases最新版本,运行后选择反向代理,
|
||||
后将gocq的配置文件config.yml中的universal改为universal: ws://127.0.0.1:8080/cqhttp/ws
|
||||
后将gocq的配置文件config.yml中的universal改为universal: ws://127.0.0.1:8080/onebot/v11/ws
|
||||
|
||||
# 获取代码
|
||||
git clone https://github.com/HibiKier/zhenxun_bot.git
|
||||
@@ -292,12 +206,14 @@ git clone https://github.com/HibiKier/zhenxun_bot.git
|
||||
cd zhenxun_bot
|
||||
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
pip install poetry # 安装 poetry
|
||||
poetry install # 安装依赖
|
||||
|
||||
# 进行基础配置
|
||||
####请查看 配置 部分####
|
||||
|
||||
# 开始运行
|
||||
poetry shell # 进入虚拟环境
|
||||
python bot.py
|
||||
```
|
||||
|
||||
@@ -317,360 +233,235 @@ python bot.py
|
||||
```
|
||||
|
||||
|
||||
## 使用Docker
|
||||
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
||||
#### GitHub:[Sakuracio/zxenv](https://github.com/Sakuracio/zxenv)
|
||||
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
|
||||
|
||||
|
||||
|
||||
## 更新
|
||||
|
||||
### 2021/11/29 \[v0.0.6.4]
|
||||
### 2022/4/10 \[v0.1.4.7]
|
||||
|
||||
* 新增cos图撤回配置项
|
||||
* 新增默认群权限配置项
|
||||
* 修复权限等级类配置无法正常应用
|
||||
* 新增消息记录模块
|
||||
* 丰富处理请求操作提示
|
||||
* web ui新增配置项修改
|
||||
|
||||
### 2021/11/24 \[v0.0.6.3]
|
||||
|
||||
* 修复在线搜索色图出错
|
||||
* 修复pix无法正确获取HIBIAPI
|
||||
### 2022/4/9
|
||||
|
||||
### 2021/11/23 \[v0.0.6.2]
|
||||
* fix: 更新问题,戳一戳图片路径问题 [@pull/144](https://github.com/HibiKier/zhenxun_bot/pull/144)
|
||||
|
||||
* 替换cos API
|
||||
* 提供私聊b了,即跨群b了用户
|
||||
* 修复游戏抽卡导入角色失败(原神)
|
||||
* 修复无Pixiv代理时报错
|
||||
* 将项目中大部分aiohttp替换为httpx
|
||||
* 删除了丘丘人翻译插件
|
||||
* 新增群词条
|
||||
* 修复游戏抽卡碧蓝航线bwiki格式更改导致获取报错
|
||||
* 首次启动会生成配置文件后停止程序,配置后再次启动即可
|
||||
### 2022/4/8
|
||||
|
||||
### 2021/11/18
|
||||
|
||||
* 修复超级用户无法正确拉真寻入群
|
||||
* 修复原神玩家查询
|
||||
|
||||
### 2021/11/14
|
||||
|
||||
* 修复功能总开关无法正确开启
|
||||
### 2022/4/6
|
||||
|
||||
### 2021/11/12
|
||||
|
||||
* 修复PIX无法url无法正确获取
|
||||
* update search_type [@pull/143](https://github.com/HibiKier/zhenxun_bot/pull/143)
|
||||
|
||||
### 2021/11/10
|
||||
|
||||
* 修复PIX表重复创建导致首次无法运行
|
||||
* 检测Omage图库改为命令方式:检测omega图库
|
||||
|
||||
### 2021/11/9
|
||||
|
||||
* 修复管理员帮助无法正常响应
|
||||
* 修复被ban时会一直回复被ban提醒
|
||||
|
||||
### 2021/11/5
|
||||
|
||||
* 修复ai没有图灵key时报错
|
||||
* 提供图片路径resource/img/background/check
|
||||
|
||||
### 2021/11/4
|
||||
|
||||
* 通用排行榜改用图片消息,且可以自定义排行榜人数
|
||||
* 优化CreateMat排行榜数据显示
|
||||
* 修复了pix更新多余参数导致失败的问题
|
||||
* 修复滴滴滴-注入风险
|
||||
* 修复无法正常关闭滴滴滴,戳一戳
|
||||
* 添加了发送图片撤回配置项WITHDRAW_IMAGE_TIME
|
||||
* 修复了天气regex文本过长时会正则匹配过久导致nb卡顿
|
||||
* message_build新增custom_forward_msg用于快捷生成转发消息
|
||||
* 插件配置改为yaml存储,新增Config,用于获取和新增插件配置
|
||||
* 新增 当插件加载失败时,会发送消息提醒超级用户,且在功能状态中对应失败插件写上[ERROR]
|
||||
* 修复当查看-spuer插件帮助时无法正确回复
|
||||
* 群内帮助图片会随群内功能开关和插件总开关变化
|
||||
* 自检改为图像形式
|
||||
* 更新色图删除了rar_setu,r18_rar和rar文件夹,压缩将统一在temp文件夹
|
||||
* 更新色图只有在有更新数量或报错时才会提醒超级用户
|
||||
* 群欢迎消息加入cd
|
||||
* 加入资源管理resources_manager
|
||||
* 新增 好友请求/群聊邀请 控制命令
|
||||
|
||||
### 2021/10/15
|
||||
|
||||
* 适配了原神资源查询米游社地图返回的新格式
|
||||
|
||||
### 2021/10/8
|
||||
|
||||
* 修复疫情省份查询失效
|
||||
* 修复功能调用统计全局下统计可能发生错误
|
||||
|
||||
### 2021/10/4
|
||||
|
||||
* 修复了功能调用统计失效问题
|
||||
* 当色图库中没有色图时,会在线搜索色图而不是‘没找到符合条件的色图...’
|
||||
* 快速更新权限再给超级用户发送错误日志
|
||||
* 修复疫情未加载省份城市无法正常使用
|
||||
|
||||
### 2021/10/3
|
||||
|
||||
* 对插件进行分离
|
||||
* 重写了插件与限制管理器以及帮助获取
|
||||
* 修改一些插件目录和数据存储目录
|
||||
* 插件通用配置与限制数据将以ymal文件存储 \[路径:data/configs]
|
||||
* 所有商店相关操作调用统计合并为商店(包括之前已经保存的数据,会先进行备份)
|
||||
* 简化了点歌的代码相关
|
||||
* 修复了碧蓝航线抽卡新框导致报错无法正常初始化
|
||||
* 修复了P站排行/搜图在PC端无法正常显示
|
||||
* 添加了插件对超级用户是否限制的配置 ‘limit_superuser’
|
||||
* 添加命令 ‘重载插件配置’,用于生效手动修改配文件
|
||||
* 超级用户帮助可以添加 -super 来显示该插件的超级用户帮助,示例:帮助.ban -super
|
||||
* 原神黄历改为网页截图
|
||||
* 修改了鲁迅说逻辑结构
|
||||
* 修改了统计图表样式,改为自定义CreateMat
|
||||
* 节日红包不再被24小时限制,群内多个节日红包将会覆盖
|
||||
* 当群权限为-1时,不会对群发送修改权限通知,并屏蔽此群一切命令(包括提醒)
|
||||
* 修复了红包数量可以过大或为负数,红包数量大于群员数量时会修改为群员数量
|
||||
* 修复了负数开箱
|
||||
* 签到最低好感度设置为0.01 [@pull/53](https://github.com/HibiKier/zhenxun_bot/pull/53)
|
||||
* pip安装新依赖 ruamel.yaml
|
||||
* 修复功能 EPIC [@pull/58](https://github.com/HibiKier/zhenxun_bot/pull/58)
|
||||
|
||||
### 2021/9/10
|
||||
|
||||
* 修复撤回消息有时无法正确获取消息id
|
||||
|
||||
### 2021/9/9
|
||||
|
||||
* 替换coser API
|
||||
* 修复签到uid可能不默认为0
|
||||
* 修复签到可能重复的问题
|
||||
* 修复无订阅时递归出错
|
||||
* 启用了plugins2info_dict, plugins2cd_dict, plugins2exists_dict配置文件,通过USE_CONFIG_FILE=True开启
|
||||
* 修复涩图local_id会被固定为50
|
||||
* 优化图库数量查询
|
||||
* 修复原神大地图过大无法打开报错
|
||||
* 修复无法显示正确的涩图上限
|
||||
|
||||
### 2021/9/7
|
||||
|
||||
* 修改 update_info.json
|
||||
* 修改 更新信息 图片大小
|
||||
* 修复 查看订阅 命令 UP和番剧无法正常显示
|
||||
* 修复订阅推送无法正确推送
|
||||
* 修复搜图返回列表为空时无法正确回复 [@pull/40](https://github.com/HibiKier/zhenxun_bot/pull/40)
|
||||
|
||||
### 2021/9/5
|
||||
* 添加配置PIX_IMAGE_SIZE,调整PIX下载图片大小,当设置的图片404时,改为原图
|
||||
* 新增配置DEFAULT_GROUP_LEVEL,默认群等级
|
||||
* 新增超级用户功能 super ban,将屏蔽被ban用户的所有消息,指令:b了
|
||||
* b站转发解析支持纯BV号解析,且五分钟内不会解析相同url
|
||||
* 俄罗斯轮盘新增 连胜/最高连胜/连败/最高连败 纪录,新增 最高连胜排行榜/最高连败排行榜
|
||||
* 增加扩展图库 OmegaPixivIllusts,不想自己找图的人福音([Ailitonia](https://github.com/Ailitonia) 佬的高质量精品手筛图库)([传送门](https://github.com/Ailitonia/omega-miya/blob/master/archive_data/db_pixiv.7z) ),可以手动导入图库,也可以将解压文件放在bot.py同级目录重启bot
|
||||
* 增加配置PIX_OMEGA_PIXIV_RATIO,PIX功能发送PIX图库和扩展图库OmegaPixivIllusts图片的比例,如果没有使用扩展图库OmegaPixivIllusts,请设置为(10, 0)
|
||||
* 增加配置WITHDRAW_PIX_TIME,用于配置在开关PIX图片在群私聊的自动撤回
|
||||
* 上传图库cases, 开箱 也可以连抽(未更新过没有价格)
|
||||
* 新增命令 查看群白名单
|
||||
* plugins2info_dict新增键"default_status",设置加入新群时功能的默认开关状态
|
||||
* 增加配置plugins2exists_dict,可自定义是否阻塞某命令同时触发多次
|
||||
* 增加配置plugins2cd_dict,可自定义为命令添加cd
|
||||
* 新增B站订阅(直播/番剧/UP)[测试],提供命令:添加订阅 [主播/UP/番剧] [id/链接/番名],删除订阅 [id],查看订阅
|
||||
* 优化pix和色图的数据库查询
|
||||
* 触发已关闭的功能的正则时不再触发ai
|
||||
* 更换coser API
|
||||
* PIX搜索pid功能在群聊无法搜索PIX图库的r18和OmegaPixivIllusts的r15以及r18,超级用户除外
|
||||
* PIX单次搜索的图片张数超级用户限制为至多30张,普通用户10张
|
||||
* PIX超级用户新增-s,-r,可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
|
||||
* 优化P站排行和搜图,现在需要艾特,改为使用HIBIAPI,在群内时将使用合并消息(群聊搜图会屏蔽R-18)
|
||||
* win10下playwright相关功能无法使用,但是不再需要删除文件
|
||||
* 签到大改,优化签到方式与逻辑,改为图片形式发送,有概率额外获得随机道具(好感度有加成)
|
||||
* 修改撤回功能,改为回复撤回,回复发送撤回
|
||||
* 更改logging为loguru
|
||||
* 删除了 发送图片 中的 [N]张图[keyword] 功能
|
||||
* 修复私聊 关闭[功能] 默认不为 全部 而要添加参数 ‘a’
|
||||
* 修复0权限用户可以修改禁言检测相关设置
|
||||
|
||||
### 2021/8/17
|
||||
|
||||
* 新增配置CHECK_NOTICE_INFO_CD,修改群权限,个人权限检测各种检测的提示消息cd
|
||||
* 新增功能‘连续上传图片’功能,直到输入‘stop’停止
|
||||
* 新增功能维护时白名单以及对应命令(白名单中的群聊不受维护限制)
|
||||
* 新增ALAPI功能,微博热搜,可以通过序号来查看部分热搜内容
|
||||
* 新增配置NICKNAME,偶尔也想换换名字的说(自我介绍仅当NICKNAME=真寻时生效)
|
||||
* 提供 更新信息 命令,可以使群员查看更新内容(可开关,与其他功能无异,但不会被统计,该命令图片由自动更新生成)
|
||||
* 超级用户可以通过私聊来对指定qq进行ban/unban
|
||||
* 超级用户帮助改为图片形式
|
||||
* 公开图库删除‘色图’
|
||||
* 群权限检测,个人权限检测,功能开关检测合并,权限检测顺序:个人权限 > 群权限 > 插件开关 >超级用户禁用某群插件 > 超级用户限制群里插件 > 插件维护检测
|
||||
* 重写群功能管理,超级用户可对群/私聊分别禁用,也可禁用指定群指定功能,新增命令‘功能状态’,超级用户关闭功能提供参数(默认ALL):group/g(群聊),private/p(私聊)
|
||||
* 超级用户不会被任何权限等检测阻挡
|
||||
* 不会重复复读,复读消息只会发送一次
|
||||
* b站转发解析支持b23.tv,www.bilibili.com链接,cv专栏(playwright截图,压缩倍率0.5,较慢且文字可能不清晰,后优化)
|
||||
* 我有一个朋友功能,当艾特一个对象时,‘朋友’改为艾特对象的群名片或昵称
|
||||
* 修复‘上传/删除/移动图片’目录不正确
|
||||
* 修复天气功能,当城市名在‘天气’后时报错
|
||||
* 修复配置INITIAL_SETU_PROBABILITY不生效
|
||||
|
||||
### 2021/8/10
|
||||
|
||||
* 重复的好友请求和邀群提示在5分钟内不会重复提示
|
||||
* 疫情会优先检查城市,城市省份市区重名时请添加‘市’
|
||||
* 添加命令‘原神资源查找’,‘设置cookie’
|
||||
* 添加配置AUTO_UPDATE_ZHENXUN,是否自动更新真寻,默认True
|
||||
* 添加配置MAX_RUSSIAN_BET_GOLD,俄罗斯轮盘赌注最大金额,默认1000
|
||||
* 检查更新真寻定时任务时间改为12 : 00
|
||||
* 添加功能能不能好好说话(nbnhhsh)
|
||||
* 添加功能随机roll,无参为数字,有参为随机参数
|
||||
* 添加linux重启脚本以及重启命令‘重启’(建议首次生成restart.sh先查看命令是否正确)
|
||||
* 修复管理员功能的权限检测
|
||||
* 修复丢人爬开关
|
||||
|
||||
### 2021/8/6
|
||||
|
||||
* 天气查询会优先遍历城市
|
||||
* 添加自动更新真寻命令
|
||||
|
||||
##### 如果你的版本为 2021/8/4,可以直接复制plugins/check_zhenxun_update后,通过指令来更新真寻
|
||||
|
||||
### 2021/8/4
|
||||
|
||||
* 修改天气与疫情城市数据,改为api获取,丰富疫情的回复消息
|
||||
* 原神资源查询,大地图将被压缩至9M,且启动时当大地图存在时不再自动更新地图
|
||||
* 下载数据库内色图时将直接存储至_setu,不再存储至临时文件
|
||||
* 重复的好友请求或邀请请求在一定时间不会重复发送提醒
|
||||
* 添加每日自动清理临时图片定时任务
|
||||
* 修复金币排行显示
|
||||
* 修复无法正常关闭戳一戳功能
|
||||
|
||||
### 2021/7/30
|
||||
|
||||
* 重构代码,进行优化,添加注释,删除冗余代码,降低代码耦合
|
||||
* 添加功能: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
|
||||
|
||||
* 原神今日素材改为单张截图+拼图,更新文件utils/img_utils.py及plugins/genshin/material_remind/__init__.py
|
||||
|
||||
### 2021/7/26
|
||||
|
||||
* 修复原神今日素材稻妻城开放后截图不完整的问题
|
||||
|
||||
### 2021/7/14
|
||||
|
||||
* 原神今日素材自动更新时间由 00:01 -> 04:01 [#issues7](https://github.com/HibiKier/zhenxun_bot/issues/7)
|
||||
* 小问题的修复和优化
|
||||
|
||||
### 2021/7/12
|
||||
|
||||
* 修复开箱功能单抽出金时存储格式错误导致 ‘我的金色’ 无法正常发送图片
|
||||
* 小问题的修复和优化
|
||||
|
||||
### 2021/7/6
|
||||
|
||||
* 识番功能 trace.moe 替换为新API(旧API已失效)
|
||||
* 小问题的修复和优化
|
||||
|
||||
### 2021/6/30
|
||||
|
||||
* 将plugin2name和plugin2level合并为plugin2info
|
||||
* util改为utils(。。!)
|
||||
* 修复当用户发送速度极快时开箱会突破每日限制
|
||||
* 新增功能:通过PID获取图片
|
||||
* 发送图片新增功能:搜索图片
|
||||
* 功能统计可视化
|
||||
* 新增命令:好感度总排行
|
||||
* 原神每日素材改为从"可莉特调"截图,提供命令‘更新原神每日素材’和定时任务
|
||||
* 修复月功能统计错误的问题
|
||||
|
||||
### 2021/6/24
|
||||
|
||||
* 添加了一些ALAPI:网易云热评,获取b站视频封面,古诗(需要填写ALAPI_TOKEN)
|
||||
* 如果填写了ALAPI_TOKEN,将会检测备用接口回复的文本是否合规
|
||||
* 优化了色图,当搜索色图下载失败时,会从本地色图库中发送相关tag色图
|
||||
* 当网易云点歌繁忙时会尝试多次点歌
|
||||
|
||||
### 2021/6/23
|
||||
|
||||
* 添加功能:群权限(所以说内鬼都快爬,可以在configs/config.py中修改各个功能的权限等级)
|
||||
* 优化了数据统计,将以7天,30天为周期,为将来更方便实现数据可视化
|
||||
* 更新坎公骑冠剑UP卡池
|
||||
* 修复赛马娘UP卡池
|
||||
* 修复一些小问题
|
||||
|
||||
### 2021/6/18
|
||||
|
||||
* 修复p站排行,搜图因网络问题爆炸时没有具体回复
|
||||
* 更换色图显示方式为 id,title,author,pid
|
||||
* 修复修改商品后商品顺序改变
|
||||
* 滴滴滴- 和 /t支持图片回复
|
||||
* 将/t回复更加简单(可以通过序号),且可以直接发送群
|
||||
* 修复bt功能无法交互
|
||||
|
||||
### 2021/6/17
|
||||
|
||||
* 修复p站排行,搜图因网络问题爆炸时没有具体回复
|
||||
* 更换色图显示方式为 id,title,author,pid
|
||||
|
||||
### 2021/6/15
|
||||
* 修改了‘帮助’功能,具体为‘帮助 指令名’,未指定指令名时则为查看全部功能列表
|
||||
* 修改了色图的存储数据格式
|
||||
* 色图功能搜索的色图改为随机从urls中随机抽取
|
||||
* 将商品数据存储入数据库,提供 '增加/删除/修改商品' 指令
|
||||
* 商店列表图片不再使用固定背景图,改为直接拼图
|
||||
* 增加功能:俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
|
||||
* 增加功能:金币红包(节日红包与群红包相互独立)
|
||||
* 金币排行
|
||||
* 重写一个朋友插件
|
||||
* 其他微小调整
|
||||
|
||||
### 2021/6/4
|
||||
* 重写BT功能
|
||||
* 进行一些BUG修复和微小调整
|
||||
* 添加撤回功能[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
|
||||
* 为色图功能添加额外的 上传色图 和 删除色图方法(影响hash)
|
||||
|
||||
### 2021/5/26
|
||||
* 将语录源更换为一言api
|
||||
### 2022/4/5 \[v0.1.4.6]
|
||||
|
||||
* 修复web修改插件后帮助图片生成错误
|
||||
|
||||
### 2022/4/4 \[v0.1.4.5]
|
||||
|
||||
* 替换了bt搜索URL
|
||||
* 优化使用playwright的相关代码
|
||||
* 原神玩家查询新增层岩巨渊探索
|
||||
* 修复原神便笺角色头像黑框
|
||||
* 修复同意群聊请求错误
|
||||
* 提供webui方面的api
|
||||
* 新增web-ui(前端简易管理页面插件)插件
|
||||
|
||||
### 2022/3/21
|
||||
|
||||
* 修复statistics_handle.py乱码
|
||||
|
||||
### 2022/3/18 \[v0.1.4.4]
|
||||
|
||||
* 修复戳一戳无法功能关闭与ban禁用
|
||||
* 新增图片搜索 search_image
|
||||
|
||||
### 2022/3/7
|
||||
|
||||
* 优化增删权限插件
|
||||
|
||||
### 2022/3/6
|
||||
|
||||
* 修复树脂提醒无法开启
|
||||
* 修复p搜图片路径错误
|
||||
|
||||
### 2022/3/3 \[v0.1.4.3]
|
||||
|
||||
* 修复手动同意群聊请求依旧退出
|
||||
|
||||
### 2022/3/1 \[v0.1.4.2]
|
||||
|
||||
* 0.1.4内容
|
||||
|
||||
### 2022/2/27 \[v0.1.4.1]
|
||||
|
||||
* 优化抽卡
|
||||
|
||||
### 2022/2/25 \[v0.1.4]
|
||||
|
||||
* PIX提供配置MAX_ONCE_NUM2FORWARD:当单次发送图片超过指定张数且在群聊时,将转为合并消息
|
||||
* 修复点歌无法正确发送
|
||||
* 修复我有一个朋友有时文本会包含CQ码
|
||||
* 修复群欢消息被动控制文本未删除 [@pull/124](https://github.com/HibiKier/zhenxun_bot/pull/124)
|
||||
* message_builder.image不再提供参数:abspath
|
||||
|
||||
### 2022/2/23
|
||||
|
||||
* 插件状态将从已加载插件模块中读取
|
||||
* 修复b站订阅插件订阅失败问题
|
||||
* 修复重启命令无法使用
|
||||
|
||||
### 2022/2/21 \[v0.1.3.2]
|
||||
|
||||
* 群权限为-1时,超级用户发送的命令依旧生效
|
||||
* 当群权限为-1时,被动技能也将不会发送
|
||||
* 修复功能开关,b站转发解析,复读 ignore无法使用
|
||||
* 修复色图下载文件名与路径错误
|
||||
* 修复被动技能提醒有时无法删除控制文本
|
||||
|
||||
|
||||
### 2022/2/20 \[v0.1.3.1]
|
||||
|
||||
* 修复pix下载临时文件目录错误
|
||||
* 修复AI,天气,发送图片ignore导致无法使用
|
||||
* 修复纯文本被动技能提醒有时无法删除控制文本
|
||||
|
||||
### 2022/2/19 \[v0.1.3] (nonebot beta2!)
|
||||
|
||||
* 由于nonebot升级版本,提供更新建议(__该次升级将会导致nonebot.beta1以下的插件无法使用__
|
||||
* 保证services,utils,configs,plugins,basic_plugins,文件夹均为最新
|
||||
* 根目录有pyproject.toml与poetry.lock
|
||||
* 执行命令:
|
||||
* pip3 install poetry
|
||||
* poetry install
|
||||
* poetry shell
|
||||
* playwright install chromium
|
||||
* python3 bot.py
|
||||
|
||||
|
||||
* 适配nonebot.beta2
|
||||
* 删除图片搜索 nonebot_plugin_picsearcher
|
||||
* 替换cos api
|
||||
* 原神签到树脂提醒新增绑定群里,在某群绑定uid就会在某群发送提醒信息(有好友则私聊,需要重新绑定uid
|
||||
* 修改update_info.json
|
||||
* 修复原神资源查询下载数据失败时导致报错
|
||||
* 优化BuildImage.circle()锯齿问题 [@pull/109](https://github.com/HibiKier/zhenxun_bot/pull/109)
|
||||
* epic restful 替换 [@pull/119](https://github.com/HibiKier/zhenxun_bot/pull/119)
|
||||
* fix: 修复远古时期残留的epic推送问题 [@pull/122](https://github.com/HibiKier/zhenxun_bot/pull/122)
|
||||
|
||||
### 2022/2/11
|
||||
|
||||
* 修复pix不使用反代无法下载图片
|
||||
|
||||
### 2022/2/10 \[v0.1.1]
|
||||
|
||||
* 修复购买道具出错
|
||||
|
||||
### 2022/2/9 \[v0.1]
|
||||
|
||||
* 新增原神自动签到和手动签到
|
||||
* 新增原神树脂提醒
|
||||
* 新增手动重载Config.yaml命令以及重载配置定时任务(极少部分帮助或配置可能需要重启
|
||||
* 修改了发送本地图库的matcher,改为on_message
|
||||
* register_use可以通过返回值发送消息
|
||||
* 修复修改商品时限制时间出错
|
||||
* 修复超时商品依旧可以被购买
|
||||
|
||||
### 2022/1/16 \[v0.0.9.0]
|
||||
|
||||
* Ai提供文本敏感词过滤器
|
||||
* 疫情插件适配新版腾讯API
|
||||
* 修复/t回复带空格切分
|
||||
* 修复原神玩家查询缺少渊下宫和稻妻家园以及角色不完全
|
||||
* 修复方法 text2image 中 padding 和 font 无法对纯文本生效
|
||||
* 修复签到图片中信息并未使用配置文件中的色图概率
|
||||
* 修改原神大地图合成方式,改为先压缩再合成
|
||||
* bag_user弃用字段props(该字段会在下次更新删除),使用新字段property
|
||||
* 数据库中所有belonging_group统一修改为group_id
|
||||
* 商店将registered_use和register_goods更名为register_use何register_goods
|
||||
* 商品注册提供了kwargs参数提供:
|
||||
* bot
|
||||
* event
|
||||
* 特殊字段
|
||||
* “send_success_msg”(发送成功的交互信息->即:使用道具 {name} {num} 次成功)
|
||||
* “_max_num_limit”(该道具单次使用的最多个数,默认1)
|
||||
|
||||
### 2022/1/5 \[v0.0.8.2]
|
||||
|
||||
* 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币
|
||||
* 商店插件将作为内置插件移动至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
|
||||
- [ ] 提供更多对插件的控制
|
||||
- [ ] 明日方舟卡片式的签到..(大概)
|
||||
- [ ] 更多的群管理功能
|
||||
- [ ] 数据清理控制
|
||||
- [ ] docker容器
|
||||
- [ ] web管理
|
||||
|
||||
## 感谢
|
||||
[Onebot](https://github.com/howmanybots/onebot)
|
||||
[go-cqhttp](https://github.com/Mrs4s/go-cqhttp)
|
||||
[nonebot2](https://github.com/nonebot/nonebot2)
|
||||
[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)
|
||||
[cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins#%E7%94%9F%E6%88%90%E5%99%A8%E6%8F%92%E4%BB%B6)
|
||||
[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
|
||||
[nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)
|
||||
[nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager)
|
||||
[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)
|
||||
[nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says)
|
||||
[AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus)
|
||||
[omega-miya](https://github.com/Ailitonia/omega-miya)
|
||||
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
|
||||
[Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台.
|
||||
[nonebot / nonebot2](https://github.com/nonebot/nonebot2) :跨平台Python异步机器人框架
|
||||
[Angel-Hair / XUN_Bot](https://github.com/Angel-Hair/XUN_Bot) :一个基于NoneBot和酷Q的功能性QQ机器人
|
||||
[pcrbot / cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins) :hoshino插件合集
|
||||
[MeetWq /nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw) :A simple withdraw plugin for Nonebot2
|
||||
[maxesisn / nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) :适用于nonebot2的点歌插件
|
||||
[nonepkg / nonebot-plugin-manager](https://github.com/nonepkg/nonebot-plugin-manager) :Nonebot Plugin Manager base on import hook
|
||||
[H-K-Y / Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot) :原神bot,这是一个基于nonebot和HoshinoBot的原神娱乐及信息查询插件
|
||||
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
|
||||
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
|
||||
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
|
||||
[KimigaiiWuyi / GenshinUID]("https://github.com/KimigaiiWuyi/GenshinUID") :一个基于HoshinoBot/NoneBot2的原神UID查询插件
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__: v0.0.6.4
|
||||
__version__: v0.1.4.7
|
||||
Executable → Regular
+323
-290
@@ -1,290 +1,323 @@
|
||||
from typing import List
|
||||
from nonebot.adapters.cqhttp.message import MessageSegment
|
||||
from services.log import logger
|
||||
from configs.path_config import DATA_PATH
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_local_proxy, get_bot
|
||||
from pathlib import Path
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from datetime import datetime
|
||||
from services.db_context import db
|
||||
from models.level_user import LevelUser
|
||||
from configs.config import Config
|
||||
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import asyncio
|
||||
import time
|
||||
import os
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
async def group_current_status(group_id: int) -> str:
|
||||
"""
|
||||
获取当前所有通知的开关
|
||||
:param group_id: 群号
|
||||
"""
|
||||
rst = "[被动技能 状态]\n"
|
||||
_data = group_manager.get_task_data()
|
||||
for task in _data.keys():
|
||||
rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n'
|
||||
return rst.strip()
|
||||
|
||||
|
||||
custom_welcome_msg_json = (
|
||||
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
|
||||
)
|
||||
|
||||
|
||||
async def custom_group_welcome(
|
||||
msg: str, imgs: List[str], user_id: int, group_id: int
|
||||
) -> str:
|
||||
"""
|
||||
替换群欢迎消息
|
||||
:param msg: 欢迎消息文本
|
||||
:param imgs: 欢迎消息图片,只取第一张
|
||||
:param user_id: 用户id,用于log记录
|
||||
:param group_id: 群号
|
||||
"""
|
||||
img_result = ""
|
||||
img = imgs[0] if imgs else ""
|
||||
result = ""
|
||||
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"):
|
||||
os.remove(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
|
||||
if not custom_welcome_msg_json.exists():
|
||||
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
|
||||
data = {}
|
||||
else:
|
||||
try:
|
||||
data = json.load(open(custom_welcome_msg_json, "r"))
|
||||
except FileNotFoundError:
|
||||
data = {}
|
||||
try:
|
||||
if msg:
|
||||
data[str(group_id)] = str(msg)
|
||||
json.dump(
|
||||
data, open(custom_welcome_msg_json, "w"), indent=4, ensure_ascii=False
|
||||
)
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}")
|
||||
result += msg
|
||||
if img:
|
||||
await AsyncHttpx.download_file(img, DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
|
||||
img_result = image(abspath=DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片")
|
||||
except Exception as e:
|
||||
logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}")
|
||||
return "替换群消息失败.."
|
||||
return f"替换群欢迎消息成功:\n{result}" + img_result
|
||||
|
||||
|
||||
task_data = None
|
||||
|
||||
|
||||
async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
global task_data
|
||||
"""
|
||||
修改群功能状态
|
||||
:param cmd: 功能名称
|
||||
:param group_id: 群号
|
||||
:param is_super: 是否位超级用户,超级用户用于私聊开关功能状态
|
||||
"""
|
||||
if not task_data:
|
||||
task_data = group_manager.get_task_data()
|
||||
group_help_file = Path(DATA_PATH) / "group_help" / f"{group_id}.png"
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
type_ = "plugin"
|
||||
modules = plugins2settings_manager.get_plugin_module(cmd, True)
|
||||
if cmd == "全部被动":
|
||||
for task in task_data:
|
||||
if status == "开启":
|
||||
if not await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.open_group_task(group_id, task)
|
||||
else:
|
||||
if await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.close_group_task(group_id, task)
|
||||
return f"已 {status} 全部被动技能!"
|
||||
if cmd in [task_data[x] for x in task_data.keys()]:
|
||||
type_ = "task"
|
||||
modules = [x for x in task_data.keys() if task_data[x] == cmd]
|
||||
for module in modules:
|
||||
if is_super:
|
||||
module = f"{module}:super"
|
||||
if status == "开启":
|
||||
if type_ == "task":
|
||||
if await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
|
||||
await group_manager.open_group_task(group_id, module)
|
||||
else:
|
||||
if group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于开启状态!不要重复开启."
|
||||
group_manager.unblock_plugin(module, group_id)
|
||||
else:
|
||||
if type_ == "task":
|
||||
if not await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
|
||||
await group_manager.close_group_task(group_id, module)
|
||||
else:
|
||||
if not group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
|
||||
group_manager.block_plugin(module, group_id)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
if is_super:
|
||||
for file in os.listdir(Path(DATA_PATH) / 'group_help'):
|
||||
file = Path(DATA_PATH) / 'group_help' / file
|
||||
file.unlink()
|
||||
else:
|
||||
_help_image = Path(DATA_PATH) / 'group_help' / f"{group_id}.png"
|
||||
if _help_image.exists():
|
||||
_help_image.unlink()
|
||||
return f"{status} {cmd} 功能!"
|
||||
|
||||
|
||||
def set_plugin_status(cmd: str, block_type: str = "all"):
|
||||
"""
|
||||
设置插件功能状态(超级用户使用)
|
||||
:param cmd: 功能名称
|
||||
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
|
||||
"""
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
module = plugins2settings_manager.get_plugin_module(cmd)
|
||||
if status == "开启":
|
||||
plugins_manager.unblock_plugin(module)
|
||||
else:
|
||||
plugins_manager.block_plugin(module, block_type=block_type)
|
||||
for file in os.listdir(Path(DATA_PATH) / 'group_help'):
|
||||
file = Path(DATA_PATH) / 'group_help' / file
|
||||
file.unlink()
|
||||
|
||||
|
||||
async def get_plugin_status():
|
||||
"""
|
||||
获取功能状态
|
||||
"""
|
||||
return await asyncio.get_event_loop().run_in_executor(None, _get_plugin_status)
|
||||
|
||||
|
||||
def _get_plugin_status() -> MessageSegment:
|
||||
"""
|
||||
合成功能状态图片
|
||||
"""
|
||||
rst = "\t功能\n"
|
||||
flag_str = "状态".rjust(4) + "\n"
|
||||
for module in plugins_manager.get_data():
|
||||
flag = plugins_manager.get_plugin_block_type(module)
|
||||
flag = flag.upper() + " CLOSE" if flag else "OPEN"
|
||||
try:
|
||||
plugin_name = plugins_manager.get(module)["plugin_name"]
|
||||
if (
|
||||
"[Hidden]" in plugin_name
|
||||
or "[Admin]" in plugin_name
|
||||
or "[Superuser]" in plugin_name
|
||||
):
|
||||
continue
|
||||
rst += f"{plugin_name}"
|
||||
except KeyError:
|
||||
rst += f"{module}"
|
||||
if plugins_manager.get(module)["error"]:
|
||||
rst += "[ERROR]"
|
||||
rst += "\n"
|
||||
flag_str += f"{flag}\n"
|
||||
height = len(rst.split("\n")) * 24
|
||||
a = CreateImg(250, height, font_size=20)
|
||||
a.text((10, 10), rst)
|
||||
b = CreateImg(200, height, font_size=20)
|
||||
b.text((10, 10), flag_str)
|
||||
A = CreateImg(500, height)
|
||||
A.paste(a)
|
||||
A.paste(b, (270, 0))
|
||||
return image(b64=A.pic2bs4())
|
||||
|
||||
|
||||
async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool:
|
||||
"""
|
||||
更新群成员信息
|
||||
:param group_id: 群号
|
||||
:param remind_superuser: 失败信息提醒超级用户
|
||||
"""
|
||||
bot = get_bot()
|
||||
_group_user_list = await bot.get_group_member_list(group_id=group_id)
|
||||
_error_member_list = []
|
||||
_exist_member_list = []
|
||||
# try:
|
||||
for user_info in _group_user_list:
|
||||
if user_info["card"] == "":
|
||||
nickname = user_info["nickname"]
|
||||
else:
|
||||
nickname = user_info["card"]
|
||||
async with db.transaction():
|
||||
# 更新权限
|
||||
if (
|
||||
user_info["role"]
|
||||
in [
|
||||
"owner",
|
||||
"admin",
|
||||
]
|
||||
and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
|
||||
):
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
|
||||
)
|
||||
if str(user_info["user_id"]) in bot.config.superusers:
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"], user_info["group_id"], 9
|
||||
)
|
||||
user = await GroupInfoUser.get_member_info(
|
||||
user_info["user_id"], user_info["group_id"]
|
||||
)
|
||||
if user:
|
||||
if user.user_name != nickname:
|
||||
await user.update(user_name=nickname).apply()
|
||||
logger.info(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功"
|
||||
)
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
continue
|
||||
join_time = datetime.strptime(
|
||||
time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"])
|
||||
),
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
if await GroupInfoUser.add_member_info(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
nickname,
|
||||
join_time,
|
||||
):
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
else:
|
||||
_error_member_list.append(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n"
|
||||
)
|
||||
_del_member_list = list(
|
||||
set(_exist_member_list).difference(
|
||||
set(await GroupInfoUser.get_group_member_id_list(group_id))
|
||||
)
|
||||
)
|
||||
if _del_member_list:
|
||||
for del_user in _del_member_list:
|
||||
if await GroupInfoUser.delete_member_info(del_user, group_id):
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
|
||||
else:
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
|
||||
if _error_member_list and remind_superuser:
|
||||
result = ""
|
||||
for error_user in _error_member_list:
|
||||
result += error_user
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
|
||||
)
|
||||
return True
|
||||
from typing import List
|
||||
from nonebot.adapters.onebot.v11.message import MessageSegment
|
||||
from services.log import logger
|
||||
from configs.path_config import DATA_PATH
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_bot, get_matchers
|
||||
from pathlib import Path
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from datetime import datetime
|
||||
from services.db_context import db
|
||||
from models.level_user import LevelUser
|
||||
from configs.config import Config
|
||||
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import asyncio
|
||||
import time
|
||||
import os
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
async def group_current_status(group_id: int) -> str:
|
||||
"""
|
||||
获取当前所有通知的开关
|
||||
:param group_id: 群号
|
||||
"""
|
||||
rst = "[被动技能 状态]\n"
|
||||
_data = group_manager.get_task_data()
|
||||
for task in _data.keys():
|
||||
rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n'
|
||||
return rst.strip()
|
||||
|
||||
|
||||
custom_welcome_msg_json = (
|
||||
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
|
||||
)
|
||||
|
||||
|
||||
async def custom_group_welcome(
|
||||
msg: str, imgs: List[str], user_id: int, group_id: int
|
||||
) -> str:
|
||||
"""
|
||||
替换群欢迎消息
|
||||
:param msg: 欢迎消息文本
|
||||
:param imgs: 欢迎消息图片,只取第一张
|
||||
:param user_id: 用户id,用于log记录
|
||||
:param group_id: 群号
|
||||
"""
|
||||
img_result = ""
|
||||
img = imgs[0] if imgs else ""
|
||||
result = ""
|
||||
if (DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").exists():
|
||||
(DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").unlink()
|
||||
if not custom_welcome_msg_json.exists():
|
||||
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
|
||||
data = {}
|
||||
else:
|
||||
try:
|
||||
data = json.load(open(custom_welcome_msg_json, "r"))
|
||||
except FileNotFoundError:
|
||||
data = {}
|
||||
try:
|
||||
if msg:
|
||||
data[str(group_id)] = str(msg)
|
||||
json.dump(
|
||||
data, open(custom_welcome_msg_json, "w"), indent=4, ensure_ascii=False
|
||||
)
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}")
|
||||
result += msg
|
||||
if img:
|
||||
await AsyncHttpx.download_file(
|
||||
img, DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg"
|
||||
)
|
||||
img_result = image(DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg")
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片")
|
||||
except Exception as e:
|
||||
logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}")
|
||||
return "替换群消息失败.."
|
||||
return f"替换群欢迎消息成功:\n{result}" + img_result
|
||||
|
||||
|
||||
task_data = None
|
||||
|
||||
|
||||
async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
global task_data
|
||||
"""
|
||||
修改群功能状态
|
||||
:param cmd: 功能名称
|
||||
:param group_id: 群号
|
||||
:param is_super: 是否位超级用户,超级用户用于私聊开关功能状态
|
||||
"""
|
||||
if not task_data:
|
||||
task_data = group_manager.get_task_data()
|
||||
group_help_file = DATA_PATH / "group_help" / f"{group_id}.png"
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
type_ = "plugin"
|
||||
modules = plugins2settings_manager.get_plugin_module(cmd, True)
|
||||
if cmd == "全部被动":
|
||||
for task in task_data:
|
||||
if status == "开启":
|
||||
if not await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.open_group_task(group_id, task)
|
||||
else:
|
||||
if await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.close_group_task(group_id, task)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
return f"已 {status} 全部被动技能!"
|
||||
if cmd == "全部功能":
|
||||
for f in plugins2settings_manager.get_data():
|
||||
if status == "开启":
|
||||
group_manager.unblock_plugin(f, group_id)
|
||||
else:
|
||||
group_manager.block_plugin(f, group_id)
|
||||
return f"已 {status} 全部功能!"
|
||||
if cmd in [task_data[x] for x in task_data.keys()]:
|
||||
type_ = "task"
|
||||
modules = [x for x in task_data.keys() if task_data[x] == cmd]
|
||||
for module in modules:
|
||||
if is_super:
|
||||
module = f"{module}:super"
|
||||
if status == "开启":
|
||||
if type_ == "task":
|
||||
if await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
|
||||
await group_manager.open_group_task(group_id, module)
|
||||
else:
|
||||
if group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于开启状态!不要重复开启."
|
||||
group_manager.unblock_plugin(module, group_id)
|
||||
else:
|
||||
if type_ == "task":
|
||||
if not await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
|
||||
await group_manager.close_group_task(group_id, module)
|
||||
else:
|
||||
if not group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
|
||||
group_manager.block_plugin(module, group_id)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
if is_super:
|
||||
for file in os.listdir(DATA_PATH / "group_help"):
|
||||
file = DATA_PATH / "group_help" / file
|
||||
file.unlink()
|
||||
else:
|
||||
_help_image = DATA_PATH / "group_help" / f"{group_id}.png"
|
||||
if _help_image.exists():
|
||||
_help_image.unlink()
|
||||
return f"{status} {cmd} 功能!"
|
||||
|
||||
|
||||
def set_plugin_status(cmd: str, block_type: str = "all"):
|
||||
"""
|
||||
设置插件功能状态(超级用户使用)
|
||||
:param cmd: 功能名称
|
||||
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
|
||||
"""
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
module = plugins2settings_manager.get_plugin_module(cmd)
|
||||
if status == "开启":
|
||||
plugins_manager.unblock_plugin(module)
|
||||
else:
|
||||
plugins_manager.block_plugin(module, block_type=block_type)
|
||||
for file in os.listdir(DATA_PATH / "group_help"):
|
||||
file = DATA_PATH / "group_help" / file
|
||||
file.unlink()
|
||||
|
||||
|
||||
async def get_plugin_status():
|
||||
"""
|
||||
获取功能状态
|
||||
"""
|
||||
return await asyncio.get_event_loop().run_in_executor(None, _get_plugin_status)
|
||||
|
||||
|
||||
def _get_plugin_status() -> MessageSegment:
|
||||
"""
|
||||
合成功能状态图片
|
||||
"""
|
||||
rst = "\t功能\n"
|
||||
flag_str = "状态".rjust(4) + "\n"
|
||||
tmp_name = []
|
||||
for matcher in get_matchers():
|
||||
if matcher.plugin_name not in tmp_name:
|
||||
tmp_name.append(matcher.plugin_name)
|
||||
module = matcher.plugin_name
|
||||
flag = plugins_manager.get_plugin_block_type(module)
|
||||
flag = flag.upper() + " CLOSE" if flag else "OPEN"
|
||||
try:
|
||||
plugin_name = plugins_manager.get(module)["plugin_name"]
|
||||
if (
|
||||
"[Hidden]" in plugin_name
|
||||
or "[Admin]" in plugin_name
|
||||
or "[Superuser]" in plugin_name
|
||||
):
|
||||
continue
|
||||
rst += f"{plugin_name}"
|
||||
except KeyError:
|
||||
rst += f"{module}"
|
||||
if plugins_manager.get(module)["error"]:
|
||||
rst += "[ERROR]"
|
||||
rst += "\n"
|
||||
flag_str += f"{flag}\n"
|
||||
height = len(rst.split("\n")) * 24
|
||||
a = BuildImage(250, height, font_size=20)
|
||||
a.text((10, 10), rst)
|
||||
b = BuildImage(200, height, font_size=20)
|
||||
b.text((10, 10), flag_str)
|
||||
A = BuildImage(500, height)
|
||||
A.paste(a)
|
||||
A.paste(b, (270, 0))
|
||||
return image(b64=A.pic2bs4())
|
||||
|
||||
|
||||
async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool:
|
||||
"""
|
||||
更新群成员信息
|
||||
:param group_id: 群号
|
||||
:param remind_superuser: 失败信息提醒超级用户
|
||||
"""
|
||||
bot = get_bot()
|
||||
_group_user_list = await bot.get_group_member_list(group_id=group_id)
|
||||
_error_member_list = []
|
||||
_exist_member_list = []
|
||||
# try:
|
||||
for user_info in _group_user_list:
|
||||
if user_info["card"] == "":
|
||||
nickname = user_info["nickname"]
|
||||
else:
|
||||
nickname = user_info["card"]
|
||||
async with db.transaction():
|
||||
# 更新权限
|
||||
if (
|
||||
user_info["role"]
|
||||
in [
|
||||
"owner",
|
||||
"admin",
|
||||
]
|
||||
and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
|
||||
):
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
|
||||
)
|
||||
if str(user_info["user_id"]) in bot.config.superusers:
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"], user_info["group_id"], 9
|
||||
)
|
||||
user = await GroupInfoUser.get_member_info(
|
||||
user_info["user_id"], user_info["group_id"]
|
||||
)
|
||||
if user:
|
||||
if user.user_name != nickname:
|
||||
await user.update(user_name=nickname).apply()
|
||||
logger.info(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功"
|
||||
)
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
continue
|
||||
join_time = datetime.strptime(
|
||||
time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"])
|
||||
),
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
if await GroupInfoUser.add_member_info(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
nickname,
|
||||
join_time,
|
||||
):
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
else:
|
||||
_error_member_list.append(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n"
|
||||
)
|
||||
_del_member_list = list(
|
||||
set(_exist_member_list).difference(
|
||||
set(await GroupInfoUser.get_group_member_id_list(group_id))
|
||||
)
|
||||
)
|
||||
if _del_member_list:
|
||||
for del_user in _del_member_list:
|
||||
if await GroupInfoUser.delete_member_info(del_user, group_id):
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
|
||||
else:
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
|
||||
if _error_member_list and remind_superuser:
|
||||
result = ""
|
||||
for error_user in _error_member_list:
|
||||
result += error_user
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
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 "那我先睡觉了..."
|
||||
@@ -1,7 +1,6 @@
|
||||
from nonebot import on_notice
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupAdminNoticeEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import GroupAdminNoticeEvent
|
||||
from models.level_user import LevelUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from configs.config import Config
|
||||
@@ -16,7 +15,7 @@ admin_notice = on_notice(priority=5)
|
||||
|
||||
|
||||
@admin_notice.handle()
|
||||
async def _(bot: Bot, event: GroupAdminNoticeEvent, state: T_State):
|
||||
async def _(event: GroupAdminNoticeEvent):
|
||||
try:
|
||||
nickname = (
|
||||
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from nonebot import on_command
|
||||
from utils.utils import get_message_text, get_message_imgs
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from .data_source import custom_group_welcome
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from utils.utils import get_message_img
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from ._data_source import custom_group_welcome
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from configs.config import Config
|
||||
from services.log import logger
|
||||
|
||||
@@ -35,14 +35,14 @@ custom_welcome = on_command(
|
||||
|
||||
|
||||
@custom_welcome.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
try:
|
||||
msg = get_message_text(event.json())
|
||||
imgs = get_message_imgs(event.json())
|
||||
if not msg and not imgs:
|
||||
msg = arg.extract_plain_text().strip()
|
||||
img = get_message_img(event.json())
|
||||
if not msg and not img:
|
||||
await custom_welcome.finish(__plugin_usage__)
|
||||
await custom_welcome.send(
|
||||
await custom_group_welcome(msg, imgs, event.user_id, event.group_id),
|
||||
await custom_group_welcome(msg, img, event.user_id, event.group_id),
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}")
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import Event
|
||||
from utils.manager import group_manager, plugins2settings_manager
|
||||
from utils.utils import get_message_text
|
||||
from services.log import logger
|
||||
@@ -7,17 +6,15 @@ from services.log import logger
|
||||
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 state: pass
|
||||
"""
|
||||
global cmd
|
||||
try:
|
||||
if not cmd:
|
||||
cmd.append('关闭全部被动')
|
||||
cmd.append('开启全部被动')
|
||||
cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"]
|
||||
_data = group_manager.get_task_data()
|
||||
for key in _data:
|
||||
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()
|
||||
for key in _data:
|
||||
try:
|
||||
for x in _data[key]["cmd"]:
|
||||
cmd.append(f"开启{x}")
|
||||
cmd.append(f"关闭{x}")
|
||||
cmd.append(f"开启 {x}")
|
||||
cmd.append(f"关闭 {x}")
|
||||
if isinstance(_data[key]["cmd"], list):
|
||||
for x in _data[key]["cmd"]:
|
||||
cmd.append(f"开启{x}")
|
||||
cmd.append(f"关闭{x}")
|
||||
cmd.append(f"开启 {x}")
|
||||
cmd.append(f"关闭 {x}")
|
||||
else:
|
||||
cmd.append(f"开启{key}")
|
||||
cmd.append(f"关闭{key}")
|
||||
cmd.append(f"开启 {key}")
|
||||
cmd.append(f"关闭 {key}")
|
||||
except KeyError:
|
||||
pass
|
||||
msg = get_message_text(event.json()).split()
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
from nonebot import on_command, on_message
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP
|
||||
from .data_source import (
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent, GROUP
|
||||
from nonebot import on_command, on_message, on_regex
|
||||
from nonebot.params import RegexGroup
|
||||
from ._data_source import (
|
||||
change_group_switch,
|
||||
set_plugin_status,
|
||||
get_plugin_status,
|
||||
group_current_status,
|
||||
set_group_bot_status
|
||||
)
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME, Config
|
||||
from utils.utils import get_message_text, is_number
|
||||
from nonebot.permission import SUPERUSER
|
||||
from typing import Tuple, Any
|
||||
from .rule import switch_rule
|
||||
|
||||
|
||||
@@ -24,6 +26,7 @@ usage:
|
||||
群被动状态
|
||||
开启全部被动
|
||||
关闭全部被动
|
||||
醒来/休息吧
|
||||
示例:开启/关闭色图
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
@@ -40,6 +43,7 @@ __plugin_cmd__ = [
|
||||
"群被动状态",
|
||||
"开启全部被动",
|
||||
"关闭全部被动",
|
||||
"醒来/休息吧",
|
||||
"功能状态 [_superuser]",
|
||||
"开启/关闭[功能] [group] [_superuser]",
|
||||
"开启/关闭[功能] ['private'/'group'] [_superuser]",
|
||||
@@ -57,9 +61,11 @@ plugins_status = on_command("功能状态", permission=SUPERUSER, priority=5, bl
|
||||
|
||||
group_task_status = on_command("群被动状态", permission=GROUP, priority=5, block=True)
|
||||
|
||||
group_status = on_regex("^(休息吧|醒来)$", permission=GROUP, priority=5, block=True)
|
||||
|
||||
|
||||
@switch_rule_matcher.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
_cmd = get_message_text(event.json()).split()[0]
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
await switch_rule_matcher.send(await change_group_switch(_cmd, event.group_id))
|
||||
@@ -71,7 +77,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if is_number(block_type):
|
||||
if not int(block_type) in [
|
||||
g["group_id"]
|
||||
for g in await bot.get_group_list(self_id=int(bot.self_id))
|
||||
for g in await bot.get_group_list()
|
||||
]:
|
||||
await switch_rule_matcher.finish(f"{NICKNAME}未加入群聊:{block_type}")
|
||||
await change_group_switch(_cmd, int(block_type), True)
|
||||
@@ -98,10 +104,21 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@plugins_status.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
await plugins_status.send(await get_plugin_status())
|
||||
|
||||
|
||||
@group_task_status.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
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}")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 models.group_info import GroupInfo
|
||||
from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from nonebot import on_command, on_notice
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
|
||||
from .data_source import update_member_info
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
|
||||
from ._data_source import update_member_info
|
||||
|
||||
__zx_plugin_name__ = "更新群组成员列表 [Admin]"
|
||||
__plugin_usage__ = """
|
||||
@@ -25,7 +24,7 @@ refresh_member_group = on_command(
|
||||
|
||||
|
||||
@refresh_member_group.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
if await update_member_info(event.group_id):
|
||||
await refresh_member_group.finish("更新群员信息成功!", at_sender=True)
|
||||
else:
|
||||
@@ -36,6 +35,6 @@ group_increase_handle = on_notice(priority=1, block=False)
|
||||
|
||||
|
||||
@group_increase_handle.handle()
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
|
||||
if event.user_id == int(bot.self_id):
|
||||
await update_member_info(event.group_id)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
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 .data_source import create_help_image, admin_help_image
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
from utils.manager import group_manager
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from pathlib import Path
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot import Driver
|
||||
import asyncio
|
||||
import nonebot
|
||||
@@ -12,9 +11,9 @@ import nonebot
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
background = Path(IMAGE_PATH) / "background" / "0.png"
|
||||
background = IMAGE_PATH / "background" / "0.png"
|
||||
|
||||
admin_help_image = Path(IMAGE_PATH) / 'admin_help_img.png'
|
||||
admin_help_image = IMAGE_PATH / 'admin_help_img.png'
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
@@ -42,7 +41,7 @@ def _create_help_image():
|
||||
width = 0
|
||||
_plugin_level = {}
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
@@ -71,7 +70,7 @@ def _create_help_image():
|
||||
x = len(f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)) * 23
|
||||
width = width if width > x else x
|
||||
except AttributeError:
|
||||
logger.warning(f"获取管理插件 {matcher.module}: {plugin_name} 设置失败...")
|
||||
logger.warning(f"获取管理插件 {matcher.plugin_name}: {plugin_name} 设置失败...")
|
||||
help_str = "* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" \
|
||||
"[权限等级] 管理员帮助:\n\n"
|
||||
x = list(_plugin_level.keys())
|
||||
@@ -84,8 +83,8 @@ def _create_help_image():
|
||||
for i, x in enumerate(task_data.keys()):
|
||||
help_str += f'{i+1}.开启/关闭{task_data[x]}\n\n'
|
||||
height = len(help_str.split("\n")) * 33
|
||||
A = CreateImg(width, height, font_size=24)
|
||||
_background = CreateImg(width, height, background=background)
|
||||
A = BuildImage(width, height, font_size=24)
|
||||
_background = BuildImage(width, height, background=background)
|
||||
A.text((150, 110), help_str)
|
||||
A.paste(_background, alpha=True)
|
||||
A.save(admin_help_image)
|
||||
|
||||
@@ -4,9 +4,11 @@ from nonebot import on_message
|
||||
from services.log import logger
|
||||
from models.group_info import GroupInfo
|
||||
from models.friend_user import FriendUser
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from configs.config import NICKNAME
|
||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||
from configs.config import NICKNAME, Config
|
||||
from utils.manager import group_manager
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
__zx_plugin_name__ = "定时任务相关 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
@@ -14,7 +16,33 @@ __plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {'zwa': '早晚安'}
|
||||
|
||||
|
||||
x = on_message(priority=9, block=False)
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_ZWA",
|
||||
True,
|
||||
help_="被动 早晚安 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_backup",
|
||||
"BACKUP_FLAG",
|
||||
True,
|
||||
help_="是否开启文件备份",
|
||||
default_value=True
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_backup",
|
||||
"BACKUP_DIR_OR_FILE",
|
||||
['data/black_word', 'data/configs', 'data/statistics', 'data/word_bank', 'data/manager', 'configs'],
|
||||
name="文件备份",
|
||||
help_="备份的文件夹或文件",
|
||||
default_value=[]
|
||||
)
|
||||
|
||||
|
||||
cx = on_message(priority=9, block=False)
|
||||
|
||||
|
||||
# 早上好
|
||||
@@ -29,12 +57,11 @@ async def _():
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
for g in gl:
|
||||
if await group_manager.check_group_task_status(g, 'zwa'):
|
||||
result = image("zao.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(group_id=g, message="早上好" + result)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送早安")
|
||||
result = image("zao.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + result)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送早安")
|
||||
except Exception as e:
|
||||
logger.error(f"早晚安错误 e:{e}")
|
||||
|
||||
@@ -51,14 +78,13 @@ async def _():
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
for g in gl:
|
||||
if await group_manager.check_group_task_status(g, 'zwa'):
|
||||
result = image("sleep.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(
|
||||
group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result
|
||||
)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送晚安")
|
||||
result = image("sleep.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(
|
||||
group_id=g, message=f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + result
|
||||
)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送晚安")
|
||||
except Exception as e:
|
||||
logger.error(f"早晚安错误 e:{e}")
|
||||
|
||||
@@ -106,6 +132,34 @@ async def _():
|
||||
logger.error(f"自动更新群组信息错误 e:{e}")
|
||||
|
||||
|
||||
# 自动备份
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=3,
|
||||
minute=25,
|
||||
)
|
||||
async def _():
|
||||
if Config.get_config("_backup", "BACKUP_FLAG"):
|
||||
_backup_path = Path() / 'backup'
|
||||
_backup_path.mkdir(exist_ok=True, parents=True)
|
||||
for x in Config.get_config("_backup", "BACKUP_DIR_OR_FILE"):
|
||||
try:
|
||||
path = Path(x)
|
||||
_p = _backup_path / x
|
||||
if path.exists():
|
||||
if path.is_dir():
|
||||
if _p.exists():
|
||||
shutil.rmtree(_p, ignore_errors=True)
|
||||
shutil.copytree(x, _p)
|
||||
else:
|
||||
if _p.exists():
|
||||
_p.unlink()
|
||||
shutil.copy(x, _p)
|
||||
logger.info(f'已完成自动备份:{x}')
|
||||
except Exception as e:
|
||||
logger.error(f"自动备份文件 {x} 发生错误 {type(e)}:{e}")
|
||||
|
||||
|
||||
# 一次性任务
|
||||
# 固定时间触发,仅触发一次:
|
||||
#
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent, MessageEvent, Message, Bot
|
||||
from nonebot.params import CommandArg, Command
|
||||
from nonebot import on_command
|
||||
from models.ban_user import BanUser
|
||||
from models.level_user import LevelUser
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent, MessageEvent
|
||||
from utils.utils import get_message_at, get_message_text, is_number
|
||||
from typing import Tuple
|
||||
from utils.utils import get_message_at, is_number
|
||||
from configs.config import NICKNAME, Config
|
||||
from nonebot.permission import SUPERUSER
|
||||
from .data_source import parse_ban_time, a_ban
|
||||
from services.log import logger
|
||||
|
||||
|
||||
@@ -61,62 +62,35 @@ super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True)
|
||||
|
||||
|
||||
@ban.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
result = ""
|
||||
qq = get_message_at(event.json())
|
||||
if qq:
|
||||
qq = qq[0]
|
||||
user_name = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
|
||||
user_name = user_name['card'] if user_name['card'] else user_name['nickname']
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
msg = msg.split()
|
||||
if len(msg) == 2:
|
||||
if not is_number(msg[0].strip()) or not is_number(msg[1].strip()):
|
||||
await ban.finish("参数必须是数字!", at_sender=True)
|
||||
time = int(msg[0]) * 60 * 60 + int(msg[1]) * 60
|
||||
else:
|
||||
if not is_number(msg[0].strip()):
|
||||
await ban.finish("参数必须是数字!", at_sender=True)
|
||||
time = int(msg[0]) * 60 * 60
|
||||
else:
|
||||
time = -1
|
||||
if state["_prefix"]["raw_command"] in [".ban", "/ban"]:
|
||||
user_name = user_name['card'] or user_name['nickname']
|
||||
msg = arg.extract_plain_text().strip()
|
||||
time = parse_ban_time(msg)
|
||||
if isinstance(time, str):
|
||||
await ban.finish(time, at_sender=True)
|
||||
if cmd in [".ban", "/ban"]:
|
||||
if (
|
||||
await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
<= await LevelUser.get_user_level(qq, event.group_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
<= await LevelUser.get_user_level(qq, event.group_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
await ban.finish(
|
||||
f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!",
|
||||
at_sender=True,
|
||||
)
|
||||
if await BanUser.ban(
|
||||
qq, await LevelUser.get_user_level(event.user_id, event.group_id), time
|
||||
):
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time/60} 分钟"
|
||||
)
|
||||
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
|
||||
if time != -1:
|
||||
result += f"将在 {time/60} 分钟后解封"
|
||||
else:
|
||||
time = await BanUser.check_ban_time(qq)
|
||||
if is_number(time):
|
||||
time = abs(int(time))
|
||||
if time < 60:
|
||||
time = str(time) + " 秒"
|
||||
else:
|
||||
time = str(int(time / 60)) + " 分钟"
|
||||
else:
|
||||
time += " 分钟"
|
||||
result = f"{user_name} 已在黑名单!预计 {time}后解封"
|
||||
result = await a_ban(qq, time, user_name, event)
|
||||
else:
|
||||
if (
|
||||
await BanUser.check_ban_level(
|
||||
qq, await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
await BanUser.check_ban_level(
|
||||
qq, await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
await ban.finish(
|
||||
f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True
|
||||
@@ -130,78 +104,53 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
result = f"{user_name} 不在黑名单!"
|
||||
else:
|
||||
await ban.finish("艾特人了吗??", at_sender=True)
|
||||
await ban.finish(result, at_sender=True)
|
||||
await ban.send(result, at_sender=True)
|
||||
|
||||
|
||||
@ban.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
msg = get_message_text(event.json())
|
||||
msg = msg.split()
|
||||
if is_number(msg[0]):
|
||||
qq = int(msg[0])
|
||||
if state["_prefix"]["raw_command"] in [".ban", "/ban"]:
|
||||
hour = 0
|
||||
minute = 0
|
||||
if len(msg) > 1 and is_number(msg[1]):
|
||||
hour = int(msg[1])
|
||||
if len(msg) > 2 and is_number(msg[2]):
|
||||
minute = int(msg[2])
|
||||
time = hour * 60 * 60 + minute * 60
|
||||
time = time if time else -1
|
||||
if await BanUser.ban(
|
||||
qq, 9, time
|
||||
):
|
||||
logger.info(
|
||||
f"USER {event.user_id} 将 USER {qq} 封禁 时长 {time/60} 分钟"
|
||||
)
|
||||
result = f"已经将 {qq} 加入{NICKNAME}的黑名单了!"
|
||||
if time != -1:
|
||||
result += f"将在 {time/60} 分钟后解封"
|
||||
else:
|
||||
result += f"将在 ∞ 分钟后解封"
|
||||
await ban.send(result)
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if msg:
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
if is_number(arg.extract_plain_text().strip().split()[0]):
|
||||
qq = int(msg[0])
|
||||
msg = msg[1:]
|
||||
if cmd in [".ban", "/ban"]:
|
||||
time = parse_ban_time(msg)
|
||||
if isinstance(time, str):
|
||||
await ban.finish(time)
|
||||
result = await a_ban(qq, time, str(qq), event, 9)
|
||||
else:
|
||||
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)) + " 分钟"
|
||||
if await BanUser.unban(qq):
|
||||
logger.info(
|
||||
f"USER {event.user_id} 将 USER {qq} 解禁"
|
||||
)
|
||||
result = f"已经把 {qq} 从黑名单中删除了!"
|
||||
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} 不在黑名单!"
|
||||
result = f"{qq} 不在黑名单!"
|
||||
await ban.send(result)
|
||||
else:
|
||||
await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
|
||||
else:
|
||||
await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
|
||||
|
||||
|
||||
@super_ban.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
qq = get_message_at(event.json())
|
||||
else:
|
||||
qq = get_message_text(event.json())
|
||||
qq = arg.extract_plain_text().strip()
|
||||
if not is_number(qq):
|
||||
await super_ban.finish("对象qq必须为纯数字...")
|
||||
qq = [qq]
|
||||
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']
|
||||
user_name = user['card'] or 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的对象..')
|
||||
await super_ban.send('需要添加被super ban的对象,可以使用at或者指定qq..')
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.permission import SUPERUSER
|
||||
import asyncio
|
||||
from utils.utils import get_message_text, get_message_imgs
|
||||
from nonebot.params import CommandArg
|
||||
from utils.utils import get_message_img
|
||||
from services.log import logger
|
||||
from utils.message_builder import image
|
||||
from utils.manager import group_manager
|
||||
from configs.config import Config
|
||||
import asyncio
|
||||
|
||||
|
||||
__zx_plugin_name__ = "广播 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
@@ -20,19 +22,25 @@ __plugin_cmd__ = ["广播-"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {"broadcast": "广播"}
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_BROADCAST",
|
||||
True,
|
||||
help_="被动 广播 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@broadcast.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
imgs = get_message_imgs(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
img_list = get_message_img(event.json())
|
||||
rst = ""
|
||||
for img in imgs:
|
||||
for img in img_list:
|
||||
rst += image(img)
|
||||
sid = bot.self_id
|
||||
gl = await bot.get_group_list(self_id=sid)
|
||||
gl = await bot.get_group_list()
|
||||
gl = [
|
||||
g["group_id"]
|
||||
for g in gl
|
||||
@@ -48,7 +56,7 @@ async def _(bot: Bot, event: Event, state: T_State):
|
||||
await broadcast.send(f"已播报至 {int(cnt / g_cnt * 100)}% 的群聊")
|
||||
x += 0.25
|
||||
try:
|
||||
await bot.send_group_msg(self_id=sid, group_id=g, message=msg + rst)
|
||||
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)}")
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
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
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
"chat_history",
|
||||
"FLAG",
|
||||
True,
|
||||
help_="是否开启消息自从存储",
|
||||
name="消息存储",
|
||||
default_value=True
|
||||
)
|
||||
|
||||
|
||||
chat_history = on_message(rule=rule)
|
||||
|
||||
# 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))
|
||||
@@ -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)
|
||||
@@ -4,12 +4,12 @@ from utils.message_builder import image
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from datetime import datetime
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
GroupIncreaseNoticeEvent,
|
||||
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 configs.config import NICKNAME
|
||||
from models.group_info import GroupInfo
|
||||
@@ -38,6 +38,22 @@ Config.add_plugin_config(
|
||||
Config.add_plugin_config(
|
||||
"invite_manager", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_GROUP_WELCOME",
|
||||
True,
|
||||
help_="被动 进群欢迎 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_REFUND_GROUP_REMIND",
|
||||
True,
|
||||
help_="被动 退群提醒 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
|
||||
_flmt = FreqLimiter(Config.get_config("invite_manager", "welcome_msg_cd"))
|
||||
|
||||
|
||||
@@ -50,7 +66,7 @@ add_group = on_request(priority=1, block=False)
|
||||
|
||||
|
||||
@group_increase_handle.handle()
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
|
||||
if event.user_id == int(bot.self_id):
|
||||
group = await GroupInfo.get_group_info(event.group_id)
|
||||
# 群聊不存在或被强制拉群,退出该群
|
||||
@@ -96,9 +112,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
|
||||
|
||||
# 群欢迎消息
|
||||
if await group_manager.check_group_task_status(
|
||||
event.group_id, "group_welcome"
|
||||
) and _flmt.check(event.group_id):
|
||||
if _flmt.check(event.group_id):
|
||||
_flmt.start_cd(event.group_id)
|
||||
msg = ""
|
||||
img = ""
|
||||
@@ -113,23 +127,25 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
if msg.find("[at]") != -1:
|
||||
msg = msg.replace("[at]", "")
|
||||
at_flag = True
|
||||
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"):
|
||||
if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists():
|
||||
img = image(
|
||||
abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"
|
||||
DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg"
|
||||
)
|
||||
if msg or img:
|
||||
msg = msg.strip() + img
|
||||
msg = "\n" + msg if at_flag else msg
|
||||
await group_increase_handle.send(
|
||||
"\n" + msg.strip() + img, at_sender=at_flag
|
||||
"[[_task|group_welcome]]" + msg, at_sender=at_flag
|
||||
)
|
||||
else:
|
||||
await group_increase_handle.send(
|
||||
"新人快跑啊!!本群现状↓(快使用自定义!)"
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz")
|
||||
"[[_task|group_welcome]]新人快跑啊!!本群现状↓(快使用自定义!)"
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH / "qxz")), "qxz")
|
||||
)
|
||||
|
||||
|
||||
@group_decrease_handle.handle()
|
||||
async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
|
||||
async def _(bot: Bot, event: GroupDecreaseNoticeEvent):
|
||||
# 被踢出群
|
||||
if event.sub_type == "kick_me":
|
||||
group_id = event.group_id
|
||||
@@ -164,21 +180,16 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
|
||||
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除成功")
|
||||
else:
|
||||
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败")
|
||||
if await group_manager.check_group_task_status(
|
||||
event.group_id, "refund_group_remind"
|
||||
):
|
||||
rst = ""
|
||||
if event.sub_type == "leave":
|
||||
rst = f"{user_name}离开了我们..."
|
||||
if event.sub_type == "kick":
|
||||
operator = await bot.get_group_member_info(
|
||||
user_id=event.operator_id, group_id=event.group_id
|
||||
)
|
||||
operator_name = (
|
||||
operator["card"] if operator["card"] else operator["nickname"]
|
||||
)
|
||||
rst = f"{user_name} 被 {operator_name} 送走了."
|
||||
try:
|
||||
await group_decrease_handle.send(f"{rst}")
|
||||
except ActionFailed:
|
||||
return
|
||||
rst = ""
|
||||
if event.sub_type == "leave":
|
||||
rst = f"{user_name}离开了我们..."
|
||||
if event.sub_type == "kick":
|
||||
operator = await bot.get_group_member_info(
|
||||
user_id=event.operator_id, group_id=event.group_id
|
||||
)
|
||||
operator_name = operator["card"] if operator["card"] else operator["nickname"]
|
||||
rst = f"{user_name} 被 {operator_name} 送走了."
|
||||
try:
|
||||
await group_decrease_handle.send(f"[[_task|refund_group_remind]]{rst}")
|
||||
except ActionFailed:
|
||||
return
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent
|
||||
GroupMessageEvent,
|
||||
Message
|
||||
)
|
||||
from nonebot.params import CommandArg
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
from configs.path_config import IMAGE_PATH, DATA_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_help_img, get_plugin_help
|
||||
from utils.utils import get_message_text
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
|
||||
__zx_plugin_name__ = "帮助"
|
||||
|
||||
group_help_path = Path(DATA_PATH) / "group_help"
|
||||
help_image = Path(IMAGE_PATH) / "help.png"
|
||||
simple_help_image = Path(IMAGE_PATH) / "simple_help.png"
|
||||
group_help_path = DATA_PATH / "group_help"
|
||||
help_image = IMAGE_PATH / "help.png"
|
||||
simple_help_image = IMAGE_PATH / "simple_help.png"
|
||||
if help_image.exists():
|
||||
help_image.unlink()
|
||||
if simple_help_image.exists():
|
||||
@@ -44,8 +44,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@simple_help.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
is_super = False
|
||||
if msg:
|
||||
if '-super' in msg:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.manager import (
|
||||
plugins2settings_manager,
|
||||
@@ -16,9 +16,9 @@ import nonebot
|
||||
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(
|
||||
@@ -50,12 +50,12 @@ def _create_help_img(
|
||||
_des_tmp = {}
|
||||
_plugin_name_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
|
||||
# 插件分类
|
||||
for matcher in _matchers:
|
||||
plugin_name = None
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
@@ -74,10 +74,10 @@ def _create_help_img(
|
||||
plugin_type = ("normal",)
|
||||
text_type = 0
|
||||
if plugins2settings_manager.get(
|
||||
matcher.module
|
||||
) and plugins2settings_manager[matcher.module].get("plugin_type"):
|
||||
matcher.plugin_name
|
||||
) and plugins2settings_manager[matcher.plugin_name].get("plugin_type"):
|
||||
plugin_type = tuple(
|
||||
plugins2settings_manager.get_plugin_data(matcher.module)[
|
||||
plugins2settings_manager.get_plugin_data(matcher.plugin_name)[
|
||||
"plugin_type"
|
||||
]
|
||||
)
|
||||
@@ -111,7 +111,7 @@ def _create_help_img(
|
||||
logger.warning(f"{type(e)}: {e}")
|
||||
else:
|
||||
matchers_data[plugin_type][plugin_name] = {
|
||||
"module": matcher.module,
|
||||
"modules": matcher.plugin_name,
|
||||
"des": plugin_des,
|
||||
"cmd": plugin_cmd,
|
||||
"text_type": text_type,
|
||||
@@ -129,7 +129,7 @@ def _create_help_img(
|
||||
_des_tmp[plugin_des] = plugin_name
|
||||
except AttributeError as e:
|
||||
if plugin_name not in _plugin_name_tmp:
|
||||
logger.warning(f"获取功能 {matcher.module}: {plugin_name} 设置失败...e:{e}")
|
||||
logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e:{e}")
|
||||
if plugin_name not in _plugin_name_tmp:
|
||||
_plugin_name_tmp.append(plugin_name)
|
||||
help_img_list = []
|
||||
@@ -147,16 +147,16 @@ def _create_help_img(
|
||||
# 禁用flag
|
||||
flag = True
|
||||
if plugins_manager.get_plugin_status(
|
||||
matchers_data[type_][k]["module"], "all"
|
||||
matchers_data[type_][k]["modules"], "all"
|
||||
):
|
||||
flag = False
|
||||
if group_id:
|
||||
flag = flag and plugins_manager.get_plugin_status(
|
||||
matchers_data[type_][k]["module"], "group"
|
||||
matchers_data[type_][k]["modules"], "group"
|
||||
)
|
||||
simple_help_str += (
|
||||
f"{i+1}.{k}<|_|~|>"
|
||||
f"{group_manager.get_plugin_status(matchers_data[type_][k]['module'], group_id) if group_id else '_'}|"
|
||||
f"{group_manager.get_plugin_status(matchers_data[type_][k]['modules'], group_id) if group_id else '_'}|"
|
||||
f"{flag}\n"
|
||||
)
|
||||
if matchers_data[type_][k]["text_type"] == 1:
|
||||
@@ -181,7 +181,7 @@ def _create_help_img(
|
||||
)
|
||||
height = len(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"
|
||||
)
|
||||
A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
|
||||
@@ -192,8 +192,8 @@ def _create_help_img(
|
||||
for x in simple_help_str.split("\n")
|
||||
]:
|
||||
simple_width = simple_width if simple_width > x else x
|
||||
bk = CreateImg(simple_width + 20, simple_height, font_size=24, color="#6495ED")
|
||||
B = CreateImg(
|
||||
bk = BuildImage(simple_width + 20, simple_height, font_size=24, color="#6495ED")
|
||||
B = BuildImage(
|
||||
simple_width + 20,
|
||||
simple_height,
|
||||
font_size=24,
|
||||
@@ -236,7 +236,7 @@ def _create_help_img(
|
||||
for img in help_img_list:
|
||||
height += img.h
|
||||
if not group_id:
|
||||
A = CreateImg(width + 150, height + 50, font_size=24)
|
||||
A = BuildImage(width + 150, height + 50, font_size=24)
|
||||
A.text(
|
||||
(10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n'
|
||||
)
|
||||
@@ -253,14 +253,14 @@ def _create_help_img(
|
||||
if img.h > height:
|
||||
height = img.h
|
||||
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)
|
||||
bk = None
|
||||
random_bk = os.listdir(random_bk_path)
|
||||
if random_bk:
|
||||
bk = random.choice(random_bk)
|
||||
x = max(width + 50, height + 250)
|
||||
B = CreateImg(
|
||||
B = BuildImage(
|
||||
x,
|
||||
x,
|
||||
font_size=24,
|
||||
@@ -272,7 +272,7 @@ def _create_help_img(
|
||||
w = 10
|
||||
h = 10
|
||||
for msg in ["目前支持的功能列表:", "可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法", "或者使用 ‘详细帮助’ 来获取所有功能方法"]:
|
||||
text = CreateImg(
|
||||
text = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=msg,
|
||||
@@ -284,7 +284,7 @@ def _create_help_img(
|
||||
if msg == "目前支持的功能列表:":
|
||||
w += 50
|
||||
B.paste(
|
||||
CreateImg(
|
||||
BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护",
|
||||
@@ -299,8 +299,8 @@ def _create_help_img(
|
||||
|
||||
|
||||
def get_max_width_or_paste(
|
||||
simple_help_img_list: list, B: CreateImg = None, is_paste: bool = False
|
||||
) -> "int, CreateImg":
|
||||
simple_help_img_list: list, B: BuildImage = None, is_paste: bool = False
|
||||
) -> "int, BuildImage":
|
||||
"""
|
||||
获取最大宽度,或直接贴图
|
||||
:param simple_help_img_list: 简单帮助图片列表
|
||||
@@ -353,11 +353,11 @@ def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
|
||||
_width = len(x) * 24
|
||||
width = width if width > _width else _width
|
||||
height = len(result.split("\n")) * 45
|
||||
A = CreateImg(width, height, font_size=24)
|
||||
bk = CreateImg(
|
||||
A = BuildImage(width, height, font_size=24)
|
||||
bk = BuildImage(
|
||||
width,
|
||||
height,
|
||||
background=Path(IMAGE_PATH) / "background" / "1.png",
|
||||
background=IMAGE_PATH / "background" / "1.png",
|
||||
)
|
||||
A.paste(bk, alpha=True)
|
||||
A.text((int(width * 0.048), int(height * 0.21)), result)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from configs.config import Config
|
||||
import nonebot
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
@@ -35,4 +34,3 @@ Config.add_plugin_config(
|
||||
default_value=6
|
||||
)
|
||||
|
||||
nonebot.load_plugins("basic_plugins/hooks")
|
||||
|
||||
Executable → Regular
+52
-48
@@ -1,48 +1,52 @@
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent
|
||||
from utils.manager import plugins2block_manager, StaticData
|
||||
import time
|
||||
|
||||
|
||||
class StatusMessageManager(StaticData):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
|
||||
def add(self, id_: int):
|
||||
self._data[id_] = time.time()
|
||||
|
||||
def delete(self, id_: int):
|
||||
if self._data.get(id_):
|
||||
del self._data[id_]
|
||||
|
||||
def check(self, id_: int, t: int = 30) -> bool:
|
||||
if self._data.get(id_):
|
||||
if time.time() - self._data[id_] > t:
|
||||
del self._data[id_]
|
||||
return True
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
status_message_manager = StatusMessageManager()
|
||||
|
||||
|
||||
def set_block_limit_false(event, module):
|
||||
"""
|
||||
设置用户block为false
|
||||
:param event: event
|
||||
:param module: 插件模块
|
||||
"""
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
if not (
|
||||
(isinstance(event, GroupMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, PrivateMessageEvent) and check_type == "group")
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
plugins2block_manager.set_false(block_type_, module)
|
||||
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent
|
||||
from utils.manager import plugins2block_manager, StaticData
|
||||
import time
|
||||
|
||||
ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
|
||||
other_limit_plugins = ["poke"]
|
||||
|
||||
|
||||
class StatusMessageManager(StaticData):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
|
||||
def add(self, id_: int):
|
||||
self._data[id_] = time.time()
|
||||
|
||||
def delete(self, id_: int):
|
||||
if self._data.get(id_):
|
||||
del self._data[id_]
|
||||
|
||||
def check(self, id_: int, t: int = 30) -> bool:
|
||||
if self._data.get(id_):
|
||||
if time.time() - self._data[id_] > t:
|
||||
del self._data[id_]
|
||||
return True
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
status_message_manager = StatusMessageManager()
|
||||
|
||||
|
||||
def set_block_limit_false(event, module):
|
||||
"""
|
||||
设置用户block为false
|
||||
:param event: event
|
||||
:param module: 插件模块
|
||||
"""
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
if not (
|
||||
(isinstance(event, GroupMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, PrivateMessageEvent) and check_type == "group")
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
plugins2block_manager.set_false(block_type_, module)
|
||||
|
||||
@@ -1,26 +1,41 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.bag_user import BagUser
|
||||
from utils.manager import (
|
||||
plugins2settings_manager,
|
||||
admin_manager,
|
||||
group_manager,
|
||||
plugins_manager,
|
||||
plugins2cd_manager,
|
||||
plugins2block_manager,
|
||||
plugins2count_manager,
|
||||
)
|
||||
from ._utils import (
|
||||
set_block_limit_false,
|
||||
status_message_manager,
|
||||
ignore_rst_module,
|
||||
other_limit_plugins,
|
||||
)
|
||||
from .utils import set_block_limit_false, status_message_manager
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from typing import Optional
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
PokeNotifyEvent,
|
||||
PrivateMessageEvent,
|
||||
Message,
|
||||
Event,
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
from utils.utils import FreqLimiter
|
||||
from utils.message_builder import at
|
||||
from models.level_user import LevelUser
|
||||
|
||||
import nonebot
|
||||
|
||||
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
@@ -28,28 +43,69 @@ _flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
|
||||
|
||||
ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
|
||||
|
||||
# 权限检测
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
module = matcher.module
|
||||
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
||||
module = matcher.plugin_name
|
||||
plugins2info_dict = plugins2settings_manager.get_data()
|
||||
if (
|
||||
(not isinstance(event, MessageEvent) and module != "poke")
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
) or (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
return
|
||||
# 群黑名单检测
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if group_manager.get_group_level(event.group_id) < 0:
|
||||
raise IgnoredException("群黑名单")
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
cost_gold = 0
|
||||
if isinstance(
|
||||
event, GroupMessageEvent
|
||||
) and plugins2settings_manager.get_plugin_data(module).get("cost_gold"):
|
||||
cost_gold = plugins2settings_manager.get_plugin_data(module).get("cost_gold")
|
||||
if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
|
||||
await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
|
||||
raise IgnoredException(f"{module} 金币限制...")
|
||||
# 当插件不阻塞超级用户时,超级用户提前扣除金币
|
||||
if (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
try:
|
||||
if (
|
||||
(not isinstance(event, MessageEvent) and module not in other_limit_plugins)
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
) or (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
# 超级用户命令
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(module)
|
||||
_module = _plugin.module
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if (
|
||||
"[superuser]" in plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
# 群黑名单检测 群总开关检测
|
||||
if isinstance(event, GroupMessageEvent) or matcher.plugin_name == other_limit_plugins:
|
||||
try:
|
||||
if (
|
||||
group_manager.get_group_level(event.group_id) < 0
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
raise IgnoredException("群黑名单")
|
||||
if not group_manager.check_group_bot_status(event.group_id):
|
||||
try:
|
||||
if str(event.get_message()) != "醒来":
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except ValueError:
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except AttributeError:
|
||||
pass
|
||||
if module in admin_manager.keys() and matcher.priority not in [1, 9]:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
# 个人权限
|
||||
@@ -92,9 +148,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
raise IgnoredException("权限不足")
|
||||
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
|
||||
# 戳一戳单独判断
|
||||
if isinstance(event, GroupMessageEvent) or (
|
||||
isinstance(event, PokeNotifyEvent) and event.group_id
|
||||
):
|
||||
if isinstance(event, GroupMessageEvent) or isinstance(event, PokeNotifyEvent) or matcher.plugin_name in other_limit_plugins:
|
||||
if status_message_manager.get(event.group_id) is None:
|
||||
status_message_manager.delete(event.group_id)
|
||||
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
|
||||
@@ -208,3 +262,125 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
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
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
from nonebot.matcher import Matcher
|
||||
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.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
Event,
|
||||
MessageEvent,
|
||||
PokeNotifyEvent,
|
||||
GroupMessageEvent,
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
from utils.utils import is_number, static_flmt
|
||||
from utils.utils import is_number, static_flmt, FreqLimiter
|
||||
from utils.message_builder import at
|
||||
from ._utils import ignore_rst_module, other_limit_plugins
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
@@ -20,21 +23,24 @@ Config.add_plugin_config(
|
||||
help_="对被ban用户发送的消息",
|
||||
)
|
||||
|
||||
_flmt = FreqLimiter(300)
|
||||
|
||||
|
||||
# 检查是否被ban
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
try:
|
||||
if (
|
||||
await BanUser.is_super_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
raise IgnoredException("用户处于超级黑名单中")
|
||||
except AttributeError:
|
||||
pass
|
||||
if not isinstance(event, MessageEvent):
|
||||
return
|
||||
if matcher.type == "message" and matcher.priority not in [1, 9]:
|
||||
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
||||
if (
|
||||
(isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent))
|
||||
and matcher.priority not in [1, 9]
|
||||
) or matcher.plugin_name in other_limit_plugins:
|
||||
try:
|
||||
if (
|
||||
await BanUser.is_super_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
raise IgnoredException("用户处于超级黑名单中")
|
||||
except AttributeError:
|
||||
pass
|
||||
if (
|
||||
await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
@@ -55,7 +61,12 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if matcher.priority != 9:
|
||||
try:
|
||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||
if ban_result:
|
||||
if (
|
||||
ban_result
|
||||
and _flmt.check(event.user_id)
|
||||
and matcher.plugin_name not in ignore_rst_module
|
||||
):
|
||||
_flmt.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=at(event.user_id)
|
||||
@@ -71,7 +82,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if matcher.priority != 9:
|
||||
try:
|
||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||
if 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)
|
||||
@@ -80,4 +91,4 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
raise IgnoredException("用户处于黑名单中")
|
||||
raise IgnoredException("用户处于黑名单中")
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from nonebot.matcher import Matcher
|
||||
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.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
|
||||
@@ -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
|
||||
@@ -1,13 +1,16 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.typing import T_State
|
||||
from .utils import status_message_manager
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from ._utils import status_message_manager
|
||||
from utils.image_utils import text2image
|
||||
from typing import Dict, Any
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
PrivateMessageEvent,
|
||||
GroupMessageEvent,
|
||||
)
|
||||
import re
|
||||
|
||||
|
||||
# 为什么AI会自己和自己聊天
|
||||
@@ -24,7 +27,7 @@ async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_Sta
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if not isinstance(event, MessageEvent):
|
||||
return
|
||||
if matcher.type == "message" and matcher.module == "ai":
|
||||
if matcher.type == "message" and matcher.plugin_name == "ai":
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
and not status_message_manager.check(event.group_id)
|
||||
@@ -35,7 +38,14 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
isinstance(event, PrivateMessageEvent)
|
||||
and not status_message_manager.check(event.user_id)
|
||||
):
|
||||
print(status_message_manager)
|
||||
status_message_manager.delete(event.user_id)
|
||||
raise IgnoredException("有命令就别说话了")
|
||||
|
||||
# @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("[[To_Img\|?(.*?)[[")):
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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(
|
||||
"^[[_task\|(.*)]]",
|
||||
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"[[_task|{task}]]", "").replace(
|
||||
f"[[_task|{task}]]", ""
|
||||
)
|
||||
data["message"] = Message(msg)
|
||||
@@ -2,7 +2,7 @@ from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_postprocessor
|
||||
from typing import Optional
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.adapters.onebot.v11 import Bot, Event
|
||||
from utils.manager import withdraw_message_manager
|
||||
import asyncio
|
||||
|
||||
@@ -25,4 +25,4 @@ async def _(
|
||||
|
||||
async def _withdraw_message(bot: Bot, id_: int, time: int):
|
||||
await asyncio.sleep(time)
|
||||
await bot.delete_msg(message_id=id_, self_id=int(bot.self_id))
|
||||
await bot.delete_msg(message_id=id_)
|
||||
|
||||
@@ -11,7 +11,7 @@ from .init_plugins_limit import (
|
||||
)
|
||||
from .init import init
|
||||
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 services.log import logger
|
||||
from pathlib import Path
|
||||
@@ -33,7 +33,7 @@ def _():
|
||||
初始化数据
|
||||
"""
|
||||
_flag = False
|
||||
config_file = Path(DATA_PATH) / "configs" / "plugins2config.yaml"
|
||||
config_file = DATA_PATH / "configs" / "plugins2config.yaml"
|
||||
if not config_file.exists():
|
||||
_flag = True
|
||||
init()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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):
|
||||
|
||||
@@ -15,14 +15,14 @@ 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)
|
||||
_data = {}
|
||||
if plugins2config_file.exists():
|
||||
_data = _yaml.load(open(plugins2config_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
@@ -39,16 +39,16 @@ def init_plugins_config(data_path):
|
||||
if (
|
||||
plugin_version is None
|
||||
or (
|
||||
_data.get(matcher.module)
|
||||
and _data[matcher.module].keys() != plugin_configs.keys()
|
||||
_data.get(matcher.plugin_name)
|
||||
and _data[matcher.plugin_name].keys() != plugin_configs.keys()
|
||||
)
|
||||
or plugin_version > plugins_manager.get(matcher.module)["version"]
|
||||
or matcher.module not in _data.keys()
|
||||
or plugin_version > plugins_manager.get(matcher.plugin_name)["version"]
|
||||
or matcher.plugin_name not in _data.keys()
|
||||
):
|
||||
for key in plugin_configs:
|
||||
if isinstance(plugin_configs[key], dict):
|
||||
Config.add_plugin_config(
|
||||
matcher.module,
|
||||
matcher.plugin_name,
|
||||
key,
|
||||
plugin_configs[key].get("value"),
|
||||
help_=plugin_configs[key].get("help"),
|
||||
@@ -56,12 +56,12 @@ def init_plugins_config(data_path):
|
||||
_override=True,
|
||||
)
|
||||
else:
|
||||
Config.add_plugin_config(matcher.module, key, plugin_configs[key])
|
||||
Config.add_plugin_config(matcher.plugin_name, key, plugin_configs[key])
|
||||
else:
|
||||
plugin_configs = _data[matcher.module]
|
||||
plugin_configs = _data[matcher.plugin_name]
|
||||
for key in plugin_configs:
|
||||
Config.add_plugin_config(
|
||||
matcher.module,
|
||||
matcher.plugin_name,
|
||||
key,
|
||||
plugin_configs[key]["value"],
|
||||
help_=plugin_configs[key]["help"],
|
||||
@@ -99,7 +99,10 @@ def init_plugins_config(data_path):
|
||||
if _data.get(plugin) and k in _data[plugin].keys():
|
||||
Config.set_config(plugin, k, _data[plugin][k])
|
||||
if level2module := Config.get_level2module(plugin, k):
|
||||
admin_manager.set_admin_level(level2module, _data[plugin][k])
|
||||
try:
|
||||
admin_manager.set_admin_level(level2module, _data[plugin][k])
|
||||
except KeyError:
|
||||
logger.warning(f"{level2module} 设置权限等级失败:{_data[plugin][k]}")
|
||||
_tmp_data[plugin][k] = Config.get_config(plugin, k)
|
||||
Config.save()
|
||||
temp_file = Path() / "configs" / "temp_config.yaml"
|
||||
@@ -148,4 +151,3 @@ def init_plugins_config(data_path):
|
||||
logger.error(f"生成简易配置注释错误 {type(e)}:{e}")
|
||||
if temp_file.exists():
|
||||
temp_file.unlink()
|
||||
|
||||
|
||||
@@ -17,27 +17,27 @@ 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)
|
||||
_data = {}
|
||||
if plugin2data_file.exists():
|
||||
_data = json.load(open(plugin2data_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
if matcher.module not in _data.keys():
|
||||
if matcher.plugin_name not in _data.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.module, matcher.module, error=True
|
||||
matcher.plugin_name, matcher.plugin_name, error=True
|
||||
)
|
||||
else:
|
||||
plugins_manager.set_module_data(matcher.module, "error", True)
|
||||
plugin_data = plugins_manager.get(matcher.module)
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "error", True)
|
||||
plugin_data = plugins_manager.get(matcher.plugin_name)
|
||||
if plugin_data:
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "version", plugin_data.get("version")
|
||||
matcher.plugin_name, "version", plugin_data.get("version")
|
||||
)
|
||||
else:
|
||||
try:
|
||||
@@ -47,36 +47,36 @@ def init_plugins_data(data_path):
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
except AttributeError:
|
||||
plugin_name = matcher.module
|
||||
plugin_name = matcher.plugin_name
|
||||
try:
|
||||
plugin_author = _module.__getattribute__("__plugin_author__")
|
||||
except AttributeError:
|
||||
plugin_author = None
|
||||
if matcher.module in plugins_manager.keys():
|
||||
plugins_manager.set_module_data(matcher.module, "error", False)
|
||||
if matcher.module not in plugins_manager.keys():
|
||||
if matcher.plugin_name in plugins_manager.keys():
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "error", False)
|
||||
if matcher.plugin_name not in plugins_manager.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.module,
|
||||
matcher.plugin_name,
|
||||
plugin_name=plugin_name,
|
||||
author=plugin_author,
|
||||
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
|
||||
and plugin_version > plugins_manager[matcher.module]["version"]
|
||||
and plugin_version > plugins_manager[matcher.plugin_name]["version"]
|
||||
):
|
||||
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(
|
||||
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(
|
||||
matcher.module, "error", _data[matcher.module]["error"]
|
||||
matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
|
||||
)
|
||||
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()
|
||||
|
||||
@@ -17,18 +17,18 @@ def init_plugins_cd_limit(data_path):
|
||||
"""
|
||||
加载 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)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
if not plugins2cd_manager.get_plugin_cd_data(matcher.module):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
|
||||
plugins2cd_manager.add_cd_limit(
|
||||
matcher.module, data_dict=plugin_cd_limit
|
||||
matcher.plugin_name, data_dict=plugin_cd_limit
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
@@ -65,18 +65,18 @@ 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)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
if not plugins2block_manager.get_plugin_block_data(matcher.module):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
|
||||
plugins2block_manager.add_block_limit(
|
||||
matcher.module, data_dict=plugin_block_limit
|
||||
matcher.plugin_name, data_dict=plugin_block_limit
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
@@ -113,18 +113,18 @@ 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)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
if not plugins2count_manager.get_plugin_count_data(matcher.module):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
if not plugins2count_manager.get_plugin_count_data(matcher.plugin_name):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_count_limit = _module.__getattribute__("__plugin_count_limit__")
|
||||
plugins2count_manager.add_count_limit(
|
||||
matcher.module, data_dict=plugin_count_limit
|
||||
matcher.plugin_name, data_dict=plugin_count_limit
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@@ -11,13 +11,13 @@ def init_plugins_resources():
|
||||
"""
|
||||
_tmp = []
|
||||
for matcher in get_matchers():
|
||||
if matcher.module not in _tmp:
|
||||
_tmp.append(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
if matcher.plugin_name not in _tmp:
|
||||
_tmp.append(matcher.plugin_name)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
logger.warning(f"插件 {matcher.module} 加载失败...,资源控制未加载...")
|
||||
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,资源控制未加载...")
|
||||
else:
|
||||
try:
|
||||
resources = _module.__getattribute__("__plugin_resources__")
|
||||
@@ -26,7 +26,7 @@ def init_plugins_resources():
|
||||
else:
|
||||
path = Path(_module.__getattribute__("__file__")).parent
|
||||
for resource in resources.keys():
|
||||
resources_manager.add_resource(matcher.module, (path / resource).absolute(), resources[resource])
|
||||
resources_manager.add_resource(matcher.plugin_name, path / resource, resources[resource])
|
||||
resources_manager.save()
|
||||
resources_manager.start_move()
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ def init_plugins_settings(data_path: str):
|
||||
"""
|
||||
初始化插件设置,从插件中获取 __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)
|
||||
_matchers = get_matchers()
|
||||
_tmp_module = {}
|
||||
@@ -26,15 +26,15 @@ def init_plugins_settings(data_path: str):
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
_tmp_module[x] = plugin_name
|
||||
except (KeyError, AttributeError) as e:
|
||||
logger.error(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
|
||||
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
|
||||
_tmp_module[x] = ""
|
||||
for matcher in _matchers:
|
||||
if matcher.module not in plugins2settings_manager.keys():
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
if matcher.plugin_name not in plugins2settings_manager.keys():
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
logger.warning(f"插件 {matcher.module} 加载失败...,插件控制未加载.")
|
||||
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
|
||||
else:
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
@@ -51,39 +51,41 @@ def init_plugins_settings(data_path: str):
|
||||
if level is None:
|
||||
level = 5
|
||||
admin_manager.add_admin_plugin_settings(
|
||||
matcher.module, cmd, level
|
||||
matcher.plugin_name, cmd, level
|
||||
)
|
||||
if (
|
||||
"[hidden]" in plugin_name.lower()
|
||||
or "[admin]" in plugin_name.lower()
|
||||
or "[superuser]" in plugin_name.lower()
|
||||
or matcher.module in plugins2settings_manager.keys()
|
||||
or matcher.plugin_name in plugins2settings_manager.keys()
|
||||
):
|
||||
continue
|
||||
except AttributeError:
|
||||
if matcher.module not in _tmp:
|
||||
if matcher.plugin_name not in _tmp:
|
||||
logger.warning(
|
||||
f"获取插件 {matcher.module} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||
)
|
||||
else:
|
||||
try:
|
||||
_tmp_module[matcher.module] = plugin_name
|
||||
_tmp_module[matcher.plugin_name] = plugin_name
|
||||
plugin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
if plugin_settings.get('cost_gold') is None:
|
||||
plugin_settings['cost_gold'] = 0
|
||||
if (
|
||||
plugin_settings["cmd"] is not None
|
||||
plugin_settings.get("cmd") is not None
|
||||
and plugin_name not in plugin_settings["cmd"]
|
||||
):
|
||||
plugin_settings["cmd"].append(plugin_name)
|
||||
if plugins2settings_manager.get(
|
||||
matcher.module
|
||||
) and plugins2settings_manager[matcher.module].get(
|
||||
matcher.plugin_name
|
||||
) and plugins2settings_manager[matcher.plugin_name].get(
|
||||
"plugin_type"
|
||||
):
|
||||
plugin_type = tuple(
|
||||
plugins2settings_manager.get_plugin_data(
|
||||
matcher.module
|
||||
matcher.plugin_name
|
||||
)["plugin_type"]
|
||||
)
|
||||
else:
|
||||
@@ -93,15 +95,15 @@ def init_plugins_settings(data_path: str):
|
||||
)
|
||||
except AttributeError:
|
||||
plugin_type = ("normal",)
|
||||
if plugin_settings and matcher.module:
|
||||
if plugin_settings and matcher.plugin_name:
|
||||
plugins2settings_manager.add_plugin_settings(
|
||||
matcher.module,
|
||||
matcher.plugin_name,
|
||||
plugin_type=plugin_type,
|
||||
data_dict=plugin_settings,
|
||||
**plugin_settings,
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
_tmp.append(matcher.module)
|
||||
_tmp.append(matcher.plugin_name)
|
||||
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
|
||||
with open(plugins2settings_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from nonebot import on_request, on_message
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
FriendRequestEvent,
|
||||
GroupRequestEvent,
|
||||
@@ -8,7 +8,7 @@ from nonebot.adapters.cqhttp import (
|
||||
from models.friend_user import FriendUser
|
||||
from datetime import datetime
|
||||
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 models.group_info import GroupInfo
|
||||
from utils.utils import scheduler
|
||||
@@ -31,7 +31,7 @@ exists_data = {"private": {}, "group": {}}
|
||||
|
||||
|
||||
@friend_req.handle()
|
||||
async def _(bot: Bot, event: FriendRequestEvent, state: dict):
|
||||
async def _(bot: Bot, event: FriendRequestEvent):
|
||||
global exists_data
|
||||
if exists_data["private"].get(event.user_id):
|
||||
if time.time() - exists_data["private"][event.user_id] < 60 * 5:
|
||||
@@ -66,7 +66,7 @@ async def _(bot: Bot, event: FriendRequestEvent, state: dict):
|
||||
|
||||
|
||||
@group_req.handle()
|
||||
async def _(bot: Bot, event: GroupRequestEvent, state: dict):
|
||||
async def _(bot: Bot, event: GroupRequestEvent):
|
||||
global exists_data
|
||||
if event.sub_type == "invite":
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
@@ -125,7 +125,7 @@ async def _(bot: Bot, event: GroupRequestEvent, state: dict):
|
||||
|
||||
|
||||
@x.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
async def _(event: MessageEvent):
|
||||
await asyncio.sleep(0.1)
|
||||
r = re.search(r'groupcode="(.*?)"', str(event.get_message()))
|
||||
if r:
|
||||
|
||||
+60
-54
@@ -1,15 +1,14 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, PrivateMessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.friend_user import FriendUser
|
||||
import random
|
||||
from models.ban_user import BanUser
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME
|
||||
|
||||
from configs.config import NICKNAME, Config
|
||||
from nonebot.params import CommandArg
|
||||
import random
|
||||
|
||||
__zx_plugin_name__ = "昵称系统"
|
||||
__plugin_usage__ = f"""
|
||||
@@ -23,6 +22,13 @@ __plugin_des__ = "区区昵称,才不想叫呢!"
|
||||
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_configs__ = {
|
||||
"BLACK_WORD": {
|
||||
"value": ["爸", "爹", "爷"],
|
||||
"help": "昵称所屏蔽的关键词,会被替换为 *",
|
||||
"default_value": None
|
||||
}
|
||||
}
|
||||
|
||||
nickname = on_command(
|
||||
"nickname",
|
||||
@@ -41,62 +47,62 @@ cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=Tru
|
||||
|
||||
|
||||
@nickname.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if not msg:
|
||||
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
|
||||
if len(msg) > 10:
|
||||
await nickname.finish("昵称可不能超过10个字!", at_sender=True)
|
||||
if await GroupInfoUser.set_group_member_nickname(
|
||||
event.user_id, event.group_id, msg
|
||||
):
|
||||
if len(msg) < 5:
|
||||
if random.random() < 0.5:
|
||||
msg = "~".join(msg)
|
||||
await nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
||||
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
||||
f"好突然,突然要叫你昵称什么的...{msg}..",
|
||||
f"{NICKNAME}会好好记住的{msg}的,放心吧",
|
||||
f"好..好.,那窝以后就叫你{msg}了.",
|
||||
]
|
||||
if msg in bot.config.superusers:
|
||||
await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True)
|
||||
_tmp = ""
|
||||
black_word = Config.get_config("nickname", "BLACK_WORD")
|
||||
for x in msg:
|
||||
_tmp += "*" if x in black_word else x
|
||||
msg = _tmp
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if await GroupInfoUser.set_group_member_nickname(
|
||||
event.user_id, event.group_id, msg
|
||||
):
|
||||
if len(msg) < 5:
|
||||
if random.random() < 0.3:
|
||||
msg = "~".join(msg)
|
||||
await nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
||||
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
||||
f"好突然,突然要叫你昵称什么的...{msg}..",
|
||||
f"{NICKNAME}会好好记住的{msg}的,放心吧",
|
||||
f"好..好.,那窝以后就叫你{msg}了.",
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}")
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}")
|
||||
else:
|
||||
await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败")
|
||||
else:
|
||||
await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败")
|
||||
|
||||
|
||||
@nickname.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if not msg:
|
||||
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
|
||||
if len(msg) > 10:
|
||||
await nickname.finish("不要超过10个字!", at_sender=True)
|
||||
if await FriendUser.set_friend_nickname(event.user_id, msg):
|
||||
await nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
||||
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
||||
f"好突然,突然要叫你昵称什么的...{msg}..",
|
||||
f"{NICKNAME}会好好记住的{msg}的,放心吧",
|
||||
f"好..好.,那窝以后就叫你{msg}了.",
|
||||
]
|
||||
if await FriendUser.set_friend_nickname(event.user_id, msg):
|
||||
await nickname.send(
|
||||
random.choice(
|
||||
[
|
||||
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
||||
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
||||
f"好突然,突然要叫你昵称什么的...{msg}..",
|
||||
f"{NICKNAME}会好好记住的{msg}的,放心吧",
|
||||
f"好..好.,那窝以后就叫你{msg}了.",
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
logger.info(f"USER {event.user_id} 设置昵称 {msg}")
|
||||
else:
|
||||
await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败")
|
||||
logger.info(f"USER {event.user_id} 设置昵称 {msg}")
|
||||
else:
|
||||
await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败")
|
||||
|
||||
|
||||
@my_nickname.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
try:
|
||||
nickname_ = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
@@ -117,7 +123,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
)
|
||||
)
|
||||
else:
|
||||
nickname_ = event.sender.card if event.sender.card else event.sender.nickname
|
||||
nickname_ = event.sender.card or event.sender.nickname
|
||||
await my_nickname.send(
|
||||
random.choice(
|
||||
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
|
||||
@@ -151,7 +157,7 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
|
||||
|
||||
@cancel_nickname.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
nickname_ = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
@@ -174,7 +180,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
|
||||
|
||||
@cancel_nickname.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
async def _(event: PrivateMessageEvent):
|
||||
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
|
||||
if nickname_:
|
||||
await cancel_nickname.send(
|
||||
|
||||
+136
-28
@@ -1,13 +1,19 @@
|
||||
from asyncpg.exceptions import (
|
||||
DuplicateColumnError,
|
||||
UndefinedColumnError,
|
||||
PostgresSyntaxError,
|
||||
)
|
||||
from nonebot import Driver
|
||||
from services.db_context import db
|
||||
from asyncpg.exceptions import DuplicateColumnError
|
||||
from models.group_info import GroupInfo
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from services.log import logger
|
||||
from configs.path_config import TEXT_PATH
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from typing import List
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from pathlib import Path
|
||||
from utils.utils import scheduler
|
||||
import nonebot
|
||||
|
||||
try:
|
||||
@@ -25,33 +31,34 @@ async def update_city():
|
||||
部分插件需要中国省份城市
|
||||
这里直接更新,避免插件内代码重复
|
||||
"""
|
||||
china_city = Path(TEXT_PATH) / "china_city.json"
|
||||
china_city = TEXT_PATH / "china_city.json"
|
||||
data = {}
|
||||
try:
|
||||
res = await AsyncHttpx.get(
|
||||
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
provinces_data = json.loads(res.text)
|
||||
for province in provinces_data.keys():
|
||||
data[provinces_data[province]] = []
|
||||
if not china_city.exists():
|
||||
try:
|
||||
res = await AsyncHttpx.get(
|
||||
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
|
||||
timeout=5,
|
||||
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
city_data = json.loads(res.text)
|
||||
for city in city_data.keys():
|
||||
data[provinces_data[province]].append(city_data[city])
|
||||
with open(china_city, "w", encoding="utf8") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
logger.info("自动更新城市列表完成.....")
|
||||
except TimeoutError:
|
||||
logger.warning("自动更新城市列表超时.....")
|
||||
except ValueError:
|
||||
logger.warning("自动城市列表失败.....")
|
||||
except Exception as e:
|
||||
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
|
||||
provinces_data = json.loads(res.text)
|
||||
for province in provinces_data.keys():
|
||||
data[provinces_data[province]] = []
|
||||
res = await AsyncHttpx.get(
|
||||
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
|
||||
timeout=5,
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
city_data = json.loads(res.text)
|
||||
for city in city_data.keys():
|
||||
data[provinces_data[province]].append(city_data[city])
|
||||
with open(china_city, "w", encoding="utf8") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
logger.info("自动更新城市列表完成.....")
|
||||
except TimeoutError:
|
||||
logger.warning("自动更新城市列表超时.....")
|
||||
except ValueError:
|
||||
logger.warning("自动城市列表失败.....")
|
||||
except Exception as e:
|
||||
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
@@ -59,15 +66,86 @@ async def _():
|
||||
"""
|
||||
数据库表结构变换
|
||||
"""
|
||||
_flag = []
|
||||
sql_str = [
|
||||
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;" # group_info表添加一个group_flag
|
||||
(
|
||||
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;",
|
||||
"group_info",
|
||||
), # group_info表添加一个group_flag
|
||||
(
|
||||
"ALTER TABLE bag_users rename belonging_group To group_id;",
|
||||
"bag_users",
|
||||
), # 将 bag_users 的 belonging_group 改为 group_id
|
||||
(
|
||||
"ALTER TABLE group_info_users rename belonging_group To group_id;",
|
||||
"group_info_users",
|
||||
),
|
||||
(
|
||||
"ALTER TABLE sign_group_users rename belonging_group To group_id;",
|
||||
"sign_group_users",
|
||||
),
|
||||
(
|
||||
"ALTER TABLE open_cases_users rename belonging_group To group_id;",
|
||||
"open_cases_users",
|
||||
),
|
||||
(
|
||||
"ALTER TABLE bag_users ADD property json NOT NULL DEFAULT '{}';",
|
||||
"bag_users",
|
||||
), # bag_users 新增字段 property 替代 props
|
||||
(
|
||||
"ALTER TABLE genshin ADD auto_sign_time timestamp with time zone;",
|
||||
"genshin"
|
||||
), # 新增原神自动签到字段
|
||||
(
|
||||
"ALTER TABLE genshin ADD resin_remind boolean DEFAULT False;",
|
||||
"genshin"
|
||||
), # 新增原神自动签到字段
|
||||
(
|
||||
"ALTER TABLE genshin ADD resin_recovery_time timestamp with time zone;",
|
||||
"genshin"
|
||||
), # 新增原神自动签到字段
|
||||
(
|
||||
"ALTER TABLE genshin ADD bind_group Integer;",
|
||||
"genshin"
|
||||
), # 新增原神群号绑定字段
|
||||
]
|
||||
for sql in sql_str:
|
||||
try:
|
||||
flag = sql[1]
|
||||
sql = sql[0]
|
||||
query = db.text(sql)
|
||||
await db.first(query)
|
||||
except DuplicateColumnError:
|
||||
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
|
||||
@@ -101,3 +179,33 @@ async def _(bot: Bot):
|
||||
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()
|
||||
|
||||
Executable → Regular
+1
-1
@@ -11,4 +11,4 @@ Config.add_plugin_config(
|
||||
)
|
||||
|
||||
|
||||
nonebot.load_plugins("plugins/shop")
|
||||
nonebot.load_plugins("basic_plugins/shop")
|
||||
Executable → Regular
+94
-89
@@ -1,89 +1,94 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import get_message_text, is_number
|
||||
from models.bag_user import BagUser
|
||||
from services.db_context import db
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from .models.goods_info import GoodsInfo
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 购买道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
购买道具
|
||||
指令:
|
||||
购买 [序号或名称] ?[数量=1]
|
||||
示例:购买 好感双倍加持卡Ⅰ
|
||||
示例:购买 1 4
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 购买道具"
|
||||
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "购买道具"],
|
||||
}
|
||||
|
||||
|
||||
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 ["神秘药水"]:
|
||||
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
goods_name_lst = [x.goods_name for x in goods_lst]
|
||||
msg = get_message_text(event.json()).strip().split(" ")
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
if is_number(msg[1]):
|
||||
num = int(msg[1])
|
||||
else:
|
||||
await buy.finish("购买的数量要是数字!", at_sender=True)
|
||||
# print(msg, num)
|
||||
if is_number(msg[0]):
|
||||
msg = int(msg[0])
|
||||
if msg > len(goods_lst) or msg < 1:
|
||||
await buy.finish("请输入正确的商品id!", at_sender=True)
|
||||
goods = goods_lst[msg - 1]
|
||||
else:
|
||||
if msg[0] in goods_name_lst:
|
||||
for i in range(len(goods_name_lst)):
|
||||
if msg[0] == goods_name_lst[i]:
|
||||
goods = goods_lst[i]
|
||||
break
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!")
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!", at_sender=True)
|
||||
async with db.transaction():
|
||||
if (
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
if await BagUser.spend_gold(
|
||||
event.user_id, event.group_id, goods.goods_price * num
|
||||
):
|
||||
for _ in range(num):
|
||||
await BagUser.add_props(event.user_id, event.group_id, goods.goods_name)
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||
)
|
||||
else:
|
||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 失败!"
|
||||
)
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from utils.utils import is_number
|
||||
from models.bag_user import BagUser
|
||||
from services.db_context import db
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from models.goods_info import GoodsInfo
|
||||
import time
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 购买道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
购买道具
|
||||
指令:
|
||||
购买 [序号或名称] ?[数量=1]
|
||||
示例:购买 好感双倍加持卡Ⅰ
|
||||
示例:购买 1 4
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 购买道具"
|
||||
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
||||
__plugin_type__ = ("商店",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "购买道具"],
|
||||
}
|
||||
__plugin_cd_limit__ = {"cd": 3}
|
||||
|
||||
|
||||
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@buy.handle()
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
goods = None
|
||||
if arg.extract_plain_text().strip() in ["神秘药水"]:
|
||||
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
||||
goods_list = [
|
||||
x
|
||||
for x in await GoodsInfo.get_all_goods()
|
||||
if x.goods_limit_time > time.time() or x.goods_limit_time == 0
|
||||
]
|
||||
goods_name_list = [
|
||||
x.goods_name
|
||||
for x in goods_list
|
||||
]
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
if is_number(msg[1]) and int(msg[1]) > 0:
|
||||
num = int(msg[1])
|
||||
else:
|
||||
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
|
||||
if is_number(msg[0]):
|
||||
msg = int(msg[0])
|
||||
if msg > len(goods_name_list) or msg < 1:
|
||||
await buy.finish("请输入正确的商品id!", at_sender=True)
|
||||
goods = goods_list[msg - 1]
|
||||
else:
|
||||
if msg[0] in goods_name_list:
|
||||
for i in range(len(goods_name_list)):
|
||||
if msg[0] == goods_name_list[i]:
|
||||
goods = goods_list[i]
|
||||
break
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!")
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!", at_sender=True)
|
||||
async with db.transaction():
|
||||
if (
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num * goods.goods_discount:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||
)
|
||||
else:
|
||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 失败!"
|
||||
)
|
||||
Executable → Regular
+8
-8
@@ -1,11 +1,11 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from utils.data_utils import init_rank
|
||||
from models.bag_user import BagUser
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.utils import is_number
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的金币"
|
||||
__plugin_usage__ = """
|
||||
@@ -33,13 +33,13 @@ gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_gold.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await my_gold.finish(await BagUser.get_my_total_gold(event.user_id, event.group_id))
|
||||
async def _(event: GroupMessageEvent):
|
||||
await my_gold.finish(await BagUser.get_user_total_gold(event.user_id, event.group_id))
|
||||
|
||||
|
||||
@gold_rank.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
num = get_message_text(event.json())
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
num = arg.extract_plain_text().strip()
|
||||
if is_number(num) and 51 > int(num) > 10:
|
||||
num = int(num)
|
||||
else:
|
||||
Executable → Regular
+41
-52
@@ -1,52 +1,41 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
我的道具
|
||||
指令:
|
||||
我的道具
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 我的道具"
|
||||
__plugin_cmd__ = ["我的道具"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "我的道具"],
|
||||
}
|
||||
|
||||
|
||||
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
pname_list = []
|
||||
pnum_list = []
|
||||
rst = ""
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p in pname_list:
|
||||
pnum_list[pname_list.index(p)] += 1
|
||||
else:
|
||||
pname_list.append(p)
|
||||
pnum_list.append(1)
|
||||
for i in range(len(pname_list)):
|
||||
rst += f"{i+1}.{pname_list[i]}\t×{pnum_list[i]}\n"
|
||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||
else:
|
||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
我的道具
|
||||
指令:
|
||||
我的道具
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 我的道具"
|
||||
__plugin_cmd__ = ["我的道具"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "我的道具"],
|
||||
}
|
||||
|
||||
|
||||
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_props.handle()
|
||||
async def _(event: GroupMessageEvent):
|
||||
props = await BagUser.get_property(event.user_id, event.group_id)
|
||||
if props:
|
||||
rst = ""
|
||||
for i, p in enumerate(props.keys()):
|
||||
rst += f"{i+1}.{p}\t×{props[p]}\n"
|
||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||
else:
|
||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
Executable → Regular
+26
-26
@@ -1,26 +1,26 @@
|
||||
from utils.utils import scheduler
|
||||
from models.bag_user import BagUser
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "每日金币重置 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
# 重置每日金币
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=0,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
user_list = await BagUser.get_all_users()
|
||||
for user in user_list:
|
||||
await user.update(
|
||||
get_today_gold=0,
|
||||
spend_today_gold=0,
|
||||
).apply()
|
||||
except Exception as e:
|
||||
logger.error(f"重置每日金币错误 e:{e}")
|
||||
from utils.utils import scheduler
|
||||
from models.bag_user import BagUser
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "每日金币重置 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
# 重置每日金币
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=0,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
user_list = await BagUser.get_all_users()
|
||||
for user in user_list:
|
||||
await user.update(
|
||||
get_today_gold=0,
|
||||
spend_today_gold=0,
|
||||
).apply()
|
||||
except Exception as e:
|
||||
logger.error(f"重置每日金币错误 e:{e}")
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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} 的使用函数")
|
||||
@@ -1,9 +1,10 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
|
||||
from nonebot.adapters.onebot.v11 import Bot, Message
|
||||
from nonebot.params import Command, CommandArg
|
||||
from typing import Tuple
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.utils import is_number
|
||||
from utils.manager import requests_manager
|
||||
from utils.message_builder import image
|
||||
from models.group_info import GroupInfo
|
||||
@@ -57,59 +58,54 @@ cls_request = on_command("查看所有请求", permission=SUPERUSER, priority=1,
|
||||
|
||||
|
||||
@cls_group.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
gl = await bot.get_group_list(self_id=int(bot.self_id))
|
||||
async def _(bot: Bot):
|
||||
gl = await bot.get_group_list()
|
||||
msg = ["{group_id} {group_name}".format_map(g) for g in gl]
|
||||
msg = "\n".join(msg)
|
||||
msg = f"bot:{bot.self_id}\n| 群号 | 群名 | 共{len(gl)}个群\n" + msg
|
||||
await bot.send_private_msg(
|
||||
self_id=int(bot.self_id),
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=msg,
|
||||
)
|
||||
await cls_group.send(msg)
|
||||
|
||||
|
||||
@cls_friend.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
gl = await bot.get_friend_list(self_id=int(bot.self_id))
|
||||
async def _(bot: Bot):
|
||||
gl = await bot.get_friend_list()
|
||||
msg = ["{user_id} {nickname}".format_map(g) for g in gl]
|
||||
msg = "\n".join(msg)
|
||||
msg = f"| QQ号 | 昵称 | 共{len(gl)}个好友\n" + msg
|
||||
await bot.send_private_msg(
|
||||
self_id=int(bot.self_id),
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=msg,
|
||||
)
|
||||
await cls_friend.send(msg)
|
||||
|
||||
|
||||
@friend_handle.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
id_ = get_message_text(event.json())
|
||||
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
id_ = arg.extract_plain_text().strip()
|
||||
if is_number(id_):
|
||||
id_ = int(id_)
|
||||
if state["_prefix"]["raw_command"][:2] == "同意":
|
||||
if await requests_manager.approve(bot, id_, "private"):
|
||||
await friend_handle.send("同意好友请求成功..")
|
||||
else:
|
||||
await friend_handle.send("同意好友请求失败,可能是未找到此id的请求..")
|
||||
if cmd[:2] == "同意":
|
||||
flag = await requests_manager.approve(bot, id_, "private")
|
||||
else:
|
||||
if await requests_manager.refused(bot, id_, "private"):
|
||||
await friend_handle.send("拒绝好友请求成功..")
|
||||
else:
|
||||
await friend_handle.send("拒绝好友请求失败,可能是未找到此id的请求..")
|
||||
flag = await requests_manager.refused(bot, id_, "private")
|
||||
if flag == 1:
|
||||
await friend_handle.send(f"{cmd[:2]}好友请求失败,该请求已失效..")
|
||||
requests_manager.delete_request(id_, "private")
|
||||
elif flag == 2:
|
||||
await friend_handle.send(f"{cmd[:2]}好友请求失败,未找到此id的请求..")
|
||||
else:
|
||||
await friend_handle.send(f"{cmd[:2]}好友请求成功!")
|
||||
else:
|
||||
await friend_handle.send("id必须为纯数字!")
|
||||
|
||||
|
||||
@group_handle.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
id_ = get_message_text(event.json())
|
||||
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
id_ = arg.extract_plain_text().strip()
|
||||
flag = None
|
||||
if is_number(id_):
|
||||
id_ = int(id_)
|
||||
if state["_prefix"]["raw_command"][:2] == "同意":
|
||||
rid = await requests_manager.approve(bot, id_, "group")
|
||||
if cmd[:2] == "同意":
|
||||
rid = requests_manager.get_group_id(id_)
|
||||
if rid:
|
||||
await friend_handle.send("同意群聊请求成功..")
|
||||
if await GroupInfo.get_group_info(rid):
|
||||
await GroupInfo.set_group_flag(rid, 1)
|
||||
else:
|
||||
@@ -121,19 +117,24 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group_info["member_count"],
|
||||
1
|
||||
)
|
||||
flag = await requests_manager.approve(bot, id_, "group")
|
||||
else:
|
||||
await friend_handle.send("同意群聊请求失败,可能是未找到此id的请求..")
|
||||
await friend_handle.send("同意群聊请求失败,未找到此id的请求..")
|
||||
else:
|
||||
if await requests_manager.refused(bot, id_, "group"):
|
||||
await friend_handle.send("拒绝群聊请求成功..")
|
||||
else:
|
||||
await friend_handle.send("拒绝群聊请求失败,可能是未找到此id的请求..")
|
||||
flag = await requests_manager.refused(bot, id_, "group")
|
||||
if flag == 1:
|
||||
await friend_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..")
|
||||
requests_manager.delete_request(id_, "group")
|
||||
elif flag == 2:
|
||||
await friend_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..")
|
||||
else:
|
||||
await friend_handle.send(f"{cmd[:2]}群聊请求成功!")
|
||||
else:
|
||||
await friend_handle.send("id必须为纯数字!")
|
||||
|
||||
|
||||
@cls_request.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
_str = ""
|
||||
for type_ in ["private", "group"]:
|
||||
msg = await requests_manager.show(type_)
|
||||
@@ -147,6 +148,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@clear_request.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
requests_manager.clear()
|
||||
await cls_request.send("已清空所有好友/群聊请求..")
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from configs.path_config import TEMP_PATH
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import scheduler
|
||||
@@ -35,7 +33,7 @@ resources_manager.add_temp_dir(TEMP_PATH)
|
||||
|
||||
|
||||
@clear_data.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
await clear_data.send("开始清理临时数据....")
|
||||
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
|
||||
await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
|
||||
@@ -47,13 +45,14 @@ def _clear_data() -> float:
|
||||
if dir_.exists():
|
||||
for file in os.listdir(dir_):
|
||||
file = dir_ / file
|
||||
try:
|
||||
if time.time() - os.path.getatime(file) > 300:
|
||||
file_size = os.path.getsize(file)
|
||||
file.unlink()
|
||||
size += file_size
|
||||
except Exception as e:
|
||||
logger.error(f"清理临时数据错误...{type(e)}:{e}")
|
||||
if file.is_file():
|
||||
try:
|
||||
if time.time() - os.path.getatime(file) > 300:
|
||||
file_size = os.path.getsize(file)
|
||||
file.unlink()
|
||||
size += file_size
|
||||
except Exception as e:
|
||||
logger.error(f"清理临时数据错误...{type(e)}:{e}")
|
||||
return float(size)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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}")
|
||||
@@ -1,14 +1,16 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GROUP, GroupMessageEvent, Message
|
||||
from nonebot import on_command, on_regex
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GROUP, GroupMessageEvent
|
||||
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 models.group_info import GroupInfo
|
||||
from services.log import logger
|
||||
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]"
|
||||
@@ -65,8 +67,8 @@ group_auth = on_command(
|
||||
|
||||
|
||||
@del_group.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group_id = get_message_text(event.json())
|
||||
async def _(bot: Bot, arg: Message = CommandArg()):
|
||||
group_id = arg.extract_plain_text().strip()
|
||||
if group_id:
|
||||
if is_number(group_id):
|
||||
try:
|
||||
@@ -84,8 +86,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@add_group_level.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
group_id = 0
|
||||
level = 0
|
||||
if not msg:
|
||||
@@ -109,7 +111,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@my_group_level.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
level = group_manager.get_group_level(event.group_id)
|
||||
tmp = ""
|
||||
data = plugins2settings_manager.get_data()
|
||||
@@ -125,17 +127,18 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
|
||||
|
||||
@what_up_group_level.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
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()
|
||||
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
msg = arg.extract_plain_text().strip()
|
||||
all_group = [
|
||||
g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id))
|
||||
g["group_id"] for g in await bot.get_group_list()
|
||||
]
|
||||
group_list = []
|
||||
for group in msg:
|
||||
@@ -143,20 +146,20 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group_list.append(int(group))
|
||||
if group_list:
|
||||
for group in group_list:
|
||||
if state["_prefix"]["raw_command"] in ["添加群白名单"]:
|
||||
if cmd in ["添加群白名单"]:
|
||||
group_manager.add_group_white_list(group)
|
||||
else:
|
||||
group_manager.delete_group_white_list(group)
|
||||
group_list = [str(x) for x in group_list]
|
||||
await manager_group_whitelist.send(
|
||||
"已成功将 " + "\n".join(group_list) + " " + state["_prefix"]["raw_command"]
|
||||
"已成功将 " + "\n".join(group_list) + " " + cmd
|
||||
)
|
||||
else:
|
||||
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
|
||||
|
||||
|
||||
@show_group_whitelist.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
x = group_manager.get_group_white_list()
|
||||
x = [str(g) for g in x]
|
||||
if x:
|
||||
@@ -166,13 +169,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@group_auth.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json()).split()
|
||||
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
for group_id in msg:
|
||||
if not is_number(group_id):
|
||||
await group_auth.send(f"{group_id}非纯数字,已跳过该项..")
|
||||
group_id = int(group_id)
|
||||
if state["_prefix"]["raw_command"][:2] == "添加":
|
||||
if cmd[:2] == "添加":
|
||||
if await GroupInfo.get_group_info(group_id):
|
||||
await GroupInfo.set_group_flag(group_id, 1)
|
||||
else:
|
||||
@@ -196,5 +200,5 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if await GroupInfo.get_group_info(group_id):
|
||||
await GroupInfo.set_group_flag(group_id, 0)
|
||||
await group_auth.send(
|
||||
f'已为 {group_id} {state["_prefix"]["raw_command"][:2]}群认证..'
|
||||
f'已为 {group_id} {cmd[:2]}群认证..'
|
||||
)
|
||||
|
||||
@@ -7,14 +7,19 @@ from utils.manager import (
|
||||
plugins2block_manager,
|
||||
group_manager,
|
||||
)
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from configs.config import Config
|
||||
from services.log import logger
|
||||
from utils.utils import scheduler
|
||||
|
||||
|
||||
__zx_plugin_name__ = "重载插件配置 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
重载插件配置
|
||||
plugins2settings,
|
||||
plugins2cd
|
||||
plugins2block
|
||||
group_manager
|
||||
指令:
|
||||
重载插件配置
|
||||
""".strip()
|
||||
@@ -24,17 +29,44 @@ __plugin_cmd__ = [
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_configs__ = {
|
||||
"AUTO_RELOAD": {
|
||||
"value": False,
|
||||
"help": "自动重载配置文件",
|
||||
"default_value": False
|
||||
},
|
||||
"AUTO_RELOAD_TIME": {
|
||||
"value": 180,
|
||||
"help": "控制自动重载配置文件时长",
|
||||
"default_value": 180
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
reload_plugins_manager = on_command(
|
||||
"重载插件限制", rule=to_me(), permission=SUPERUSER, priority=1, block=True
|
||||
"重载配置", rule=to_me(), permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
|
||||
@reload_plugins_manager.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
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("已自动重载所有配置文件...")
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from models.level_user import LevelUser
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, Message
|
||||
from utils.utils import get_message_at, get_message_text, is_number
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from utils.utils import get_message_at, is_number
|
||||
from services.log import logger
|
||||
from utils.message_builder import at
|
||||
from nonebot.params import Command, CommandArg
|
||||
from typing import Tuple
|
||||
|
||||
__zx_plugin_name__ = "用户权限管理 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
@@ -36,41 +37,49 @@ super_cmd = on_command(
|
||||
|
||||
|
||||
@super_cmd.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
group_id = -1
|
||||
level = 0
|
||||
async def _(
|
||||
bot: Bot,
|
||||
event: MessageEvent,
|
||||
cmd: Tuple[str, ...] = Command(),
|
||||
arg: Message = CommandArg(),
|
||||
):
|
||||
group_id = event.group_id if isinstance(event, GroupMessageEvent) else -1
|
||||
level = None
|
||||
args = arg.extract_plain_text().strip().split()
|
||||
qq = get_message_at(event.json())
|
||||
flag = 2
|
||||
try:
|
||||
args = get_message_text(event.json()).strip().split()
|
||||
qq = get_message_at(event.json())
|
||||
flag = -1
|
||||
if not qq:
|
||||
if len(args) > 2:
|
||||
if is_number(args[0]) and is_number(args[1]) and is_number(args[2]):
|
||||
if qq:
|
||||
qq = qq[0]
|
||||
if cmd[0][:2] == "添加" and args and is_number(args[0]):
|
||||
level = int(args[0])
|
||||
else:
|
||||
if cmd[0][:2] == "添加":
|
||||
if (
|
||||
len(args) > 2
|
||||
and is_number(args[0])
|
||||
and is_number(args[1])
|
||||
and is_number(args[2])
|
||||
):
|
||||
qq = int(args[0])
|
||||
group_id = int(args[1])
|
||||
level = int(args[2])
|
||||
flag = 1
|
||||
else:
|
||||
await super_cmd.finish("所有参数必须是数字!", at_sender=True)
|
||||
else:
|
||||
await super_cmd.finish(
|
||||
"权限参数不完全\n\t格式:添加/删除权限 [at] [level]"
|
||||
"\n\t格式:添加/删除权限 [qq] [group] [level]",
|
||||
at_sender=True,
|
||||
)
|
||||
else:
|
||||
qq = qq[0]
|
||||
group_id = event.group_id
|
||||
flag = 2
|
||||
if state["_prefix"]["raw_command"][:2] == "添加":
|
||||
if is_number(args[0]):
|
||||
level = int(args[0])
|
||||
else:
|
||||
await super_cmd.finish("权限等级必须是数字!", at_sender=True)
|
||||
if len(args) > 1 and is_number(args[0]) and is_number(args[1]):
|
||||
qq = int(args[0])
|
||||
group_id = int(args[1])
|
||||
flag = 1
|
||||
level = -1 if cmd[0][:2] == "删除" else level
|
||||
if group_id == -1 or not level or not qq:
|
||||
raise IndexError()
|
||||
except IndexError:
|
||||
await super_cmd.finish(__plugin_usage__)
|
||||
try:
|
||||
if cmd[0][:2] == "添加":
|
||||
if await LevelUser.set_level(qq, group_id, level, 1):
|
||||
result = "添加管理成功, 权限: " + str(level)
|
||||
result = f"添加管理成功, 权限: {level}"
|
||||
else:
|
||||
result = "管理已存在, 更新权限: " + str(level)
|
||||
result = f"管理已存在, 更新权限: {level}"
|
||||
else:
|
||||
if await LevelUser.delete_level(qq, event.group_id):
|
||||
result = "删除管理成功!"
|
||||
@@ -81,7 +90,10 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
elif flag == 1:
|
||||
await bot.send_group_msg(
|
||||
group_id=group_id,
|
||||
message=Message(f"{at(qq)}管理员修改了你的权限" f"\n--------\n你当前的权限等级:{level}"),
|
||||
message=Message(
|
||||
f"{at(qq)}管理员修改了你的权限"
|
||||
f"\n--------\n你当前的权限等级:{level if level != -1 else 0}"
|
||||
),
|
||||
)
|
||||
await super_cmd.send("修改成功")
|
||||
except Exception as e:
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.utils import is_number
|
||||
from services.log import logger
|
||||
from utils.manager import group_manager
|
||||
from nonebot.params import Command, CommandArg
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
__zx_plugin_name__ = "超级用户被动开关 [Superuser]"
|
||||
@@ -34,8 +35,9 @@ oc_gb = on_command(
|
||||
|
||||
|
||||
@oc_gb.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
group = arg.extract_plain_text().strip()
|
||||
if group:
|
||||
if is_number(group):
|
||||
group = int(group)
|
||||
@@ -44,7 +46,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
break
|
||||
else:
|
||||
await oc_gb.finish("没有加入这个群...", at_sender=True)
|
||||
if state["_prefix"]["raw_command"] == "开启广播通知":
|
||||
if cmd == "开启广播通知":
|
||||
logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播")
|
||||
await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True)
|
||||
else:
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_bot
|
||||
from services.log import logger
|
||||
@@ -34,7 +32,7 @@ update_friend_info = on_command(
|
||||
|
||||
|
||||
@update_group_info.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
bot = get_bot()
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
@@ -57,7 +55,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@update_friend_info.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
num = 0
|
||||
rst = ""
|
||||
fl = await get_bot().get_friend_list()
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.rule import to_me
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_help_image
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
__zx_plugin_name__ = '超级用户帮助 [Superuser]'
|
||||
|
||||
|
||||
superuser_help_image = Path(IMAGE_PATH) / 'superuser_help.png'
|
||||
superuser_help_image = IMAGE_PATH / 'superuser_help.png'
|
||||
|
||||
if superuser_help_image.exists():
|
||||
superuser_help_image.unlink()
|
||||
@@ -23,7 +20,7 @@ super_help = on_command(
|
||||
|
||||
|
||||
@super_help.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
async def _():
|
||||
if not superuser_help_image.exists():
|
||||
await create_help_image()
|
||||
x = image(superuser_help_image)
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from pathlib import Path
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot import Driver
|
||||
import asyncio
|
||||
import nonebot
|
||||
@@ -11,9 +10,9 @@ import nonebot
|
||||
|
||||
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
|
||||
@@ -32,11 +31,11 @@ def _create_help_image():
|
||||
_plugin_name_list = []
|
||||
width = 0
|
||||
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:
|
||||
plugin_name = ""
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
@@ -68,12 +67,12 @@ def _create_help_image():
|
||||
width = width if width > x else x
|
||||
except Exception as e:
|
||||
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
|
||||
width += 500
|
||||
A = CreateImg(width, height, font_size=24)
|
||||
_background = CreateImg(width, height, background=background)
|
||||
A = BuildImage(width, height, font_size=24)
|
||||
_background = BuildImage(width, height, background=background)
|
||||
A.text((300, 140), help_str)
|
||||
A.paste(_background, alpha=True)
|
||||
A.save(superuser_help_image)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.typing import T_State
|
||||
from utils.message_builder import image
|
||||
|
||||
|
||||
@@ -27,7 +25,7 @@ update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, b
|
||||
|
||||
|
||||
@update_info.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
async def _():
|
||||
img = image("update_info.png")
|
||||
if img:
|
||||
await update_info.finish(image("update_info.png"))
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import nonebot
|
||||
from nonebot.adapters.cqhttp import Bot as CQHTTPBot
|
||||
from nonebot.adapters.onebot.v11 import Adapter
|
||||
from services.db_context import init, disconnect
|
||||
|
||||
|
||||
nonebot.init()
|
||||
driver = nonebot.get_driver()
|
||||
driver.register_adapter("cqhttp", CQHTTPBot)
|
||||
driver.register_adapter(Adapter)
|
||||
config = driver.config
|
||||
driver.on_startup(init)
|
||||
driver.on_shutdown(disconnect)
|
||||
# 优先加载定时任务插件
|
||||
# 优先加载定时任务
|
||||
nonebot.load_plugin("nonebot_plugin_apscheduler")
|
||||
nonebot.load_plugins("basic_plugins")
|
||||
nonebot.load_plugins("plugins")
|
||||
# 最后加载权限控制
|
||||
nonebot.load_plugins("basic_plugins/hooks")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+2
-2
@@ -17,8 +17,8 @@ address: str = "" # 数据库地址
|
||||
port: str = "" # 数据库端口
|
||||
database: str = "" # 数据库名称
|
||||
|
||||
# 全局代理,例如 "http://127.0.0.1:7890"
|
||||
SYSTEM_PROXY: Optional[str] = None
|
||||
# 代理,例如 "http://127.0.0.1:7890"
|
||||
SYSTEM_PROXY: Optional[str] = None # 全局代理
|
||||
|
||||
|
||||
Config = ConfigsManager(Path() / "data" / "configs" / "plugins2config.yaml")
|
||||
|
||||
+25
-21
@@ -1,41 +1,45 @@
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
# 图片路径
|
||||
IMAGE_PATH = Path("resources/img/")
|
||||
# 音频路径
|
||||
VOICE_PATH = Path("resources/voice/")
|
||||
IMAGE_PATH = Path() / "resources" / "image"
|
||||
# 语音路径
|
||||
RECORD_PATH = Path() / "resources" / "record"
|
||||
# 文本路径
|
||||
TEXT_PATH = Path("resources/txt/")
|
||||
TEXT_PATH = Path() / "resources" / "text"
|
||||
# 日志路径
|
||||
LOG_PATH = Path("log/")
|
||||
LOG_PATH = Path() / "log"
|
||||
# 字体路径
|
||||
FONT_PATH = Path("resources/ttf/")
|
||||
FONT_PATH = Path() / "resources" / "font"
|
||||
# 数据路径
|
||||
DATA_PATH = Path("data/")
|
||||
# 临时图片路径
|
||||
TEMP_PATH = Path("resources/img/temp/")
|
||||
DATA_PATH = Path() / "data"
|
||||
# 临时数据路径
|
||||
TEMP_PATH = Path() / "resources" / "temp"
|
||||
|
||||
|
||||
def init_path():
|
||||
global IMAGE_PATH, VOICE_PATH, TEXT_PATH, LOG_PATH, FONT_PATH, DATA_PATH, TEMP_PATH
|
||||
def load_path():
|
||||
old_img_dir = Path() / "resources" / "img"
|
||||
if not IMAGE_PATH.exists() and old_img_dir.exists():
|
||||
os.rename(old_img_dir, IMAGE_PATH)
|
||||
old_voice_dir = Path() / "resources" / "voice"
|
||||
if not RECORD_PATH.exists() and old_voice_dir.exists():
|
||||
os.rename(old_voice_dir, RECORD_PATH)
|
||||
old_ttf_dir = Path() / "resources" / "ttf"
|
||||
if not FONT_PATH.exists() and old_ttf_dir.exists():
|
||||
os.rename(old_ttf_dir, FONT_PATH)
|
||||
old_txt_dir = Path() / "resources" / "txt"
|
||||
if not TEXT_PATH.exists() and old_txt_dir.exists():
|
||||
os.rename(old_txt_dir, TEXT_PATH)
|
||||
IMAGE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
VOICE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
RECORD_PATH.mkdir(parents=True, exist_ok=True)
|
||||
TEXT_PATH.mkdir(parents=True, exist_ok=True)
|
||||
LOG_PATH.mkdir(parents=True, exist_ok=True)
|
||||
FONT_PATH.mkdir(parents=True, exist_ok=True)
|
||||
DATA_PATH.mkdir(parents=True, exist_ok=True)
|
||||
TEMP_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
IMAGE_PATH = str(IMAGE_PATH.absolute()) + '/'
|
||||
VOICE_PATH = str(VOICE_PATH.absolute()) + '/'
|
||||
TEXT_PATH = str(TEXT_PATH.absolute()) + '/'
|
||||
LOG_PATH = str(LOG_PATH.absolute()) + '/'
|
||||
FONT_PATH = str(FONT_PATH.absolute()) + '/'
|
||||
DATA_PATH = str(DATA_PATH.absolute()) + '/'
|
||||
TEMP_PATH = str(TEMP_PATH.absolute()) + '/'
|
||||
|
||||
|
||||
init_path()
|
||||
load_path()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,14 +11,19 @@ class ConfigsManager:
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self._data: dict = {}
|
||||
self._simple_data: dict = {}
|
||||
self._admin_level_data = []
|
||||
self._simple_file = Path() / "configs" / "config.yaml"
|
||||
if file:
|
||||
file.parent.mkdir(exist_ok=True, parents=True)
|
||||
self.file = file
|
||||
_yaml = YAML()
|
||||
if file.exists():
|
||||
_yaml = YAML()
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = _yaml.load(f)
|
||||
if self._simple_file.exists():
|
||||
with open(self._simple_file, "r", encoding="utf8") as f:
|
||||
self._simple_data = _yaml.load(f)
|
||||
|
||||
def add_plugin_config(
|
||||
self,
|
||||
@@ -71,6 +76,7 @@ class ConfigsManager:
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
del self._data[module]
|
||||
self.save()
|
||||
|
||||
def set_config(self, module: str, key: str, value: str):
|
||||
"""
|
||||
@@ -80,8 +86,10 @@ class ConfigsManager:
|
||||
:param value: 值
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
if self._data[module].get(key) is not None:
|
||||
if self._data[module].get(key) is not None and self._data[module][key] != value:
|
||||
self._data[module][key]["value"] = value
|
||||
self._simple_data[module][key] = value
|
||||
self.save()
|
||||
|
||||
def set_help(self, module: str, key: str, help_: str):
|
||||
"""
|
||||
@@ -93,6 +101,7 @@ class ConfigsManager:
|
||||
if module in self._data.keys():
|
||||
if self._data[module].get(key) is not None:
|
||||
self._data[module][key]["help"] = help_
|
||||
self.save()
|
||||
|
||||
def set_default_value(self, module: str, key: str, value: str):
|
||||
"""
|
||||
@@ -104,12 +113,14 @@ class ConfigsManager:
|
||||
if module in self._data.keys():
|
||||
if self._data[module].get(key) is not None:
|
||||
self._data[module][key]["default_value"] = value
|
||||
self.save()
|
||||
|
||||
def get_config(self, module: str, key: str) -> Optional[Any]:
|
||||
def get_config(self, module: str, key: str, default: Optional[Any] = None) -> Optional[Any]:
|
||||
"""
|
||||
获取指定配置值
|
||||
:param module: 模块名
|
||||
:param key: 配置名称
|
||||
:param default: 没有key值内容的默认返回值
|
||||
"""
|
||||
key = key.upper()
|
||||
if module in self._data.keys():
|
||||
@@ -118,6 +129,8 @@ class ConfigsManager:
|
||||
if self._data[module][key]["value"] is None:
|
||||
return self._data[module][key]["default_value"]
|
||||
return self._data[module][key]["value"]
|
||||
if default is not None:
|
||||
return default
|
||||
return None
|
||||
|
||||
def get_level2module(self, module: str, key: str) -> Optional[str]:
|
||||
@@ -139,17 +152,37 @@ class ConfigsManager:
|
||||
if key in self._data.keys():
|
||||
return self._data[key]
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
def save(self, path: Union[str, Path] = None, save_simple_data: bool = False):
|
||||
"""
|
||||
保存数据
|
||||
:param path: 路径
|
||||
:param save_simple_data: 同时保存至config.yaml
|
||||
"""
|
||||
if save_simple_data:
|
||||
with open(self._simple_file, "w", encoding="utf8") as f:
|
||||
yaml.dump(
|
||||
self._simple_data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
path = path if path else self.file
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
yaml.dump(
|
||||
self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
重新加载配置文件
|
||||
"""
|
||||
_yaml = YAML()
|
||||
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):
|
||||
"""
|
||||
获取管理插件等级
|
||||
@@ -170,4 +203,3 @@ class ConfigsManager:
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._data[key]
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 772 KiB |
+105
-110
@@ -1,38 +1,39 @@
|
||||
from services.db_context import db
|
||||
from typing import Dict
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
|
||||
|
||||
class BagUser(db.Model):
|
||||
__tablename__ = "bag_users"
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
gold = db.Column(db.Integer(), default=100)
|
||||
props = db.Column(db.TEXT(), nullable=False, default="")
|
||||
props = db.Column(db.TEXT(), nullable=False, default="") # 旧道具字段(废弃)
|
||||
spend_total_gold = db.Column(db.Integer(), default=0)
|
||||
get_total_gold = db.Column(db.Integer(), default=0)
|
||||
get_today_gold = db.Column(db.Integer(), default=0)
|
||||
spend_today_gold = db.Column(db.Integer(), default=0)
|
||||
property = db.Column(db.JSON(), nullable=False, default={}) # 新道具字段
|
||||
|
||||
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
||||
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def get_my_total_gold(cls, user_qq: int, belonging_group: int) -> str:
|
||||
async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取金币概况
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
user = await query.gino.first()
|
||||
if not user:
|
||||
user = await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
group_id=group_id,
|
||||
)
|
||||
return (
|
||||
f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}"
|
||||
@@ -41,179 +42,173 @@ class BagUser(db.Model):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_gold(cls, user_qq: int, belonging_group: int) -> int:
|
||||
async def get_gold(cls, user_qq: int, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
获取当前金币
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.gold
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
group_id=group_id,
|
||||
)
|
||||
return 100
|
||||
|
||||
@classmethod
|
||||
async def get_props(cls, user_qq: int, belonging_group: int) -> str:
|
||||
async def get_property(cls, user_qq: int, group_id: int) -> Dict[str, int]:
|
||||
"""
|
||||
说明:
|
||||
获取当前道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.props
|
||||
return user.property
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
group_id=group_id,
|
||||
)
|
||||
return ""
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
async def add_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
||||
async def add_gold(cls, user_qq: int, group_id: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
增加金币
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param group_id: 所在群号
|
||||
:param num: 金币数量
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold + num,
|
||||
get_total_gold=user.get_total_gold + num,
|
||||
get_today_gold=user.get_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 + num,
|
||||
get_total_gold=num,
|
||||
get_today_gold=num,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold + num,
|
||||
get_total_gold=user.get_total_gold + num,
|
||||
get_today_gold=user.get_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
group_id=group_id,
|
||||
gold=100 + num,
|
||||
get_total_gold=num,
|
||||
get_today_gold=num,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
||||
async def spend_gold(cls, user_qq: int, group_id: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
花费金币
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param group_id: 所在群号
|
||||
:param num: 金币数量
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold - num,
|
||||
spend_total_gold=user.spend_total_gold + num,
|
||||
spend_today_gold=user.spend_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 - num,
|
||||
spend_total_gold=num,
|
||||
spend_today_gold=num,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold - num,
|
||||
spend_total_gold=user.spend_total_gold + num,
|
||||
spend_today_gold=user.spend_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
group_id=group_id,
|
||||
gold=100 - num,
|
||||
spend_total_gold=num,
|
||||
spend_today_gold=num,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def add_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
||||
async def add_property(cls, user_qq: int, group_id: int, name: str):
|
||||
"""
|
||||
说明:
|
||||
增加道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param group_id: 所在群号
|
||||
:param name: 道具名称
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(props=user.props + f"{name},").apply()
|
||||
if user:
|
||||
p = user.property
|
||||
if p.get(name) is None:
|
||||
p[name] = 1
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq, belonging_group=belonging_group, props=f"{name},"
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
p[name] += 1
|
||||
await user.update(property=p).apply()
|
||||
else:
|
||||
await cls.create(user_qq=user_qq, group_id=group_id, property={name: 1})
|
||||
|
||||
@classmethod
|
||||
async def del_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
||||
async def delete_property(
|
||||
cls, user_qq: int, group_id: int, name: str, num: int = 1
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
使用道具
|
||||
使用/删除 道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 所在群号
|
||||
:param group_id: 所在群号
|
||||
:param name: 道具名称
|
||||
:param num: 使用个数
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
rst = ""
|
||||
props = user.props
|
||||
if props.find(name) != -1:
|
||||
props = props.split(",")
|
||||
try:
|
||||
index = props.index(name)
|
||||
except ValueError:
|
||||
return False
|
||||
props = props[:index] + props[index + 1 :]
|
||||
for p in props:
|
||||
if p != "":
|
||||
rst += p + ","
|
||||
await user.update(props=rst).apply()
|
||||
return True
|
||||
if user:
|
||||
property_ = user.property
|
||||
if name in property_:
|
||||
if property_.get(name) == num:
|
||||
del property_[name]
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
except Exception:
|
||||
property_[name] -= num
|
||||
await user.update(property=property_).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def buy_property(
|
||||
cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
购买道具
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param group_id: 所在群聊
|
||||
:param goods: 商品
|
||||
:param goods_num: 商品数量
|
||||
"""
|
||||
try:
|
||||
# 折扣后金币
|
||||
spend_gold = goods.goods_discount * goods.goods_price * goods_num
|
||||
await BagUser.spend_gold(user_qq, group_id, spend_gold)
|
||||
for _ in range(goods_num):
|
||||
await BagUser.add_property(user_qq, group_id, goods.goods_name)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"buy_property 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
@@ -227,5 +222,5 @@ class BagUser(db.Model):
|
||||
if not group_id:
|
||||
query = await cls.query.gino.all()
|
||||
else:
|
||||
query = await cls.query.where((cls.belonging_group == group_id)).gino.all()
|
||||
query = await cls.query.where((cls.group_id == group_id)).gino.all()
|
||||
return query
|
||||
|
||||
@@ -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
|
||||
@@ -1,4 +1,5 @@
|
||||
from services.db_context import db
|
||||
from configs.config import Config
|
||||
|
||||
|
||||
class FriendUser(db.Model):
|
||||
@@ -80,7 +81,12 @@ class FriendUser(db.Model):
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
if user.nickname:
|
||||
return user.nickname
|
||||
_tmp = ""
|
||||
black_word = Config.get_config("nickname", "BLACK_WORD")
|
||||
if black_word:
|
||||
for x in user.nickname:
|
||||
_tmp += "*" if x in black_word else x
|
||||
return _tmp
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
|
||||
Executable → Regular
+15
-11
@@ -1,5 +1,6 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
|
||||
|
||||
class GoodsInfo(db.Model):
|
||||
@@ -34,16 +35,18 @@ class GoodsInfo(db.Model):
|
||||
:param goods_limit_time: 商品限时
|
||||
"""
|
||||
try:
|
||||
await cls.create(
|
||||
goods_name=goods_name,
|
||||
goods_price=goods_price,
|
||||
goods_description=goods_description,
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if not await cls.get_goods_info(goods_name):
|
||||
await cls.create(
|
||||
goods_name=goods_name,
|
||||
goods_price=goods_price,
|
||||
goods_description=goods_description,
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo add_goods 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_goods(cls, goods_name: str) -> bool:
|
||||
@@ -99,7 +102,8 @@ class GoodsInfo(db.Model):
|
||||
if goods_limit_time:
|
||||
await query.update(goods_limit_time=goods_limit_time).apply()
|
||||
return True
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
+47
-29
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
|
||||
from configs.config import Config
|
||||
from services.db_context import db
|
||||
from typing import List, Optional
|
||||
|
||||
@@ -10,18 +10,18 @@ class GroupInfoUser(db.Model):
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
user_name = db.Column(db.Unicode(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
user_join_time = db.Column(db.DateTime(), nullable=False)
|
||||
nickname = db.Column(db.Unicode())
|
||||
uid = db.Column(db.BigInteger())
|
||||
|
||||
_idx1 = db.Index("info_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
||||
_idx1 = db.Index("info_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_member_info(
|
||||
cls,
|
||||
user_qq: int,
|
||||
belonging_group: int,
|
||||
group_id: int,
|
||||
user_name: str,
|
||||
user_join_time: datetime,
|
||||
uid: Optional[int] = None,
|
||||
@@ -31,20 +31,20 @@ class GroupInfoUser(db.Model):
|
||||
添加群内用户信息
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
:param group_id: 群号
|
||||
:param user_name: 用户名称
|
||||
:param user_join_time: 入群时间
|
||||
:param uid: 用户唯一 id(自动生成)
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
try:
|
||||
if not await query.gino.first():
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
user_name=user_name,
|
||||
belonging_group=belonging_group,
|
||||
group_id=group_id,
|
||||
user_join_time=user_join_time,
|
||||
uid=uid
|
||||
)
|
||||
@@ -54,31 +54,31 @@ class GroupInfoUser(db.Model):
|
||||
|
||||
@classmethod
|
||||
async def get_member_info(
|
||||
cls, user_qq: int, belonging_group: int
|
||||
cls, user_qq: int, group_id: int
|
||||
) -> "GroupInfoUser":
|
||||
"""
|
||||
说明:
|
||||
查询群员信息
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
return await query.gino.first()
|
||||
|
||||
@classmethod
|
||||
async def delete_member_info(cls, user_qq: int, belonging_group: int) -> bool:
|
||||
async def delete_member_info(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除群员信息
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
@@ -87,40 +87,40 @@ class GroupInfoUser(db.Model):
|
||||
return True
|
||||
else:
|
||||
await cls.delete.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
).gino.status()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_group_member_id_list(cls, belonging_group: int) -> List[int]:
|
||||
async def get_group_member_id_list(cls, group_id: int) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
获取该群所有用户qq
|
||||
参数:
|
||||
:param belonging_group: 群号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
member_list = []
|
||||
query = cls.query.where((cls.belonging_group == belonging_group))
|
||||
query = cls.query.where((cls.group_id == group_id))
|
||||
for user in await query.gino.all():
|
||||
member_list.append(user.user_qq)
|
||||
return member_list
|
||||
|
||||
@classmethod
|
||||
async def set_group_member_nickname(
|
||||
cls, user_qq: int, belonging_group: int, nickname: str
|
||||
cls, user_qq: int, group_id: int, nickname: str
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置群员在该群内的昵称
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
:param group_id: 群号
|
||||
:param nickname: 昵称
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
user = await query.with_for_update().gino.first()
|
||||
if user:
|
||||
@@ -129,30 +129,48 @@ class GroupInfoUser(db.Model):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_group_member_nickname(cls, user_qq: int, belonging_group: int) -> str:
|
||||
async def get_user_all_group(cls, user_qq: int) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
获取该用户所在的所有群聊
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
|
||||
if query:
|
||||
query = [x.group_id for x in query]
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取用户在该群的昵称
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param belonging_group: 群号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
if user.nickname:
|
||||
return user.nickname
|
||||
_tmp = ""
|
||||
black_word = Config.get_config("nickname", "BLACK_WORD")
|
||||
if black_word:
|
||||
for x in user.nickname:
|
||||
_tmp += "*" if x in black_word else x
|
||||
return _tmp
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def get_group_member_uid(cls, user_qq: int, belonging_group: int) -> Optional[str]:
|
||||
async def get_group_member_uid(cls, user_qq: int, group_id: int) -> Optional[str]:
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
user = await query.gino.first()
|
||||
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.belonging_group == 114514)).with_for_update()
|
||||
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.group_id == 114514)).with_for_update()
|
||||
_max_uid_user = await _max_uid.gino.first()
|
||||
_max_uid = _max_uid_user.uid
|
||||
if not user or not user.uid:
|
||||
@@ -162,9 +180,9 @@ class GroupInfoUser(db.Model):
|
||||
return x.uid
|
||||
else:
|
||||
if not user:
|
||||
await GroupInfoUser.add_member_info(user_qq, belonging_group, '', datetime.min)
|
||||
await GroupInfoUser.add_member_info(user_qq, group_id, '', datetime.min)
|
||||
user = await cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
).gino.first()
|
||||
await user.update(
|
||||
uid=_max_uid + 1,
|
||||
|
||||
+39
-12
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
|
||||
from typing import List
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ class SignGroupUser(db.Model):
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
||||
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
checkin_count = db.Column(db.Integer(), nullable=False)
|
||||
checkin_time_last = db.Column(db.DateTime(timezone=True), nullable=False)
|
||||
impression = db.Column(db.Numeric(scale=3, asdecimal=False), nullable=False)
|
||||
@@ -20,28 +19,56 @@ class SignGroupUser(db.Model):
|
||||
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
|
||||
)
|
||||
|
||||
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
||||
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def ensure(
|
||||
cls, user_qq: int, belonging_group: int, for_update: bool = False
|
||||
cls, user_qq: int, group_id: int, for_update: bool = False
|
||||
) -> "SignGroupUser":
|
||||
"""
|
||||
说明:
|
||||
获取签到用户
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param group_id: 所在群聊
|
||||
:param for_update: 是否存在修改数据
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||
)
|
||||
if for_update:
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
return user or await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
group_id=group_id,
|
||||
checkin_count=0,
|
||||
checkin_time_last=datetime.min, # 从未签到过
|
||||
impression=0,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_user_all_data(cls, user_qq: int) -> List["SignGroupUser"]:
|
||||
"""
|
||||
说明:
|
||||
获取某用户所有数据
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = cls.query.where(cls.user_qq == user_qq)
|
||||
query = query.with_for_update()
|
||||
return await query.gino.all()
|
||||
|
||||
@classmethod
|
||||
async def sign(cls, user: "SignGroupUser", impression: float, checkin_time_last: datetime):
|
||||
"""
|
||||
说明:
|
||||
签到
|
||||
说明:
|
||||
:param user: 用户
|
||||
:param impression: 增加的好感度
|
||||
:param checkin_time_last: 签到时间
|
||||
"""
|
||||
await user.update(
|
||||
checkin_count=user.checkin_count + 1,
|
||||
checkin_time_last=checkin_time_last,
|
||||
@@ -51,22 +78,22 @@ class SignGroupUser(db.Model):
|
||||
).apply()
|
||||
|
||||
@classmethod
|
||||
async def get_all_impression(cls, belonging_group: int) -> "list, list, list":
|
||||
async def get_all_impression(cls, group_id: int) -> "list, list, list":
|
||||
"""
|
||||
说明:
|
||||
获取该群所有用户 id 及对应 好感度
|
||||
参数:
|
||||
:param belonging_group: 群号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
impression_list = []
|
||||
user_qq_list = []
|
||||
user_group = []
|
||||
if belonging_group:
|
||||
query = cls.query.where(cls.belonging_group == belonging_group)
|
||||
if group_id:
|
||||
query = cls.query.where(cls.group_id == group_id)
|
||||
else:
|
||||
query = cls.query
|
||||
for user in await query.gino.all():
|
||||
impression_list.append(user.impression)
|
||||
user_qq_list.append(user.user_qq)
|
||||
user_group.append(user.belonging_group)
|
||||
user_group.append(user.group_id)
|
||||
return user_qq_list, impression_list, user_group
|
||||
|
||||
@@ -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)
|
||||
@@ -1,15 +1,14 @@
|
||||
import random
|
||||
from nonebot import on_keyword
|
||||
import os
|
||||
from utils.message_builder import image
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from nonebot import on_command
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from utils.utils import FreqLimiter
|
||||
from configs.config import NICKNAME
|
||||
import random
|
||||
from nonebot import on_keyword
|
||||
import os
|
||||
|
||||
|
||||
__zx_plugin_name__ = "基本设置 [Hidden]"
|
||||
@@ -25,12 +24,12 @@ config_play_game = on_keyword({"打游戏"}, permission=GROUP, priority=1, block
|
||||
|
||||
|
||||
@config_play_game.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
if not _flmt.check(event.group_id):
|
||||
return
|
||||
_flmt.start_cd(event.group_id)
|
||||
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()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
if NICKNAME.find('真寻') != -1:
|
||||
result = (
|
||||
"我叫绪山真寻\n"
|
||||
@@ -57,6 +56,6 @@ my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True)
|
||||
|
||||
|
||||
@my_wife.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
await my_wife.finish(image("laopo.jpg", "other"))
|
||||
|
||||
|
||||
+18
-22
@@ -1,17 +1,15 @@
|
||||
from nonebot import on_message
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
GroupMessageEvent,
|
||||
Message,
|
||||
MessageEvent,
|
||||
)
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from services.log import logger
|
||||
from utils.utils import get_message_text, get_message_imgs
|
||||
from utils.utils import get_message_img, get_message_text
|
||||
from .data_source import get_chat_result, hello, no_result
|
||||
from configs.config import NICKNAME, Config
|
||||
|
||||
@@ -21,40 +19,35 @@ usage:
|
||||
与{NICKNAME}普普通通的对话吧!
|
||||
"""
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = 'HibiKier'
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"cmd": ["Ai", "ai", "AI", "aI"],
|
||||
}
|
||||
__plugin_configs__ = {
|
||||
"TL_KEY": {
|
||||
"value": [],
|
||||
"help": "图灵Key"
|
||||
"TL_KEY": {"value": [], "help": "图灵Key"},
|
||||
"ALAPI_AI_CHECK": {"value": False, "help": "是否检测青云客骂娘回复", "default_value": False},
|
||||
"TEXT_FILTER": {
|
||||
"value": ["鸡", "口交"],
|
||||
"help": "文本过滤器,将敏感词更改为*",
|
||||
"default_value": [],
|
||||
},
|
||||
"ALAPI_AI_CHECK": {
|
||||
"value": False,
|
||||
"help": "是否检测青云客骂娘回复",
|
||||
"default_value": False
|
||||
}
|
||||
}
|
||||
Config.add_plugin_config(
|
||||
"alapi",
|
||||
"ALAPI_TOKEN",
|
||||
None,
|
||||
help_="在https://admin.alapi.cn/user/login登录后获取token"
|
||||
"alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token"
|
||||
)
|
||||
|
||||
ai = on_message(rule=to_me(), priority=8)
|
||||
|
||||
|
||||
@ai.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
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()):
|
||||
return
|
||||
# 打招呼
|
||||
if (not msg and not imgs) or msg in [
|
||||
if (not msg and not img) or msg in [
|
||||
"你好啊",
|
||||
"你好",
|
||||
"在吗",
|
||||
@@ -65,7 +58,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
"在",
|
||||
]:
|
||||
await ai.finish(hello())
|
||||
img = imgs[0] if imgs else ""
|
||||
img = img[0] if img else ""
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
@@ -74,7 +67,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
if not nickname:
|
||||
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:
|
||||
nickname = event.sender.nickname
|
||||
result = await get_chat_result(msg, img, event.user_id, nickname)
|
||||
@@ -83,6 +76,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
f"问题:{msg} ---- 回答:{result}"
|
||||
)
|
||||
if result:
|
||||
result = str(result)
|
||||
for t in Config.get_config("ai", "TEXT_FILTER"):
|
||||
result = result.replace(t, "*")
|
||||
await ai.finish(Message(result))
|
||||
else:
|
||||
await ai.finish(no_result())
|
||||
|
||||
@@ -20,7 +20,7 @@ check_url = "https://v2.alapi.cn/api/censor/text"
|
||||
|
||||
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:
|
||||
@@ -57,9 +57,8 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str)
|
||||
if random.random() < 0.2:
|
||||
if nickname.find("大人") == -1:
|
||||
nickname += "大~人~"
|
||||
rst = rst.replace("小主人", nickname).replace("小朋友", nickname)
|
||||
rst = str(rst).replace("小主人", nickname).replace("小朋友", nickname)
|
||||
ai_message_manager.add_result(user_id, rst)
|
||||
print(ai_message_manager)
|
||||
return rst
|
||||
|
||||
|
||||
@@ -140,7 +139,7 @@ async def xie_ai(text: str) -> str:
|
||||
content = content.replace("{br}", "\n")
|
||||
if "提示" in content:
|
||||
content = content[: content.find("提示")]
|
||||
if "淘宝" in content:
|
||||
if "淘宝" in content or "taobao.com" in content:
|
||||
return ""
|
||||
while True:
|
||||
r = re.search("{face:(.*)}", content)
|
||||
@@ -171,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":
|
||||
result += image(img, "zai")
|
||||
else:
|
||||
@@ -194,7 +193,7 @@ def no_result() -> str:
|
||||
"我!不!知!道!",
|
||||
]
|
||||
)
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH + "noresult/")), "noresult")
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH / "noresult")), "noresult")
|
||||
)
|
||||
|
||||
|
||||
|
||||
+4
-1
@@ -75,7 +75,10 @@ class AiMessageManager(StaticData):
|
||||
:param user_id: 用户id
|
||||
:param nickname: 用户昵称
|
||||
"""
|
||||
if len(self._data[user_id]["message"]) < 2:
|
||||
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:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from configs.config import Config
|
||||
import nonebot
|
||||
|
||||
nonebot.load_plugins("plugins/alapi")
|
||||
|
||||
Config.add_plugin_config(
|
||||
"alapi",
|
||||
@@ -9,3 +8,7 @@ Config.add_plugin_config(
|
||||
None,
|
||||
help_="在https://admin.alapi.cn/user/login登录后获取token"
|
||||
)
|
||||
|
||||
|
||||
nonebot.load_plugins("plugins/alapi")
|
||||
|
||||
|
||||
Executable → Regular
+49
-49
@@ -1,49 +1,49 @@
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.message_builder import image
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional
|
||||
from configs.config import Config
|
||||
from utils.http_utils import AsyncHttpx
|
||||
|
||||
|
||||
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")
|
||||
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 = 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())
|
||||
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())
|
||||
@@ -1,7 +1,6 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from .data_source import get_data
|
||||
from nonebot import on_regex
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from ._data_source import get_data
|
||||
from services.log import logger
|
||||
|
||||
__zx_plugin_name__ = "网易云热评"
|
||||
@@ -23,8 +22,8 @@ __plugin_settings__ = {
|
||||
}
|
||||
|
||||
|
||||
comments_163 = on_command(
|
||||
"网易云热评", aliases={"网易云评论", "到点了", "12点了"}, priority=5, block=True
|
||||
comments_163 = on_regex(
|
||||
"^(网易云热评|网易云评论|到点了|12点了)$", priority=5, block=True
|
||||
)
|
||||
|
||||
|
||||
@@ -32,7 +31,7 @@ comments_163_url = "https://v2.alapi.cn/api/comment"
|
||||
|
||||
|
||||
@comments_163.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(event: MessageEvent):
|
||||
data, code = await get_data(comments_163_url)
|
||||
if code != 200:
|
||||
await comments_163.finish(data, at_sender=True)
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_message_text
|
||||
from .data_source import get_data
|
||||
from nonebot.params import CommandArg
|
||||
from ._data_source import get_data
|
||||
from services.log import logger
|
||||
|
||||
__zx_plugin_name__ = "b封面"
|
||||
@@ -32,8 +31,8 @@ cover_url = "https://v2.alapi.cn/api/bilibili/cover"
|
||||
|
||||
|
||||
@cover.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
params = {"c": msg}
|
||||
data, code = await get_data(cover_url, params)
|
||||
if code != 200:
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
from nonebot import on_command
|
||||
from nonebot import on_regex
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from configs.config import Config
|
||||
from .data_source import get_data
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from ._data_source import get_data
|
||||
|
||||
|
||||
__zx_plugin_name__ = "鸡汤"
|
||||
@@ -28,11 +25,11 @@ __plugin_settings__ = {
|
||||
url = "https://v2.alapi.cn/api/soul"
|
||||
|
||||
|
||||
jitang = on_command("鸡汤", aliases={"毒鸡汤"}, priority=5, block=True)
|
||||
jitang = on_regex("^毒?鸡汤$", priority=5, block=True)
|
||||
|
||||
|
||||
@jitang.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(event: MessageEvent):
|
||||
try:
|
||||
data, code = await get_data(url)
|
||||
if code != 200:
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from services.log import logger
|
||||
from .data_source import get_data
|
||||
from ._data_source import get_data
|
||||
|
||||
__zx_plugin_name__ = "古诗"
|
||||
__plugin_usage__ = """usage:
|
||||
@@ -27,7 +26,7 @@ poetry_url = "https://v2.alapi.cn/api/shici"
|
||||
|
||||
|
||||
@poetry.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(event: MessageEvent):
|
||||
data, code = await get_data(poetry_url)
|
||||
if code != 200:
|
||||
await poetry.finish(data, at_sender=True)
|
||||
|
||||
+16
-17
@@ -1,11 +1,10 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from services.log import logger
|
||||
from .data_source import get_data, gen_wbtop_pic
|
||||
from utils.utils import get_message_text, is_number
|
||||
from ._data_source import get_data, gen_wbtop_pic
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from utils.http_utils import AsyncPlaywright
|
||||
import asyncio
|
||||
|
||||
@@ -38,9 +37,9 @@ wbtop_data = []
|
||||
|
||||
|
||||
@wbtop.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
global wbtop_data
|
||||
msg = get_message_text(event.json())
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if not wbtop_data or not msg:
|
||||
data, code = await get_data(wbtop_url)
|
||||
if code != 200:
|
||||
@@ -57,15 +56,15 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
)
|
||||
if is_number(msg) and 0 < int(msg) <= 50:
|
||||
url = wbtop_data[int(msg) - 1]["url"]
|
||||
try:
|
||||
await wbtop.send("开始截取数据...")
|
||||
img = await AsyncPlaywright.screenshot(
|
||||
url,
|
||||
f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png",
|
||||
"#pl_feedlist_index",
|
||||
sleep=5
|
||||
)
|
||||
await wbtop.send("开始截取数据...")
|
||||
img = await AsyncPlaywright.screenshot(
|
||||
url,
|
||||
f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png",
|
||||
"#pl_feedlist_index",
|
||||
wait_time=5
|
||||
)
|
||||
if img:
|
||||
await wbtop.send(img)
|
||||
except Exception as e:
|
||||
logger.error(f"微博热搜截图出错... {type(e)}: {e}")
|
||||
else:
|
||||
await wbtop.send("发生了一些错误.....")
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from nonebot import on_command
|
||||
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 (
|
||||
add_live_sub,
|
||||
delete_sub,
|
||||
@@ -9,14 +9,15 @@ from .data_source import (
|
||||
get_media_id,
|
||||
get_sub_status,
|
||||
SubManager,
|
||||
BilibiliSub
|
||||
BilibiliSub,
|
||||
)
|
||||
from models.level_user import LevelUser
|
||||
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 services.log import logger
|
||||
from nonebot import Driver
|
||||
from nonebot.params import CommandArg, ArgStr
|
||||
import nonebot
|
||||
|
||||
__zx_plugin_name__ = "B站订阅"
|
||||
@@ -68,18 +69,9 @@ async def _():
|
||||
sub_manager = SubManager()
|
||||
|
||||
|
||||
@add_sub.args_parser
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
season_data = state["season_data"]
|
||||
msg = get_message_text(event.json())
|
||||
if not is_number(msg) or int(msg) < 1 or int(msg) > len(season_data):
|
||||
await add_sub.reject("Id必须为数字且在范围内!请重新输入...")
|
||||
state["id"] = season_data[int(msg) - 1]["media_id"]
|
||||
|
||||
|
||||
@add_sub.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json()).split()
|
||||
async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
if len(msg) < 2:
|
||||
await add_sub.finish("参数不完全,请查看订阅帮助...")
|
||||
sub_type = msg[0]
|
||||
@@ -120,11 +112,22 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
state["id"] = int(id_)
|
||||
|
||||
|
||||
@add_sub.got("sub_type")
|
||||
@add_sub.got("sub_user")
|
||||
@add_sub.got("id")
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
sub_type = state["sub_type"]
|
||||
sub_user = state["sub_user"]
|
||||
id_ = state["id"]
|
||||
async def _(
|
||||
event: MessageEvent,
|
||||
state: T_State,
|
||||
id_: str = ArgStr("id"),
|
||||
sub_type: str = ArgStr("sub_type"),
|
||||
sub_user: str = ArgStr("sub_user"),
|
||||
):
|
||||
if sub_type in ["season", "动漫", "番剧"] and state.get("season_data"):
|
||||
season_data = state["season_data"]
|
||||
if not is_number(id_) or int(id_) < 1 or int(id_) > len(season_data):
|
||||
await add_sub.reject_arg("id", "Id必须为数字且在范围内!请重新输入...")
|
||||
id_ = season_data[int(id_) - 1]["media_id"]
|
||||
id_ = int(id_)
|
||||
if sub_type in ["主播", "直播"]:
|
||||
await add_sub.send(await add_live_sub(id_, sub_user))
|
||||
elif sub_type.lower() in ["up", "用户"]:
|
||||
@@ -141,8 +144,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@del_sub.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if not is_number(msg):
|
||||
await del_sub.finish("Id必须为数字!", at_sender=True)
|
||||
id_ = (
|
||||
@@ -162,12 +165,11 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@show_sub_info.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
id_ = (
|
||||
f"{event.user_id}:{event.group_id}"
|
||||
if isinstance(event, GroupMessageEvent)
|
||||
else f"{event.user_id}"
|
||||
)
|
||||
async def _(event: MessageEvent):
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
id_ = f"{event.group_id}"
|
||||
else:
|
||||
id_ = f"{event.user_id}"
|
||||
data = await BilibiliSub.get_sub_data(id_)
|
||||
live_rst = ""
|
||||
up_rst = ""
|
||||
@@ -181,6 +183,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
up_rst += f"\tUP:{x.uname}\n" f"\tuid:{x.uid}\n" f"------------------\n"
|
||||
if x.sub_type == "season":
|
||||
season_rst += (
|
||||
f"\t番剧id:{x.sub_id}\n"
|
||||
f"\t番名:{x.season_name}\n"
|
||||
f"\t当前集数:{x.season_current_episode}\n"
|
||||
f"------------------\n"
|
||||
@@ -189,7 +192,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
up_rst = "当前订阅的UP:\n" + up_rst if up_rst else up_rst
|
||||
season_rst = "当前订阅的番剧:\n" + season_rst if season_rst else season_rst
|
||||
if not live_rst and not up_rst and not season_rst:
|
||||
live_rst = "您目前没有任何订阅..."
|
||||
live_rst = (
|
||||
"该群目前没有任何订阅..." if isinstance(event, GroupMessageEvent) else "您目前没有任何订阅..."
|
||||
)
|
||||
await show_sub_info.send(live_rst + up_rst + season_rst)
|
||||
|
||||
|
||||
@@ -206,7 +211,7 @@ async def _():
|
||||
await sub_manager.reload_sub_data()
|
||||
sub = await sub_manager.random_sub_data()
|
||||
if sub:
|
||||
logger.info(f"Bilibili订阅开始检测:{sub.sub_id}")
|
||||
logger.debug(f"Bilibili订阅开始检测:{sub.sub_id}")
|
||||
rst = await get_sub_status(sub.sub_id, sub.sub_type)
|
||||
await send_sub_msg(rst, sub, bot)
|
||||
if sub.sub_type == "live":
|
||||
|
||||
@@ -8,7 +8,6 @@ from utils.message_builder import image
|
||||
from bilibili_api.user import User
|
||||
from bilibili_api import user
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from datetime import datetime
|
||||
from utils.browser import get_browser
|
||||
@@ -20,7 +19,7 @@ import random
|
||||
|
||||
bilibili_search_url = "https://api.bilibili.com/x/web-interface/search/all/v2"
|
||||
|
||||
dynamic_path = Path(IMAGE_PATH) / "bilibili_sub" / "dynamic"
|
||||
dynamic_path = IMAGE_PATH / "bilibili_sub" / "dynamic"
|
||||
dynamic_path.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
|
||||
@@ -165,7 +164,9 @@ async def get_media_id(keyword: str) -> dict:
|
||||
for _ in range(3):
|
||||
try:
|
||||
_season_data = {}
|
||||
response = await AsyncHttpx.get(bilibili_search_url, params=params, timeout=5)
|
||||
response = await AsyncHttpx.get(
|
||||
bilibili_search_url, params=params, timeout=5
|
||||
)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get("data"):
|
||||
@@ -191,7 +192,6 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
||||
获取订阅状态
|
||||
:param id_: 订阅 id
|
||||
:param sub_type: 订阅类型
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
if sub_type == "live":
|
||||
@@ -201,7 +201,7 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
||||
elif sub_type == "season":
|
||||
return await _get_season_status(id_)
|
||||
except ResponseCodeException:
|
||||
return "获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||
# except Exception as e:
|
||||
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
|
||||
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
|
||||
@@ -254,7 +254,12 @@ async def _get_up_status(id_: int) -> Optional[str]:
|
||||
if dynamic_img:
|
||||
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
|
||||
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n"
|
||||
if _user.latest_video_created != latest_video_created and video:
|
||||
if (
|
||||
latest_video_created
|
||||
and _user.latest_video_created
|
||||
and video
|
||||
and _user.latest_video_created < latest_video_created
|
||||
):
|
||||
rst = rst + "-------------\n" if rst else rst
|
||||
await BilibiliSub.update_sub_info(
|
||||
id_, latest_video_created=latest_video_created
|
||||
@@ -304,30 +309,34 @@ async def get_user_dynamic(
|
||||
browser = await get_browser()
|
||||
if dynamic_info.get("cards") and browser:
|
||||
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
||||
if local_user.dynamic_upload_time != dynamic_upload_time:
|
||||
if local_user.dynamic_upload_time < dynamic_upload_time:
|
||||
page = await browser.new_page()
|
||||
await page.goto(
|
||||
f"https://space.bilibili.com/{local_user.uid}/dynamic",
|
||||
wait_until="networkidle",
|
||||
timeout=10000,
|
||||
)
|
||||
await page.set_viewport_size({"width": 2560, "height": 1080})
|
||||
# 删除置顶
|
||||
await page.evaluate(
|
||||
try:
|
||||
await page.goto(
|
||||
f"https://space.bilibili.com/{local_user.uid}/dynamic",
|
||||
wait_until="networkidle",
|
||||
timeout=10000,
|
||||
)
|
||||
await page.set_viewport_size({"width": 2560, "height": 1080})
|
||||
# 删除置顶
|
||||
await page.evaluate(
|
||||
"""
|
||||
xs = document.getElementsByClassName('first-card-with-title');
|
||||
for (x of xs) {
|
||||
x.remove();
|
||||
}
|
||||
"""
|
||||
xs = document.getElementsByClassName('first-card-with-title');
|
||||
for (x of xs) {
|
||||
x.remove();
|
||||
}
|
||||
"""
|
||||
)
|
||||
card = await page.query_selector(".card")
|
||||
# 截图并保存
|
||||
await card.screenshot(
|
||||
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||
timeout=100000,
|
||||
)
|
||||
await page.close()
|
||||
)
|
||||
card = await page.query_selector(".card")
|
||||
# 截图并保存
|
||||
await card.screenshot(
|
||||
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||
timeout=100000,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
|
||||
finally:
|
||||
await page.close()
|
||||
return (
|
||||
image(
|
||||
f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from pathlib import Path
|
||||
from bilibili_api import user
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
BORDER_PATH = Path(IMAGE_PATH) / "border"
|
||||
BORDER_PATH = IMAGE_PATH / "border"
|
||||
BORDER_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
@@ -35,21 +34,21 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
|
||||
sex = user_info["sex"]
|
||||
face = user_info["face"]
|
||||
sign = user_info["sign"]
|
||||
ava = CreateImg(100, 100, background=BytesIO(await get_pic(face)))
|
||||
ava = BuildImage(100, 100, background=BytesIO(await get_pic(face)))
|
||||
ava.circle()
|
||||
cover = CreateImg(470, 265, background=BytesIO(await get_pic(cover)))
|
||||
cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover)))
|
||||
print()
|
||||
|
||||
|
||||
def _create_live_des_image(
|
||||
title: str,
|
||||
cover: CreateImg,
|
||||
cover: BuildImage,
|
||||
tags: str,
|
||||
des: str,
|
||||
user_name: str,
|
||||
sex: str,
|
||||
sign: str,
|
||||
ava: CreateImg,
|
||||
ava: BuildImage,
|
||||
):
|
||||
"""
|
||||
生成主播简介图片
|
||||
@@ -66,6 +65,6 @@ def _create_live_des_image(
|
||||
border = BORDER_PATH / "0.png"
|
||||
border_img = None
|
||||
if border.exists():
|
||||
border_img = CreateImg(1772, 2657, background=border)
|
||||
bk = CreateImg(1772, 2657, font_size=30)
|
||||
border_img = BuildImage(1772, 2657, background=border)
|
||||
bk = BuildImage(1772, 2657, font_size=30)
|
||||
bk.paste(cover, (0, 100), center_type="by_width")
|
||||
|
||||
+27
-36
@@ -1,12 +1,12 @@
|
||||
from nonebot import on_command
|
||||
from .data_source import get_bt_info
|
||||
from services.log import logger
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.adapters.cqhttp import PrivateMessageEvent
|
||||
from utils.utils import get_message_text
|
||||
from nonebot.adapters.cqhttp.permission import PRIVATE
|
||||
from nonebot.adapters.onebot.v11 import PrivateMessageEvent, Message
|
||||
from nonebot.adapters.onebot.v11.permission import PRIVATE
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from utils.utils import is_number
|
||||
from nonebot.params import CommandArg, ArgStr
|
||||
from nonebot.typing import T_State
|
||||
|
||||
__zx_plugin_name__ = "磁力搜索"
|
||||
__plugin_usage__ = """
|
||||
@@ -28,9 +28,7 @@ __plugin_settings__ = {
|
||||
"limit_superuser": False,
|
||||
"cmd": ["bt", "磁力搜索", "Bt", "BT"],
|
||||
}
|
||||
__plugin_block_limit__ = {
|
||||
"rst": "您有bt任务正在进行,请等待结束."
|
||||
}
|
||||
__plugin_block_limit__ = {"rst": "您有bt任务正在进行,请等待结束."}
|
||||
__plugin_configs__ = {
|
||||
"BT_MAX_NUM": {
|
||||
"value": 10,
|
||||
@@ -43,44 +41,37 @@ __plugin_configs__ = {
|
||||
bt = on_command("bt", permission=PRIVATE, priority=5, block=True)
|
||||
|
||||
|
||||
@bt.args_parser
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
if str(event.get_message()) in ["取消", "算了"]:
|
||||
await bt.finish("已取消操作..", at_sender=True)
|
||||
msg = get_message_text(event.json())
|
||||
if not msg:
|
||||
await bt.reject("你想搜索什么呢?", at_sender=True)
|
||||
state["keyword"] = msg
|
||||
state["page"] = "1"
|
||||
|
||||
|
||||
@bt.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
mp = get_message_text(event.json())
|
||||
if not mp:
|
||||
return
|
||||
mp = mp.split()
|
||||
if len(mp) == 2:
|
||||
state["keyword"] = mp[0]
|
||||
state["page"] = mp[1]
|
||||
async def _(state: T_State, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
if msg:
|
||||
keyword = None
|
||||
page = 1
|
||||
if n := len(msg):
|
||||
keyword = msg[0]
|
||||
if n > 1 and is_number(msg[1]) and int(msg[1]) > 0:
|
||||
page = int(msg[1])
|
||||
state["keyword"] = keyword
|
||||
state["page"] = page
|
||||
else:
|
||||
state["keyword"] = mp[0]
|
||||
state["page"] = "1"
|
||||
state["page"] = 1
|
||||
|
||||
|
||||
@bt.got("keyword", prompt="虚空磁力?查什么GKD")
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
keyword = state["keyword"]
|
||||
page = state["page"]
|
||||
await bt.send("开始搜索....", at_sender=True)
|
||||
@bt.got("keyword", prompt="请输入要查询的内容!")
|
||||
async def _(
|
||||
event: PrivateMessageEvent,
|
||||
state: T_State,
|
||||
keyword: str = ArgStr("keyword"),
|
||||
page: str = ArgStr("page"),
|
||||
):
|
||||
send_flag = False
|
||||
try:
|
||||
async for title, itype, create_time, file_size, link in get_bt_info(
|
||||
async for title, type_, create_time, file_size, link in get_bt_info(
|
||||
keyword, page
|
||||
):
|
||||
await bt.send(
|
||||
f"标题:{title}\n"
|
||||
f"类型:{itype}\n"
|
||||
f"类型:{type_}\n"
|
||||
f"创建时间:{create_time}\n"
|
||||
f"文件大小:{file_size}\n"
|
||||
f"种子:{link}"
|
||||
|
||||
@@ -9,10 +9,10 @@ if platform.system() == "Windows":
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
|
||||
|
||||
url = "http://www.eclzz.world"
|
||||
url = "http://www.eclzz.mobi"
|
||||
|
||||
|
||||
async def get_bt_info(keyword: str, page: str):
|
||||
async def get_bt_info(keyword: str, page: int):
|
||||
"""
|
||||
获取资源信息
|
||||
:param keyword: 关键词
|
||||
@@ -34,11 +34,11 @@ async def get_bt_info(keyword: str, page: str):
|
||||
.strip()
|
||||
)
|
||||
spans = divs[2].find_all("span")
|
||||
itype = spans[0].text
|
||||
type_ = spans[0].text
|
||||
create_time = spans[1].find("b").text
|
||||
file_size = spans[2].find("b").text
|
||||
link = await get_download_link(divs[0].find("a")["href"])
|
||||
yield title, itype, create_time, file_size, link
|
||||
yield title, type_, create_time, file_size, link
|
||||
|
||||
|
||||
async def get_download_link(_url: str) -> str:
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
from .music_163 import get_song_id, get_song_info
|
||||
from nonebot.adapters.cqhttp import Bot, Event, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from services.log import logger
|
||||
from nonebot import on_command
|
||||
|
||||
|
||||
__zx_plugin_name__ = "点歌"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
在线点歌
|
||||
指令:
|
||||
点歌 [歌名]
|
||||
""".strip()
|
||||
__plugin_des__ = "为你点播了一首曾经的歌"
|
||||
__plugin_cmd__ = ["点歌 [歌名]"]
|
||||
__plugin_type__ = ("一些工具",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["点歌"],
|
||||
}
|
||||
|
||||
|
||||
music = on_command("点歌", priority=5, block=True)
|
||||
|
||||
|
||||
@music.handle()
|
||||
async def handle_first_receive(bot: Bot, event: Event, state: T_State):
|
||||
args = str(event.get_message()).strip()
|
||||
if args:
|
||||
state["song_name"] = args
|
||||
|
||||
|
||||
@music.got("song_name", prompt="歌名是?")
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
song = state["song_name"]
|
||||
song_id = await get_song_id(song)
|
||||
if not song_id:
|
||||
await music.finish("没有找到这首歌!", at_sender=True)
|
||||
for _ in range(3):
|
||||
song_content = [{"type": "music", "data": {"type": 163, "id": song_id}}]
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 点歌 :{song}"
|
||||
)
|
||||
await music.finish(song_content)
|
||||
else:
|
||||
await music.finish("网易云繁忙...")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from nonebot import on_command
|
||||
from .data_source import Check
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.message_builder import image
|
||||
@@ -29,5 +27,5 @@ check_ = on_command(
|
||||
|
||||
|
||||
@check_.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
async def _():
|
||||
await check_.send(image(b64=await check.show()))
|
||||
|
||||
@@ -2,9 +2,8 @@ import psutil
|
||||
import time
|
||||
from datetime import datetime
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from pathlib import Path
|
||||
import asyncio
|
||||
from services.log import logger
|
||||
|
||||
@@ -49,7 +48,7 @@ class Check:
|
||||
|
||||
async def show(self):
|
||||
await self.check_all()
|
||||
A = CreateImg(0, 0, font_size=24)
|
||||
A = BuildImage(0, 0, font_size=24)
|
||||
rst = (
|
||||
f'[Time] {str(datetime.now()).split(".")[0]}\n'
|
||||
f"-----System-----\n"
|
||||
@@ -69,10 +68,10 @@ class Check:
|
||||
if w > width:
|
||||
width = w
|
||||
height += 30
|
||||
A = CreateImg(width + 50, height + 10, font_size=24, font="HWZhongSong.ttf")
|
||||
A = BuildImage(width + 50, height + 10, font_size=24, font="HWZhongSong.ttf")
|
||||
A.transparent(1)
|
||||
A.text((10, 10), rst)
|
||||
_x = max(width, height)
|
||||
bk = CreateImg(_x + 100, _x + 100, background=Path(IMAGE_PATH) / "background" / "check" / "0.jpg")
|
||||
bk = BuildImage(_x + 100, _x + 100, background=IMAGE_PATH / "background" / "check" / "0.jpg")
|
||||
bk.paste(A, alpha=True, center_type='center')
|
||||
return bk.pic2bs4()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot import on_command
|
||||
from .data_source import check_update, get_latest_version_data
|
||||
@@ -8,6 +7,7 @@ from utils.utils import scheduler, get_bot
|
||||
from pathlib import Path
|
||||
from configs.config import Config
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.params import ArgStr
|
||||
import platform
|
||||
import os
|
||||
|
||||
@@ -45,7 +45,7 @@ restart = on_command(
|
||||
|
||||
|
||||
@update_zhenxun.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(bot: Bot):
|
||||
try:
|
||||
code, error = await check_update(bot)
|
||||
if error:
|
||||
@@ -67,14 +67,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@restart.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
if str(platform.system()).lower() == "windows":
|
||||
await restart.finish("暂无windows重启脚本...")
|
||||
|
||||
|
||||
@restart.got("flag", prompt="确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)")
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
flag = state["flag"]
|
||||
async def _(flag: str = ArgStr("flag")):
|
||||
if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
|
||||
await restart.send("开始重启真寻..请稍等...")
|
||||
open("is_restart", "w")
|
||||
@@ -107,20 +106,19 @@ async def _():
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=f"检测到真寻版本更新\n"
|
||||
f"当前版本:{_version},最新版本:{latest_version}\n"
|
||||
f"尝试自动更新...",
|
||||
f"当前版本:{_version},最新版本:{latest_version}",
|
||||
)
|
||||
try:
|
||||
code = await check_update(bot)
|
||||
except Exception as e:
|
||||
logger.error(f"更新真寻未知错误 {type(e)}:{e}")
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=f"更新真寻未知错误 {type(e)}:{e}\n",
|
||||
)
|
||||
else:
|
||||
if code == 200:
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=f"更新完毕,请重启真寻....",
|
||||
)
|
||||
# try:
|
||||
# code = await check_update(bot)
|
||||
# except Exception as e:
|
||||
# logger.error(f"更新真寻未知错误 {type(e)}:{e}")
|
||||
# await bot.send_private_msg(
|
||||
# user_id=int(list(bot.config.superusers)[0]),
|
||||
# message=f"更新真寻未知错误 {type(e)}:{e}\n",
|
||||
# )
|
||||
# else:
|
||||
# if code == 200:
|
||||
# await bot.send_private_msg(
|
||||
# user_id=int(list(bot.config.superusers)[0]),
|
||||
# message=f"更新完毕,请重启真寻....",
|
||||
# )
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from nonebot.adapters.cqhttp import Bot, Message
|
||||
from utils.image_utils import CreateImg
|
||||
from nonebot.adapters.onebot.v11 import Bot, Message
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from utils.http_utils import AsyncHttpx
|
||||
@@ -73,6 +73,7 @@ async def check_update(bot: Bot) -> 'int, str':
|
||||
message=f"检测真寻已更新,当前版本:{_version},最新版本:{latest_version}\n" f"开始更新.....",
|
||||
)
|
||||
logger.info(f"开始下载真寻最新版文件....")
|
||||
tar_gz_url = (await AsyncHttpx.get(tar_gz_url)).headers.get('Location')
|
||||
if await AsyncHttpx.download_file(tar_gz_url, zhenxun_latest_tar_gz):
|
||||
logger.info("下载真寻最新版文件完成....")
|
||||
error = await asyncio.get_event_loop().run_in_executor(
|
||||
@@ -85,12 +86,12 @@ async def check_update(bot: Bot) -> 'int, str':
|
||||
update_info = data["body"]
|
||||
width = 0
|
||||
height = len(update_info.split('\n')) * 24
|
||||
A = CreateImg(width, height, font_size=20)
|
||||
A = BuildImage(width, height, font_size=20)
|
||||
for m in update_info.split('\n'):
|
||||
w, h = A.getsize(m)
|
||||
if w > width:
|
||||
width = w
|
||||
A = CreateImg(width + 50, height, font_size=20)
|
||||
A = BuildImage(width + 50, height, font_size=20)
|
||||
A.text((10, 10), update_info)
|
||||
A.save(f'{IMAGE_PATH}/update_info.png')
|
||||
await bot.send_private_msg(
|
||||
@@ -128,21 +129,32 @@ def _file_handle(latest_version: str) -> str:
|
||||
shutil.rmtree(backup_dir)
|
||||
tf = None
|
||||
error = ''
|
||||
try:
|
||||
backup_dir.mkdir(exist_ok=True, parents=True)
|
||||
logger.info("开始解压真寻文件压缩包....")
|
||||
tf = tarfile.open(zhenxun_latest_tar_gz)
|
||||
tf.extractall(temp_dir)
|
||||
logger.info("解压真寻文件压缩包完成....")
|
||||
zhenxun_latest_file = Path(temp_dir) / os.listdir(temp_dir)[0]
|
||||
update_info_file = Path(zhenxun_latest_file) / "update_info.json"
|
||||
update_info = json.load(open(update_info_file, "r", encoding="utf8"))
|
||||
update_file = update_info["update_file"]
|
||||
add_file = update_info["add_file"]
|
||||
delete_file = update_info["delete_file"]
|
||||
config_file = Path() / "configs" / "config.py"
|
||||
config_path_file = Path() / "configs" / "config_path.py"
|
||||
for file in delete_file + update_file:
|
||||
# try:
|
||||
backup_dir.mkdir(exist_ok=True, parents=True)
|
||||
logger.info("开始解压真寻文件压缩包....")
|
||||
tf = tarfile.open(zhenxun_latest_tar_gz)
|
||||
tf.extractall(temp_dir)
|
||||
logger.info("解压真寻文件压缩包完成....")
|
||||
zhenxun_latest_file = Path(temp_dir) / os.listdir(temp_dir)[0]
|
||||
update_info_file = Path(zhenxun_latest_file) / "update_info.json"
|
||||
update_info = json.load(open(update_info_file, "r", encoding="utf8"))
|
||||
update_file = update_info["update_file"]
|
||||
add_file = update_info["add_file"]
|
||||
delete_file = update_info["delete_file"]
|
||||
config_file = Path() / "configs" / "config.py"
|
||||
config_path_file = Path() / "configs" / "path_config.py"
|
||||
for file in [config_file.name]:
|
||||
tmp = ""
|
||||
new_file = Path(zhenxun_latest_file) / "configs" / file
|
||||
old_file = Path() / "configs" / file
|
||||
new_lines = open(new_file, "r", encoding="utf8").readlines()
|
||||
old_lines = open(old_file, "r", encoding="utf8").readlines()
|
||||
for nl in new_lines:
|
||||
tmp += check_old_lines(old_lines, nl)
|
||||
with open(old_file, "w", encoding="utf8") as f:
|
||||
f.write(tmp)
|
||||
for file in delete_file + update_file:
|
||||
if file != "configs":
|
||||
file = Path() / file
|
||||
backup_file = Path(backup_dir) / file
|
||||
if file.exists():
|
||||
@@ -157,23 +169,15 @@ def _file_handle(latest_version: str) -> str:
|
||||
with open(backup_file, "w", encoding="utf8") as wf:
|
||||
wf.write(data)
|
||||
logger.info(f"已备份文件:{file}")
|
||||
for file in add_file + update_file:
|
||||
new_file = Path(zhenxun_latest_file) / file
|
||||
old_file = Path() / file
|
||||
if old_file not in [config_file, config_path_file]:
|
||||
if not old_file.exists() and new_file.exists():
|
||||
os.rename(new_file.absolute(), old_file.absolute())
|
||||
logger.info(f"已更新文件:{file}")
|
||||
else:
|
||||
tmp = ""
|
||||
new_lines = open(new_file, "r", encoding="utf8").readlines()
|
||||
old_lines = open(old_file, "r", encoding="utf8").readlines()
|
||||
for nl in new_lines:
|
||||
tmp += check_old_lines(old_lines, nl)
|
||||
with open(file, "w", encoding="utf8") as f:
|
||||
f.write(tmp)
|
||||
except Exception as e:
|
||||
error = f'{type(e)}:{e}'
|
||||
for file in add_file + update_file:
|
||||
new_file = Path(zhenxun_latest_file) / file
|
||||
old_file = Path() / file
|
||||
if old_file not in [config_file, config_path_file] and file != "configs":
|
||||
if not old_file.exists() and new_file.exists():
|
||||
os.rename(new_file.absolute(), old_file.absolute())
|
||||
logger.info(f"已更新文件:{file}")
|
||||
# except Exception as e:
|
||||
# error = f'{type(e)}:{e}'
|
||||
if tf:
|
||||
tf.close()
|
||||
if temp_dir.exists():
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from nonebot import on_command
|
||||
from nonebot import on_regex
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
|
||||
from utils.message_builder import image
|
||||
from services.log import logger
|
||||
from utils.manager import withdraw_message_manager
|
||||
@@ -31,12 +31,10 @@ __plugin_configs__ = {
|
||||
},
|
||||
}
|
||||
|
||||
coser = on_command(
|
||||
"cos", aliases={"coser", "括丝", "COS", "Cos", "cOS", "coS"}, priority=5, block=True
|
||||
)
|
||||
coser = on_regex("^(cos|COS|coser|括丝)$", priority=5, block=True)
|
||||
|
||||
|
||||
url = "http://iw233.cn/API/cos.php"
|
||||
url = "https://api.iyk0.com/cos"
|
||||
|
||||
|
||||
@coser.handle()
|
||||
@@ -51,4 +49,3 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
except Exception as e:
|
||||
await coser.send("你cos给我看!")
|
||||
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import get_message_text, is_number, get_message_imgs
|
||||
from utils.utils import is_number, get_message_img
|
||||
from utils.message_builder import image
|
||||
from utils.message_builder import text as _text
|
||||
from services.log import logger
|
||||
from utils.message_builder import at
|
||||
from nonebot.params import CommandArg
|
||||
|
||||
|
||||
__zx_plugin_name__ = "联系管理员"
|
||||
@@ -58,14 +58,12 @@ reply = on_command("/t", priority=1, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@dialogue.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
uid = event.user_id
|
||||
coffee = int(list(bot.config.superusers)[0])
|
||||
text = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
text = arg.extract_plain_text().strip()
|
||||
img_msg = _text("")
|
||||
for img in get_message_imgs(event.json()):
|
||||
for img in get_message_img(event.json()):
|
||||
img_msg += image(img)
|
||||
if not text or text in ["帮助"]:
|
||||
if not text and not img_msg:
|
||||
await dialogue.send("请发送[滴滴滴]+您要说的内容~", at_sender=True)
|
||||
else:
|
||||
group_id = 0
|
||||
@@ -76,17 +74,18 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group_name = (await bot.get_group_info(group_id=event.group_id))[
|
||||
"group_name"
|
||||
]
|
||||
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
await bot.send_private_msg(
|
||||
user_id=coffee,
|
||||
message=_text(
|
||||
f"*****一份交流报告*****\n"
|
||||
f"昵称:{nickname}({uid})\n"
|
||||
f"群聊:{group_name}({group_id})\n"
|
||||
f"消息:{text}"
|
||||
nickname = event.sender.card or event.sender.nickname
|
||||
for coffee in bot.config.superusers:
|
||||
await bot.send_private_msg(
|
||||
user_id=int(coffee),
|
||||
message=_text(
|
||||
f"*****一份交流报告*****\n"
|
||||
f"昵称:{nickname}({event.user_id})\n"
|
||||
f"群聊:{group_name}({group_id})\n"
|
||||
f"消息:{text}"
|
||||
)
|
||||
+ img_msg,
|
||||
)
|
||||
+ img_msg,
|
||||
)
|
||||
await dialogue.send(
|
||||
_text(f"您的话已发送至管理员!\n======\n{text}") + img_msg, at_sender=True
|
||||
)
|
||||
@@ -99,12 +98,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
"msg": _text(text) + img_msg,
|
||||
}
|
||||
# print(dialogue_data)
|
||||
logger.info(f"Q{uid}@群{group_id} 联系管理员:{coffee} text:{text}")
|
||||
logger.info(f"Q{event.user_id}@群{group_id} 联系管理员:text:{text}")
|
||||
|
||||
|
||||
@reply.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if not msg:
|
||||
result = "*****待回复消息总览*****\n"
|
||||
for key in dialogue_data.keys():
|
||||
@@ -127,26 +126,26 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
id_ = msg[0]
|
||||
user_id = dialogue_data[id_]["user_id"]
|
||||
group_id = dialogue_data[id_]["group_id"]
|
||||
text = msg[1]
|
||||
text = " ".join(msg[1:])
|
||||
dialogue_data.pop(id_)
|
||||
else:
|
||||
user_id = 0
|
||||
if is_number(msg[1]):
|
||||
group_id = int(msg[1])
|
||||
text = msg[2]
|
||||
text = " ".join(msg[2:])
|
||||
else:
|
||||
await reply.finish("群号错误...", at_sender=True)
|
||||
else:
|
||||
user_id = int(msg[0])
|
||||
if is_number(msg[1]) and len(msg[1]) > 5:
|
||||
group_id = int(msg[1])
|
||||
text = msg[2]
|
||||
text = " ".join(msg[2:])
|
||||
else:
|
||||
group_id = 0
|
||||
text = msg[1]
|
||||
text = " ".join(msg[1:])
|
||||
else:
|
||||
await reply.finish("第一参数,请输入数字.....", at_sender=True)
|
||||
for img in get_message_imgs(event.json()):
|
||||
for img in get_message_img(event.json()):
|
||||
text += image(img)
|
||||
if group_id:
|
||||
if user_id:
|
||||
|
||||
Executable → Regular
+171
-391
@@ -1,53 +1,46 @@
|
||||
from nonebot import on_regex, on_keyword
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from .genshin_handle import (
|
||||
genshin_draw,
|
||||
update_genshin_info,
|
||||
reset_count,
|
||||
reload_genshin_pool,
|
||||
)
|
||||
from .prts_handle import update_prts_info, prts_draw, reload_prts_pool
|
||||
from .pretty_handle import update_pretty_info, pretty_draw, reload_pretty_pool
|
||||
from .guardian_handle import update_guardian_info, guardian_draw
|
||||
from .pcr_handle import update_pcr_info, pcr_draw
|
||||
from .azur_handle import update_azur_info, azur_draw
|
||||
from .fgo_handle import update_fgo_info, fgo_draw
|
||||
from .onmyoji_handle import update_onmyoji_info, onmyoji_draw
|
||||
from .update_game_info import update_info
|
||||
from .util import is_number, check_num
|
||||
from .rule import is_switch
|
||||
from .config import (
|
||||
PRTS_FLAG,
|
||||
PRETTY_FLAG,
|
||||
GUARDIAN_FLAG,
|
||||
GENSHIN_FLAG,
|
||||
PCR_FLAG,
|
||||
AZUR_FLAG,
|
||||
FGO_FLAG,
|
||||
ONMYOJI_FLAG,
|
||||
)
|
||||
from .async_update_game_info import async_update_game
|
||||
import re
|
||||
import asyncio
|
||||
from utils.utils import scheduler
|
||||
from services.log import logger
|
||||
import traceback
|
||||
from cn2an import cn2an
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Set, Tuple
|
||||
|
||||
import nonebot
|
||||
from nonebot import on_regex, on_keyword
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||
from nonebot.log import logger
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.params import RegexGroup
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_Handler
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
|
||||
from .handles.base_handle import BaseHandle
|
||||
from .handles.azur_handle import AzurHandle
|
||||
from .handles.fgo_handle import FgoHandle
|
||||
from .handles.genshin_handle import GenshinHandle
|
||||
from .handles.guardian_handle import GuardianHandle
|
||||
from .handles.onmyoji_handle import OnmyojiHandle
|
||||
from .handles.pcr_handle import PcrHandle
|
||||
from .handles.pretty_handle import PrettyHandle
|
||||
from .handles.prts_handle import PrtsHandle
|
||||
|
||||
from .config import draw_config
|
||||
|
||||
|
||||
__zx_plugin_name__ = "游戏抽卡"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
模拟赛马娘,原神,明日方舟,坎公骑冠剑,公主连结(国/台),碧蓝航线,FGO,阴阳师进行抽卡
|
||||
指令:
|
||||
原神[1-300]抽: 原神常驻池
|
||||
原神角色[1-300]抽: 原神角色UP池子
|
||||
原神武器[1-300]抽: 原神武器UP池子
|
||||
原神[1-180]抽: 原神常驻池
|
||||
原神角色[1-180]抽: 原神角色UP池子
|
||||
原神武器[1-180]抽: 原神武器UP池子
|
||||
重置原神抽卡: 清空当前卡池的抽卡次数[即从0开始计算UP概率]
|
||||
方舟[1-300]抽: 方舟卡池,当有当期UP时指向UP池
|
||||
赛马娘[1-200]抽: 赛马娘卡池,当有当期UP时指向UP池
|
||||
坎公骑冠剑[1-300]抽: 坎公骑冠剑卡池,当有当期UP时指向UP池
|
||||
pcr/公主连接[1-300]抽: 公主连接卡池
|
||||
碧蓝航线/碧蓝[重型/轻型/特型][1-300]抽: 碧蓝航线重型/轻型/特型卡池
|
||||
碧蓝航线/碧蓝[重型/轻型/特型/活动][1-300]抽: 碧蓝航线重型/轻型/特型/活动卡池
|
||||
fgo[1-300]抽: fgo卡池
|
||||
阴阳师[1-300]抽: 阴阳师卡池
|
||||
* 以上指令可以通过 XX一井 来指定最大抽取数量 *
|
||||
@@ -70,9 +63,9 @@ usage:
|
||||
""".strip()
|
||||
__plugin_des__ = "就算是模拟抽卡也不能改变自己是个非酋"
|
||||
__plugin_cmd__ = [
|
||||
"原神[1-300]抽",
|
||||
"原神角色[1-300]抽",
|
||||
"原神武器[1-300]抽",
|
||||
"原神[1-180]抽",
|
||||
"原神角色[1-180]抽",
|
||||
"原神武器[1-180]抽",
|
||||
"重置原神抽卡",
|
||||
"方舟[1-300]抽",
|
||||
"赛马娘[1-200]抽",
|
||||
@@ -102,314 +95,137 @@ __plugin_settings__ = {
|
||||
}
|
||||
|
||||
|
||||
prts = on_regex(
|
||||
r".*?方舟[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("prts"), priority=5, block=True
|
||||
)
|
||||
prts_update = on_keyword(
|
||||
{"更新方舟信息", "更新明日方舟信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
prts_up_reload = on_keyword({"重载方舟卡池"}, priority=1, block=True)
|
||||
@dataclass
|
||||
class Game:
|
||||
keywords: Set[str]
|
||||
handle: BaseHandle
|
||||
flag: bool
|
||||
max_count: int = 300 # 一次最大抽卡数
|
||||
reload_time: Optional[int] = None # 重载UP池时间(小时)
|
||||
|
||||
genshin = on_regex(
|
||||
".*?原神(武器|角色)?池?[1-9|一][0-9]{0,2}[抽|井]",
|
||||
rule=is_switch("genshin"),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
genshin_update = on_keyword({"更新原神信息"}, permission=SUPERUSER, priority=1, block=True)
|
||||
genshin_reset = on_keyword({"重置原神抽卡"}, priority=1, block=True)
|
||||
genshin_up_reload = on_keyword({"重载原神卡池"}, priority=1, block=True)
|
||||
|
||||
pretty = on_regex(
|
||||
".*?马娘卡?[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("pretty"), priority=5, block=True
|
||||
)
|
||||
pretty_update = on_keyword(
|
||||
{"更新马娘信息", "更新赛马娘信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
pretty_up_reload = on_keyword({"重载赛马娘卡池"}, priority=1, block=True)
|
||||
|
||||
guardian = on_regex(
|
||||
".*?坎公骑冠剑武?器?[1-9|一][0-9]{0,2}[抽|井]",
|
||||
rule=is_switch("guardian"),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
guardian_update = on_keyword(
|
||||
{"更新坎公骑冠剑信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
games = (
|
||||
Game({"azur", "碧蓝", "碧蓝航线"}, AzurHandle(), draw_config.AZUR_FLAG),
|
||||
Game({"fgo", "命运冠位指定"}, FgoHandle(), draw_config.FGO_FLAG),
|
||||
Game(
|
||||
{"genshin", "原神"},
|
||||
GenshinHandle(),
|
||||
draw_config.GENSHIN_FLAG,
|
||||
max_count=180,
|
||||
reload_time=18,
|
||||
),
|
||||
Game(
|
||||
{"guardian", "坎公骑冠剑"},
|
||||
GuardianHandle(),
|
||||
draw_config.GUARDIAN_FLAG,
|
||||
reload_time=4,
|
||||
),
|
||||
Game({"onmyoji", "阴阳师"}, OnmyojiHandle(), draw_config.ONMYOJI_FLAG),
|
||||
Game({"pcr", "公主连结", "公主连接", "公主链接", "公主焊接"}, PcrHandle(), draw_config.PCR_FLAG),
|
||||
Game(
|
||||
{"pretty", "马娘", "赛马娘"},
|
||||
PrettyHandle(),
|
||||
draw_config.PRETTY_FLAG,
|
||||
max_count=200,
|
||||
reload_time=4,
|
||||
),
|
||||
Game({"prts", "方舟", "明日方舟"}, PrtsHandle(), draw_config.PRTS_FLAG, reload_time=4),
|
||||
)
|
||||
|
||||
pcr = on_regex(
|
||||
".*?(pcr|公主连结|公主连接|公主链接|公主焊接)[1-9|一][0-9]{0,2}[抽|井]",
|
||||
rule=is_switch("pcr"),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
pcr_update = on_keyword(
|
||||
{"更新pcr信息", "更新公主连结信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
azur = on_regex(
|
||||
".*?碧蓝航?线?(轻型|重型|特型)池?[1-9|一][0-9]{0,2}[抽]",
|
||||
rule=is_switch("azur"),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
azur_update = on_keyword(
|
||||
{"更新碧蓝信息", "更新碧蓝航线信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
fgo = on_regex(
|
||||
".*?fgo[1-9|一][0-9]{0,2}[抽]", rule=is_switch("fgo"), priority=5, block=True
|
||||
)
|
||||
fgo_update = on_keyword({"更新fgo信息"}, permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
onmyoji = on_regex(
|
||||
".*?阴阳师[1-9|一][0-9]{0,2}[抽]", rule=is_switch("onmyoji"), priority=5, block=True
|
||||
)
|
||||
onmyoji_update = on_keyword({"更新阴阳师信息"}, permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
|
||||
@prts.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
if msg in ["方舟一井", "方舟1井"]:
|
||||
num = 300
|
||||
else:
|
||||
rmsg = re.search(r".*?方舟(.*)抽", msg)
|
||||
if rmsg:
|
||||
num, flag = check_num(rmsg.group(1), 300)
|
||||
if not flag:
|
||||
await prts.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await prts.send(await prts_draw(int(num)), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 方舟 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@prts_up_reload.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = await reload_prts_pool()
|
||||
await prts_up_reload.finish(Message(f"重载完成!\n{text}"))
|
||||
|
||||
|
||||
@genshin.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
rmsg = re.search(r".*?原神(武器|角色)?池?(.*)[抽|井]", msg)
|
||||
if rmsg:
|
||||
pool_name = rmsg.group(1)
|
||||
if pool_name == "武器":
|
||||
pool_name = "arms"
|
||||
elif pool_name == "角色":
|
||||
pool_name = "char"
|
||||
else:
|
||||
pool_name = ""
|
||||
num = rmsg.group(2)
|
||||
if msg.find("一井") != -1 or msg.find("1井") != -1:
|
||||
num = 180
|
||||
else:
|
||||
num, flag = check_num(num, 180)
|
||||
if not flag:
|
||||
await genshin.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await genshin.send(
|
||||
await genshin_draw(event.user_id, int(num), pool_name), at_sender=True
|
||||
)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 原神 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@genshin_up_reload.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = await reload_genshin_pool()
|
||||
await genshin_reset.finish(Message(f"重载成功!\n{text}"))
|
||||
|
||||
|
||||
@genshin_reset.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
reset_count(event.user_id)
|
||||
await genshin_reset.send("重置了原神抽卡次数", at_sender=True)
|
||||
|
||||
|
||||
@pretty.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
if msg.find("1井") != -1 or msg.find("一井") != -1:
|
||||
num = 200
|
||||
if msg.find("卡") == -1:
|
||||
pool_name = "char"
|
||||
else:
|
||||
pool_name = "card"
|
||||
else:
|
||||
rmsg = re.search(r".*?马娘(.*)抽", msg)
|
||||
if rmsg:
|
||||
num = rmsg.group(1)
|
||||
if num[0] == "卡":
|
||||
num = num[1:]
|
||||
pool_name = "card"
|
||||
def create_matchers():
|
||||
def draw_handler(game: Game) -> T_Handler:
|
||||
async def handler(
|
||||
matcher: Matcher, event: MessageEvent, args: Tuple[str, ...] = RegexGroup()
|
||||
):
|
||||
pool_name, num, unit = args
|
||||
if num == "单":
|
||||
num = 1
|
||||
else:
|
||||
pool_name = "char"
|
||||
num, flag = check_num(num, 200)
|
||||
if not flag:
|
||||
await pretty.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await pretty.send(await pretty_draw(int(num), pool_name), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 赛马娘 {num}抽"
|
||||
)
|
||||
try:
|
||||
num = int(cn2an(num, mode="smart"))
|
||||
except ValueError:
|
||||
await matcher.finish("必!须!是!数!字!")
|
||||
if unit == "井":
|
||||
num *= game.max_count
|
||||
if num < 1:
|
||||
await matcher.finish("虚空抽卡???")
|
||||
elif num > game.max_count:
|
||||
await matcher.finish("一井都满不足不了你嘛!快爬开!")
|
||||
pool_name = (
|
||||
pool_name.replace("池", "")
|
||||
.replace("武器", "arms")
|
||||
.replace("角色", "char")
|
||||
.replace("卡牌", "card")
|
||||
.replace("卡", "card")
|
||||
)
|
||||
try:
|
||||
res = await game.handle.draw(num, pool_name=pool_name, user_id=event.user_id)
|
||||
except:
|
||||
logger.warning(traceback.format_exc())
|
||||
await matcher.finish("出错了...")
|
||||
await matcher.finish(res, at_sender=True)
|
||||
|
||||
return handler
|
||||
|
||||
def update_handler(game: Game) -> T_Handler:
|
||||
async def handler(matcher: Matcher):
|
||||
await game.handle.update_info()
|
||||
await matcher.finish("更新完成!")
|
||||
|
||||
return handler
|
||||
|
||||
def reload_handler(game: Game) -> T_Handler:
|
||||
async def handler(matcher: Matcher):
|
||||
res = await game.handle.reload_pool()
|
||||
if res:
|
||||
await matcher.finish(res)
|
||||
|
||||
return handler
|
||||
|
||||
def reset_handler(game: Game) -> T_Handler:
|
||||
async def handler(matcher: Matcher, event: MessageEvent):
|
||||
if game.handle.reset_count(event.user_id):
|
||||
await matcher.finish("重置成功!")
|
||||
|
||||
return handler
|
||||
|
||||
def scheduled_job(game: Game) -> T_Handler:
|
||||
async def handler():
|
||||
await game.handle.reload_pool()
|
||||
|
||||
return handler
|
||||
|
||||
for game in games:
|
||||
pool_pattern = r"([^\s单0-9零一二三四五六七八九百十]{0,3})"
|
||||
num_pattern = r"(单|[0-9零一二三四五六七八九百十]{1,3})"
|
||||
unit_pattern = r"([抽|井|连])"
|
||||
draw_regex = r".*?(?:{})\s*{}\s*{}\s*{}".format(
|
||||
"|".join(game.keywords), pool_pattern, num_pattern, unit_pattern
|
||||
)
|
||||
update_keywords = {f"更新{keyword}信息" for keyword in game.keywords}
|
||||
reload_keywords = {f"重载{keyword}卡池" for keyword in game.keywords}
|
||||
reset_keywords = {f"重置{keyword}抽卡" for keyword in game.keywords}
|
||||
if game.flag:
|
||||
on_regex(draw_regex, priority=5, block=True).append_handler(
|
||||
draw_handler(game)
|
||||
)
|
||||
on_keyword(
|
||||
update_keywords, permission=SUPERUSER, priority=1, block=True
|
||||
).append_handler(update_handler(game))
|
||||
on_keyword(reload_keywords, priority=1, block=True).append_handler(
|
||||
reload_handler(game)
|
||||
)
|
||||
on_keyword(reset_keywords, priority=1, block=True).append_handler(
|
||||
reset_handler(game)
|
||||
)
|
||||
if game.reload_time:
|
||||
scheduler.add_job(
|
||||
scheduled_job(game), trigger="cron", hour=game.reload_time, minute=1
|
||||
)
|
||||
|
||||
|
||||
@pretty_up_reload.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = await reload_pretty_pool()
|
||||
await genshin_reset.finish(Message(f"重载成功!\n{text}"))
|
||||
|
||||
|
||||
@guardian.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
pool_name = "char"
|
||||
if msg.find("1井") != -1 or msg.find("一井") != -1:
|
||||
num = 300
|
||||
if msg.find("武器") != -1:
|
||||
pool_name = "arms"
|
||||
else:
|
||||
rmsg = re.search(r".*?坎公骑冠剑(.*)抽", msg)
|
||||
if rmsg:
|
||||
num = rmsg.group(1)
|
||||
if num.find("武器") != -1:
|
||||
pool_name = "arms"
|
||||
num = num.replace("武器", "")
|
||||
num, flag = check_num(num, 300)
|
||||
if not flag:
|
||||
await guardian.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await guardian.send(await guardian_draw(int(num), pool_name), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 坎公骑冠剑 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@pcr.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
if msg.find("1井") != -1 or msg.find("一井") != -1:
|
||||
num = 300
|
||||
else:
|
||||
rmsg = re.search(r".*?(pcr|公主连结)(.*)[抽|井]", msg)
|
||||
if rmsg:
|
||||
num, flag = check_num(rmsg.group(2), 300)
|
||||
if not flag:
|
||||
await pcr.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await pcr.send(await pcr_draw(int(num)), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 公主连结 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@azur.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
rmsg = re.search(".*?碧蓝航?线?(轻型|重型|特型)池?(.*)[抽]", msg)
|
||||
if rmsg:
|
||||
pool_name = rmsg.group(1)
|
||||
num, flag = check_num(rmsg.group(2), 300)
|
||||
if not flag:
|
||||
await azur.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await azur.send(await azur_draw(int(num), pool_name), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 碧蓝航线 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@fgo.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
rmsg = re.search(".*?fgo(.*)抽", msg)
|
||||
if rmsg:
|
||||
num, flag = check_num(rmsg.group(1), 300)
|
||||
if not flag:
|
||||
await fgo.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await fgo.send(await fgo_draw(int(num)), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) fgo {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@onmyoji.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
rmsg = re.search(".*?阴阳师(.*)抽", msg)
|
||||
if rmsg:
|
||||
num, flag = check_num(rmsg.group(1), 300)
|
||||
if not flag:
|
||||
await onmyoji.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await onmyoji.send(await onmyoji_draw(int(num)), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 阴阳师 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@prts_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_prts_info()
|
||||
await prts_update.finish("更新完成!")
|
||||
|
||||
|
||||
@genshin_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_genshin_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@pretty_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_pretty_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@guardian_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_guardian_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@pcr_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_pcr_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@azur_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_azur_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@fgo_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_fgo_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@onmyoji_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_onmyoji_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
create_matchers()
|
||||
|
||||
|
||||
# 更新资源
|
||||
@@ -420,57 +236,21 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
)
|
||||
async def _():
|
||||
tasks = []
|
||||
if PRTS_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_prts_info()))
|
||||
if GENSHIN_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_genshin_info()))
|
||||
if PRETTY_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_pretty_info()))
|
||||
if GUARDIAN_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_guardian_info()))
|
||||
if PCR_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_pcr_info()))
|
||||
if AZUR_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_azur_info()))
|
||||
if FGO_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_fgo_info()))
|
||||
if ONMYOJI_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_onmyoji_info()))
|
||||
for game in games:
|
||||
if game.flag:
|
||||
tasks.append(asyncio.ensure_future(game.handle.update_info()))
|
||||
await asyncio.gather(*tasks)
|
||||
logger.info("draw_card 抽卡自动更新完成...")
|
||||
|
||||
|
||||
# 每天四点重载方舟up卡池
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=4,
|
||||
minute=1,
|
||||
)
|
||||
driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
if PRTS_FLAG:
|
||||
await reload_prts_pool()
|
||||
logger.info("自动重载方舟卡池UP成功")
|
||||
|
||||
|
||||
# 每天四点重载赛马娘up卡池
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=4,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
if PRETTY_FLAG:
|
||||
await reload_pretty_pool()
|
||||
logger.info("自动重载赛马娘UP成功")
|
||||
|
||||
|
||||
# 每天下午六点点重载原神up卡池
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=18,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
if PRTS_FLAG:
|
||||
await reload_genshin_pool()
|
||||
logger.info("自动重载原神卡池UP成功")
|
||||
tasks = []
|
||||
for game in games:
|
||||
if game.flag:
|
||||
game.handle.init_data()
|
||||
if not game.handle.data_exists():
|
||||
tasks.append(asyncio.ensure_future(game.handle.update_info()))
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
@@ -1,390 +0,0 @@
|
||||
from bs4 import BeautifulSoup
|
||||
from datetime import datetime, timedelta
|
||||
from .config import DRAW_PATH
|
||||
from pathlib import Path
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from services.log import logger
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import re
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
headers = {'User-Agent': '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"'}
|
||||
|
||||
prts_up_char = Path(DRAW_PATH + "/draw_card_up/prts_up_char.json")
|
||||
genshin_up_char = Path(DRAW_PATH + "/draw_card_up/genshin_up_char.json")
|
||||
pretty_up_char = Path(DRAW_PATH + "/draw_card_up/pretty_up_char.json")
|
||||
guardian_up_char = Path(DRAW_PATH + "/draw_card_up/guardian_up_char.json")
|
||||
|
||||
prts_url = "https://ak.hypergryph.com/news.html"
|
||||
genshin_url = "https://wiki.biligame.com/ys/%E7%A5%88%E6%84%BF"
|
||||
pretty_url = "https://wiki.biligame.com/umamusume/%E5%85%AC%E5%91%8A"
|
||||
guardian_url = "https://wiki.biligame.com/gt/%E9%A6%96%E9%A1%B5"
|
||||
|
||||
|
||||
# 是否过时
|
||||
def is_expired(data: dict):
|
||||
try:
|
||||
times = data['time'].split('-')
|
||||
for i in range(len(times)):
|
||||
times[i] = str(datetime.now().year) + '-' + times[i].split('日')[0].strip().replace('月', '-')
|
||||
start_date = datetime.strptime(times[0], '%Y-%m-%d').date()
|
||||
end_date = datetime.strptime(times[1], '%Y-%m-%d').date()
|
||||
now = datetime.now().date()
|
||||
except ValueError:
|
||||
return False
|
||||
return start_date <= now <= end_date
|
||||
|
||||
|
||||
# 检查写入
|
||||
def check_write(data: dict, up_char_file):
|
||||
if not is_expired(data['char']):
|
||||
for x in list(data.keys()):
|
||||
data[x]['title'] = ''
|
||||
else:
|
||||
with open(up_char_file, 'w', encoding='utf8') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
if not up_char_file.exists():
|
||||
with open(up_char_file, 'w', encoding='utf8') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
else:
|
||||
with open(up_char_file, 'r', encoding='utf8') as f:
|
||||
old_data = json.load(f)
|
||||
if is_expired(old_data['char']):
|
||||
return old_data
|
||||
else:
|
||||
with open(up_char_file, 'w', encoding='utf8') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
return data
|
||||
|
||||
|
||||
class PrtsAnnouncement:
|
||||
|
||||
def __init__(self):
|
||||
self.game_name = '明日方舟'
|
||||
|
||||
async def _get_announcement_text(self):
|
||||
text = (await AsyncHttpx.get(prts_url)).text
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
ol = soup.find('ol', {'class': 'articleList active', 'data-category-key': 'LATEST'})
|
||||
for li in ol:
|
||||
itype = li.find('span', {'class': 'articleItemCate'}).text
|
||||
if itype == '活动':
|
||||
a = li.find('a')['href']
|
||||
return (await AsyncHttpx.get(f'https://ak.hypergryph.com{a}')).text
|
||||
|
||||
async def update_up_char(self):
|
||||
prts_up_char.parent.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
data = {'char': {'up_char': {'6': {}, '5': {}, '4': {}}, 'title': '', 'time': '', 'pool_img': ''}}
|
||||
text = await self._get_announcement_text()
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
content = soup.find('div', {'class': 'article-content'})
|
||||
contents = [x for x in content.contents if x.text or str(x).find('img') != -1]
|
||||
start_index = -1
|
||||
end_index = -1
|
||||
for i in range(len(contents)):
|
||||
if str(contents[i]).startswith('<p>'):
|
||||
r = re.search('(.*)(寻访|复刻).*?开启', contents[i].text)
|
||||
if r:
|
||||
if str(contents[i+3].text).find('★') != -1:
|
||||
img = contents[i-1].find('img')
|
||||
if img:
|
||||
data['char']['pool_img'] = img['src']
|
||||
start_index = i
|
||||
for j in range(i, len(contents)):
|
||||
if str(contents[j]).find('注意') != -1:
|
||||
end_index = j
|
||||
break
|
||||
break
|
||||
contents = contents[start_index: end_index]
|
||||
title = contents[0].text
|
||||
data['char']['title'] = title[title.find('【'): title.find('】') + 1]
|
||||
data['char']['time'] = str(contents[1].text).split(':', maxsplit=1)[1]
|
||||
for p in contents[2:]:
|
||||
p = str(p.text)
|
||||
r = None
|
||||
if p.find('★') != -1:
|
||||
if p.find('权值') == -1:
|
||||
r = re.search(r'.*?:(.*)(占(.*)★.*?的(.*)%)', p)
|
||||
else:
|
||||
r = re.search(r'.*?:(.*)(在(.*)★.*?以(.*)倍权值.*?)', p)
|
||||
star = r.group(2)
|
||||
if r:
|
||||
chars = r.group(1)
|
||||
if chars.find('/') != -1:
|
||||
chars = chars.strip().split('/')
|
||||
elif chars.find('\\') != -1:
|
||||
chars = chars.strip().split('\\')
|
||||
else:
|
||||
chars = chars.split('\n')
|
||||
chars = [x.replace('[限定]', '').strip() for x in chars]
|
||||
probability = r.group(3)
|
||||
probability = probability if int(probability) > 10 else f'权{probability}'
|
||||
for char in chars:
|
||||
if char.strip():
|
||||
data['char']['up_char'][star][char.strip()] = probability
|
||||
except TimeoutError:
|
||||
logger.warning(f'更新明日方舟UP池信息超时...')
|
||||
if prts_up_char.exists():
|
||||
with open(prts_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f'更新明日方舟未知错误 e:{e}')
|
||||
if prts_up_char.exists():
|
||||
with open(prts_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
return check_write(data, prts_up_char)
|
||||
|
||||
|
||||
class GenshinAnnouncement:
|
||||
|
||||
def __init__(self):
|
||||
self.game_name = '原神'
|
||||
|
||||
async def _get_announcement_text(self):
|
||||
return (await AsyncHttpx.get(genshin_url)).text
|
||||
|
||||
async def update_up_char(self):
|
||||
genshin_up_char.parent.mkdir(exist_ok=True, parents=True)
|
||||
data = {
|
||||
'char': {'up_char': {'5': {}, '4': {}}, 'title': '', 'time': '', 'pool_img': ''},
|
||||
'arms': {'up_char': {'5': {}, '4': {}}, 'title': '', 'time': '', 'pool_img': ''}
|
||||
}
|
||||
text = await self._get_announcement_text()
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
try:
|
||||
div = soup.find_all('div', {'class': 'row'})[1]
|
||||
tables = div.find_all('table', {'class': 'wikitable'})
|
||||
for table in tables:
|
||||
trs = table.find('tbody').find_all('tr')
|
||||
pool_img = trs[0].find('th').find('img')
|
||||
if pool_img['title'].find('角色活动') == -1:
|
||||
itype = 'arms'
|
||||
else:
|
||||
itype = 'char'
|
||||
try:
|
||||
data[itype]['pool_img'] = str(pool_img['srcset']).split(' ')[0]
|
||||
except KeyError:
|
||||
data[itype]['pool_img'] = pool_img['src']
|
||||
data[itype]['title'] = str(pool_img['title']).split(f'期{"角色" if itype == "char" else "武器"}')[0][:-3]
|
||||
data[itype]['time'] = trs[1].find('td').text
|
||||
if data[itype]['time'][-1] == '\n':
|
||||
data[itype]['time'] = data[itype]['time'][:-1]
|
||||
if '版本更新后' in data[itype]['time']:
|
||||
sp = data[itype]['time'].split('~')
|
||||
end_time = datetime.strptime(sp[1].strip(), "%Y/%m/%d %H:%M:%S")
|
||||
start_time = end_time - timedelta(days=20)
|
||||
data[itype]['time'] = start_time.strftime('%Y/%m/%d') + ' ~ ' + end_time.strftime('%Y/%m/%d')
|
||||
tmp = ''
|
||||
for tm in data[itype]['time'].split('~'):
|
||||
date_time_sp = tm.split('/')
|
||||
date_time_sp[2] = date_time_sp[2].strip().replace(' ', '日 ')
|
||||
tmp += date_time_sp[1] + '月' + date_time_sp[2] + ' - '
|
||||
data[itype]['time'] = tmp[:-2].strip()
|
||||
for a in trs[2].find('td').find_all('a'):
|
||||
char_name = a['title']
|
||||
data[itype]['up_char']['5'][char_name] = "50"
|
||||
for a in trs[3].find('td').find_all('a'):
|
||||
char_name = a['title']
|
||||
data[itype]['up_char']['4'][char_name] = "50"
|
||||
except TimeoutError:
|
||||
logger.warning(f'更新原神UP池信息超时...')
|
||||
if genshin_up_char.exists():
|
||||
with open(genshin_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f'更新原神UP失败,疑似UP池已结束, e:{e}')
|
||||
if genshin_up_char.exists():
|
||||
with open(genshin_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
data['char']['title'] = ''
|
||||
data['arms']['title'] = ''
|
||||
with open(genshin_up_char, 'w', encoding='utf8') as wf:
|
||||
json.dump(data, wf, ensure_ascii=False, indent=4)
|
||||
return data
|
||||
return check_write(data, genshin_up_char)
|
||||
|
||||
|
||||
class PrettyAnnouncement:
|
||||
|
||||
def __init__(self):
|
||||
self.game_name = '赛马娘'
|
||||
|
||||
async def _get_announcement_text(self):
|
||||
text = (await AsyncHttpx.get(pretty_url)).text
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
divs = soup.find('div', {'id': 'mw-content-text'}).find('div').find_all('div')
|
||||
title = " "
|
||||
for div in divs:
|
||||
a = div.find('a')
|
||||
try:
|
||||
title = a['title']
|
||||
except (KeyError, TypeError):
|
||||
continue
|
||||
if title.find('新角色追加') != -1:
|
||||
url = a['href']
|
||||
break
|
||||
return (await AsyncHttpx.get(f'https://wiki.biligame.com/{url}')).text, title[:-2]
|
||||
|
||||
async def update_up_char(self):
|
||||
pretty_up_char.parent.mkdir(exist_ok=True, parents=True)
|
||||
data = {
|
||||
'char': {'up_char': {'3': {}, '2': {}, '1': {}}, 'title': '', 'time': '', 'pool_img': ''},
|
||||
'card': {'up_char': {'3': {}, '2': {}, '1': {}}, 'title': '', 'time': '', 'pool_img': ''}
|
||||
}
|
||||
try:
|
||||
text, title = await self._get_announcement_text()
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
context = soup.find('div', {'class': 'toc-sticky'})
|
||||
if not context:
|
||||
context = soup.find('div', {'class': 'mw-parser-output'})
|
||||
data['char']['title'] = title
|
||||
data['card']['title'] = title
|
||||
r = re.search(r'(\d{1,2}/\d{1,2} \d{1,2}:\d{1,2} ~ \d{1,2}/\d{1,2} \d{1,2}:\d{1,2})', str(context.text))
|
||||
if r:
|
||||
time = str(r.group(1))
|
||||
else:
|
||||
logger.error('赛马娘UP无法找到活动日期....取消更新UP池子...')
|
||||
return check_write(data, pretty_up_char)
|
||||
time = time.replace('~', '-').replace('/', '月').split(' ')
|
||||
time = time[0] + '日 ' + time[1] + ' - ' + time[3] + '日 ' + time[4]
|
||||
data['char']['time'] = time
|
||||
data['card']['time'] = time
|
||||
for p in context.find_all('p'):
|
||||
if str(p).find('当期UP赛马娘') != -1 and str(p).find('■') != -1:
|
||||
if not data['char']['pool_img']:
|
||||
try:
|
||||
data['char']['pool_img'] = p.find('img')['src']
|
||||
except TypeError:
|
||||
for center in context.find_all('center'):
|
||||
try:
|
||||
img = center.find('img')
|
||||
if img and str(img['alt']).find('新马娘') != -1 and str(img['alt']).find('总览') == 1:
|
||||
data['char']['pool_img'] = img['src']
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
r = re.findall(r'.*?当期UP赛马娘([\s\S]*)<奖励内容>.*?', str(p))
|
||||
if r:
|
||||
for x in r:
|
||||
x = str(x).split('\n')
|
||||
for msg in x:
|
||||
if msg.find('★') != -1:
|
||||
msg = msg.replace('<br/>', '')
|
||||
char_name = msg[msg.find('['):].strip()
|
||||
if (star := len(msg[:msg.find('[')].strip())) == 3:
|
||||
data['char']['up_char']['3'][char_name] = '70'
|
||||
elif star == 2:
|
||||
data['char']['up_char']['2'][char_name] = '70'
|
||||
elif star == 1:
|
||||
data['char']['up_char']['1'][char_name] = '70'
|
||||
if str(p).find('(当期UP对象)') != -1 and str(p).find('赛马娘') == -1 and str(p).find('■') != -1:
|
||||
# data['card']['pool_img'] = p.find('img')['src']
|
||||
if not data['char']['pool_img']:
|
||||
try:
|
||||
data['char']['pool_img'] = p.find('img')['src']
|
||||
except TypeError:
|
||||
for center in context.find_all('center'):
|
||||
try:
|
||||
img = center.find('img')
|
||||
if img and str(img['alt']).find('新卡') != -1 and str(img['alt']).find('总览') == 1:
|
||||
data['card']['pool_img'] = img['src']
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
r = re.search(r'■全?新?支援卡(当期UP对象)([\s\S]*)</p>', str(p))
|
||||
if r:
|
||||
rmsg = r.group(1).strip()
|
||||
rmsg = rmsg.split('<br/>')
|
||||
rmsg = [x for x in rmsg if x]
|
||||
for x in rmsg:
|
||||
x = x.replace('\n', '').replace('・', '')
|
||||
star = x[:x.find('[')].strip()
|
||||
char_name = x[x.find('['):].strip()
|
||||
if star == 'SSR':
|
||||
data['card']['up_char']['3'][char_name] = '70'
|
||||
if star == 'SR':
|
||||
data['card']['up_char']['2'][char_name] = '70'
|
||||
if star == 'R':
|
||||
data['card']['up_char']['1'][char_name] = '70'
|
||||
# 日文->中文
|
||||
with open(DRAW_PATH + 'pretty_card.json', 'r', encoding='utf8') as f:
|
||||
all_data = json.load(f)
|
||||
for star in data['card']['up_char'].keys():
|
||||
for name in list(data['card']['up_char'][star].keys()):
|
||||
char_name = name.split(']')[1].strip()
|
||||
tp_name = name[name.find('['): name.find(']') + 1].strip().replace('[', '【').replace(']', '】')
|
||||
for x in all_data.keys():
|
||||
if all_data[x]['名称'].find(tp_name) != -1 and all_data[x]['关联角色'] == char_name:
|
||||
data['card']['up_char'][star].pop(name)
|
||||
data['card']['up_char'][star][all_data[x]['中文名']] = '70'
|
||||
except TimeoutError:
|
||||
logger.warning(f'更新赛马娘UP池信息超时...')
|
||||
if pretty_up_char.exists():
|
||||
with open(pretty_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f'赛马娘up更新未知错误 {type(e)}:{e}')
|
||||
if pretty_up_char.exists():
|
||||
with open(pretty_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
return check_write(data, pretty_up_char)
|
||||
|
||||
|
||||
class GuardianAnnouncement:
|
||||
|
||||
def __init__(self):
|
||||
self.game_name = '坎公骑冠剑'
|
||||
|
||||
async def _get_announcement_text(self):
|
||||
return (await AsyncHttpx.get(guardian_url)).text
|
||||
|
||||
async def update_up_char(self):
|
||||
data = {
|
||||
'char': {'up_char': {'3': {}}, 'title': '', 'time': '', 'pool_img': ''},
|
||||
'arms': {'up_char': {'5': {}}, 'title': '', 'time': '', 'pool_img': ''}
|
||||
}
|
||||
try:
|
||||
text = await self._get_announcement_text()
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
context = soup.select('div.col-sm-3:nth-child(3) > div:nth-child(2) > div:nth-child(1) '
|
||||
'> div:nth-child(2) > div:nth-child(3) > font:nth-child(1)')[0]
|
||||
title = context.find('p').find('b').text
|
||||
tmp = title.split(',')
|
||||
time = ''
|
||||
for msg in tmp:
|
||||
r = re.search(r'[从|至](.*)(开始|结束)', msg)
|
||||
if r:
|
||||
time += r.group(1).strip() + ' - '
|
||||
time = time[:-3]
|
||||
title = time.split(' - ')[0] + 'UP卡池'
|
||||
data['char']['title'] = title
|
||||
data['arms']['title'] = title
|
||||
data['char']['time'] = time
|
||||
data['arms']['time'] = time
|
||||
start_idx = -1
|
||||
end_idx = -1
|
||||
index = 0
|
||||
divs = context.find_all('div')
|
||||
for x in divs:
|
||||
if x.text == '角色':
|
||||
start_idx = index
|
||||
if x.text == '武器':
|
||||
end_idx = index
|
||||
break
|
||||
index += 1
|
||||
for x in divs[start_idx + 1: end_idx]:
|
||||
name = x.find('p').find_all('a')[-1].text
|
||||
data['char']['up_char']['3'][name] = '0'
|
||||
for x in divs[end_idx + 1:]:
|
||||
name = x.find('p').find_all('a')[-1].text
|
||||
data['arms']['up_char']['5'][name] = '0'
|
||||
except TimeoutError:
|
||||
logger.warning(f'更新坎公骑冠剑UP池信息超时...')
|
||||
if guardian_up_char.exists():
|
||||
with open(guardian_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f'坎公骑冠剑up更新未知错误 {type(e)}:{e}')
|
||||
return check_write(data, guardian_up_char)
|
||||
@@ -1,70 +0,0 @@
|
||||
import asyncio
|
||||
import nonebot
|
||||
import os
|
||||
from services.log import logger
|
||||
from .pcr_handle import update_pcr_info, init_pcr_data
|
||||
from .azur_handle import update_azur_info, init_azur_data
|
||||
from .prts_handle import update_prts_info, init_prts_data
|
||||
from .pretty_handle import update_pretty_info, init_pretty_data
|
||||
from .guardian_handle import update_guardian_info, init_guardian_data
|
||||
from .genshin_handle import update_genshin_info, init_genshin_data
|
||||
from .fgo_handle import update_fgo_info, init_fgo_data
|
||||
from .onmyoji_handle import update_onmyoji_info, init_onmyoji_data
|
||||
from .config import DRAW_PATH, PRTS_FLAG, PRETTY_FLAG, GUARDIAN_FLAG, PCR_FLAG, AZUR_FLAG, GENSHIN_FLAG, FGO_FLAG, \
|
||||
ONMYOJI_FLAG
|
||||
|
||||
|
||||
driver: nonebot.Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def async_update_game():
|
||||
tasks = []
|
||||
init_lst = [init_pcr_data, init_pretty_data, init_azur_data, init_prts_data, init_genshin_data, init_guardian_data,
|
||||
init_fgo_data, init_onmyoji_data]
|
||||
if PRTS_FLAG and not os.path.exists(DRAW_PATH + 'prts.json'):
|
||||
tasks.append(asyncio.ensure_future(update_prts_info()))
|
||||
init_lst.remove(init_prts_data)
|
||||
|
||||
if PRETTY_FLAG and (not os.path.exists(DRAW_PATH + 'pretty.json') or
|
||||
not os.path.exists(DRAW_PATH + 'pretty_card.json')):
|
||||
tasks.append(asyncio.ensure_future(update_pretty_info()))
|
||||
init_lst.remove(init_pretty_data)
|
||||
|
||||
if GUARDIAN_FLAG and not os.path.exists(DRAW_PATH + 'guardian.json'):
|
||||
tasks.append(asyncio.ensure_future(update_guardian_info()))
|
||||
|
||||
if PCR_FLAG and not os.path.exists(DRAW_PATH + 'pcr.json'):
|
||||
tasks.append(asyncio.ensure_future(update_pcr_info()))
|
||||
init_lst.remove(init_pcr_data)
|
||||
|
||||
if GENSHIN_FLAG and (not os.path.exists(DRAW_PATH + 'genshin.json') or
|
||||
not os.path.exists(DRAW_PATH + 'genshin_arms.json')):
|
||||
tasks.append(asyncio.ensure_future(update_genshin_info()))
|
||||
init_lst.remove(init_genshin_data)
|
||||
|
||||
if AZUR_FLAG and not os.path.exists(DRAW_PATH + 'azur.json'):
|
||||
tasks.append(asyncio.ensure_future(update_azur_info()))
|
||||
init_lst.remove(init_azur_data)
|
||||
|
||||
if FGO_FLAG and (not os.path.exists(DRAW_PATH + 'fgo.json') or
|
||||
not os.path.exists(DRAW_PATH + 'fgo_card.json')):
|
||||
tasks.append(asyncio.ensure_future(update_fgo_info()))
|
||||
init_lst.remove(init_fgo_data)
|
||||
|
||||
if ONMYOJI_FLAG and not os.path.exists(DRAW_PATH + 'onmyoji.json'):
|
||||
tasks.append(asyncio.ensure_future(update_onmyoji_info()))
|
||||
init_lst.remove(init_onmyoji_data)
|
||||
|
||||
try:
|
||||
await asyncio.gather(*tasks)
|
||||
for func in init_lst:
|
||||
await func()
|
||||
except asyncio.exceptions.CancelledError:
|
||||
logger.info('更新异常:CancelledError,再次更新...')
|
||||
await async_update_game()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
import random
|
||||
from .update_game_simple_info import update_simple_info
|
||||
from .util import generate_img, init_star_rst, BaseData, set_list, get_star, max_card, format_card_information
|
||||
from .config import AZUR_ONE_P, AZUR_TWO_P, AZUR_THREE_P, AZUR_FOUR_P, AZUR_FLAG, DRAW_PATH
|
||||
from dataclasses import dataclass
|
||||
from .init_card_pool import init_game_pool
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
ALL_CHAR = []
|
||||
|
||||
|
||||
@dataclass
|
||||
class AzurChar(BaseData):
|
||||
itype: str # 舰娘类型
|
||||
|
||||
|
||||
async def azur_draw(count: int, pool_name: str):
|
||||
# 0 1 2
|
||||
cnlist = ['金', '紫', '蓝', '白']
|
||||
star_list = [0, 0, 0, 0]
|
||||
char_list, char_dict, max_star_list, star_list, max_star_index_list = \
|
||||
format_card_information(count, star_list, _get_azur_card, pool_name, guaranteed=False)
|
||||
rst = init_star_rst(star_list, cnlist, max_star_list, max_star_index_list)
|
||||
if count > 90:
|
||||
char_list = set_list(char_list)
|
||||
return MessageSegment.image("base64://" + await generate_img(char_list, 'azur', star_list)) \
|
||||
+ '\n' + rst[:-1] + '\n' + max_card(char_dict)
|
||||
|
||||
|
||||
async def update_azur_info():
|
||||
global ALL_CHAR
|
||||
url = 'https://wiki.biligame.com/blhx/舰娘图鉴'
|
||||
data, code = await update_simple_info(url, 'azur')
|
||||
if code == 200:
|
||||
ALL_CHAR = init_game_pool('azur', data, AzurChar)
|
||||
|
||||
|
||||
async def init_azur_data():
|
||||
global ALL_CHAR
|
||||
if AZUR_FLAG:
|
||||
with open(DRAW_PATH + 'azur.json', 'r', encoding='utf8') as f:
|
||||
azur_dict = json.load(f)
|
||||
ALL_CHAR = init_game_pool('azur', azur_dict, AzurChar)
|
||||
|
||||
|
||||
# 抽取卡池
|
||||
def _get_azur_card(pool_name: str):
|
||||
global ALL_CHAR
|
||||
if pool_name == '轻型':
|
||||
itype = ['驱逐', '轻巡', '维修']
|
||||
elif pool_name == '重型':
|
||||
itype = ['重巡', '战列', '战巡', '重炮']
|
||||
else:
|
||||
itype = ['维修', '潜艇', '重巡', '轻航', '航母']
|
||||
star = get_star([4, 3, 2, 1], [AZUR_FOUR_P, AZUR_THREE_P, AZUR_TWO_P, AZUR_ONE_P])
|
||||
chars = [x for x in ALL_CHAR if x.star == star and x.itype in itype and not x.limited]
|
||||
return random.choice(chars), 4 - star
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user