Compare commits

...
53 Commits
Author SHA1 Message Date
HibiKier cb6549c297 Update prts_handle.py 2021-12-16 11:31:15 +08:00
HibiKier 29816ada2a Update README.md 2021-12-16 11:29:12 +08:00
HibiKier dd12bdc028 Update README.md 2021-12-16 11:17:27 +08:00
HibiKier 2a52c0711b Update README.md 2021-12-16 11:17:04 +08:00
HibiKier 2653f67193 update 0.0.7.0 2021-12-16 11:16:28 +08:00
HibiKier b892617824 Update group_user_checkin.py 2021-12-07 12:20:14 +08:00
HibiKier a6fb05c91d Update README.md 2021-12-01 16:25:44 +08:00
HibiKier ccfb9403c8 Update update_info.json 2021-12-01 16:21:58 +08:00
HibiKier 66fa194c7f Update data_source.py 2021-12-01 16:21:29 +08:00
HibiKier 65d8fae9ca Update http_utils.py 2021-12-01 15:20:32 +08:00
HibiKier 58acb14859 Update requirements.txt 2021-12-01 14:53:45 +08:00
HibiKier b63c05a509 Update requirements.txt 2021-12-01 14:17:11 +08:00
HibiKi 2a1a2ee8c5 update 0.0.6.5 2021-12-01 14:03:34 +08:00
HibiKier 8c4b515093 Update update_info.json 2021-12-01 10:53:15 +08:00
HibiKier 6d43989a4d Update update_info.json 2021-12-01 10:52:28 +08:00
HibiKier fb1f15bcb4 Update update_game_simple_info.py 2021-11-29 21:30:06 +08:00
HibiKier 81ad585a18 Update update_game_requests_info.py 2021-11-29 21:29:48 +08:00
HibiKier eb3bd2b4a6 Update update_game_info.py 2021-11-29 21:29:29 +08:00
HibiKier e401914790 Update README.md 2021-11-29 13:11:34 +08:00
HibiKier fef5dadaba Update __version__ 2021-11-29 13:10:43 +08:00
HibiKi c1348d08ed update 0.0.6.4 2021-11-29 13:09:47 +08:00
HibiKier fbd7c568d9 Update pix_update.py 2021-11-24 18:26:52 +08:00
HibiKier 2941774913 Update __init__.py 2021-11-24 18:26:38 +08:00
HibiKier b96d910401 Update __version__ 2021-11-24 14:40:53 +08:00
HibiKier 9275d0782b Update README.md 2021-11-24 14:40:39 +08:00
HibiKier 7acc6cf6af Update data_source.py 2021-11-24 14:33:10 +08:00
HibiKier d380a9aacc Update data_source.py 2021-11-24 14:32:46 +08:00
HibiKier 495377da13 Update README.md 2021-11-24 10:25:00 +08:00
HibiKier 218eed4068 Add files via upload 2021-11-24 10:24:40 +08:00
HibiKier 1e9c99dec1 Delete plugins/search_image directory 2021-11-24 10:07:47 +08:00
HibiKier 0326bc2831 Update __init__.py 2021-11-24 09:56:50 +08:00
HibiKier aed770a761 Update README.md 2021-11-23 21:48:11 +08:00
HibiKi 3de487fb24 update 0.0.6.2 2021-11-23 21:44:59 +08:00
HibiKier c802dfda22 Update README.md 2021-11-19 15:47:10 +08:00
HibiKier 3a4378e4c6 Update __init__.py 2021-11-18 14:41:54 +08:00
HibiKier 955a1f8a7f Update __init__.py 2021-11-18 14:41:13 +08:00
HibiKier ab69e5c477 Create README.md 2021-11-17 11:34:40 +08:00
HibiKier 55e42e8334 Update README.md 2021-11-17 11:33:26 +08:00
HibiKier a0f59bc2c2 Update README.md 2021-11-14 17:27:26 +08:00
HibiKier 66dabd0c8a Update plugins_manager.py 2021-11-14 17:25:45 +08:00
HibiKier 915d585e3a Merge pull request #77 from AkashiCoin/main
修复有免费游戏时不能获取免费游戏的问题
2021-11-13 16:12:49 +08:00
HibiKier 979080d281 Merge branch 'main' into main 2021-11-13 16:12:41 +08:00
HibiKier 335f76c532 Update data_source.py 2021-11-12 16:13:16 +08:00
AkashiCoin b50b934a12 Update data_source.py 2021-11-10 22:26:57 +08:00
AkashiCoin 6a1684d277 Update __init__.py 2021-11-10 22:26:29 +08:00
HibiKier 4926e4d69c Update pix_update.py 2021-11-10 21:33:10 +08:00
HibiKier b29a26551a Update README.md 2021-11-10 21:32:54 +08:00
HibiKier d1c1d93ab7 fix 2021-11-10 21:27:49 +08:00
HibiKier 907df4253c Update __version__ 2021-11-10 20:06:44 +08:00
HibiKier 658152fdc9 Update jitang.py 2021-11-10 16:45:19 +08:00
HibiKier 1a68ede632 Update README.md 2021-11-09 18:05:36 +08:00
HibiKier b70851b810 Update __init__.py 2021-11-09 18:04:33 +08:00
HibiKier 17506691a8 Update __init__.py 2021-11-07 20:45:34 +08:00
326 changed files with 17052 additions and 14342 deletions
+145
View File
@@ -0,0 +1,145 @@
### 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.py
member_activity_handle.py
Yu-Gi-Oh/
+100 -130
View File
@@ -1,4 +1,4 @@
<div align=center><img width="320" height="320" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/zhenxun.jpg"/></div>
<div align=center><img width="320" height="320" src="https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/logo.png"/></div>
![maven](https://img.shields.io/badge/python-3.8%2B-blue)
![maven](https://img.shields.io/badge/nonebot-2.0.0-yellow)
@@ -25,6 +25,10 @@
## 真寻的帮助
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
## 提供符合真寻标准的插件仓库
[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
## 功能列表
<details>
@@ -47,9 +51,11 @@
- [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] B站主播/UP/番剧订阅
@@ -85,6 +91,8 @@
- [x] 通过PID获取图片
- [x] 功能统计可视化
- [x] 关于
### 已实现的管理员功能
- [x] 更新群组成员信息
- [x] 95%的群功能开关
@@ -96,6 +104,8 @@
- [x] 移动图片 (同上)
- [x] 删除图片 (同上)
- [x] 群内B站订阅
- [x] 群词条
- [x] 休息吧/醒来
### 已实现的超级用户功能
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
@@ -121,6 +131,11 @@
- [x] 功能开关(更多设置)
- [x] 功能状态
- [x] b了
- [x] 执行sql
- [x] 重载配置
- [x] 清理临时数据
- [x] 增删群认证
- [x] 同意/拒绝好友/群聊请求
#### 超级用户的被动技能
- [x] 邀请入群提醒(别人邀请真寻入群)
@@ -147,129 +162,10 @@
- [x] 定时更新权限
</details>
## 功能具体指令
<details>
<summary>功能具体指令说明</summary>
### 常用功能
** [*]:表示该参数可有多个 [?]:表示参数可选 **
| 功能 | 指令 | 说明
| ----------------------| :--------------------------------------:| :------------------------:
| 签到 | 签到/我的签到/好感度排行/好感度总榜/好感度总榜\[显示我/屏蔽我] | 普通的签到插件,可以获得好感度和金币<br>好感度影响开箱次数和涩图触发概率,金币用于购买道具,俄罗斯轮盘赌注以及金币红包<br>好感度总榜,显示所有群的群员好感度排行,可通过命令好感度总榜\[显示我/屏蔽我] 来设置是否隐藏
| 发送图片 | 美图/壁纸/萝莉 \[id]?(默认随机)/\[num]张图\[keyword] | 发送指定文件夹下的图片<br>示例:萝莉->发送img文件夹下luoli文件夹下的图片<br>在线搜索一些不色的图,示例:3张图米浴
| 色图 | 色图/色图xx/n张色图/n张xx的色图/查色图(查询本地色图信息)/色图r【n<10】 | 色图r返回10张r18色图(仅私聊),并限制每日次数(默认5次)<br>其他示例:色图 真寻 <br>5张真寻的色图
| 黑白草图 | 黑白草图/黑白图 \[文字] \[图片] | 整活生成器,示例:黑白图 我喜欢真寻 \[图片]
| coser | coser/cos/括丝 | coser图片,说实话挺失望的,太色了
| 骂我 | 骂我 | 就是发送钉宫的语音罢了
| 戳一戳 | 戳一戳 | 随机发送钉宫语音 or 美图 or 萝莉图 or 文本
| 模拟开箱 | 开箱 \[武器箱名称](默认随机)/N连开箱 \[武器箱名称](默认随机)/我的开箱/群开箱统计/我的金色 | 当不指定武器箱时默认随机,此功能需要先在/open_cases/config.py中编写指定武器箱数据,然后提前爬取价格,使用超级用户命令更新cookie后,再使用命令更新xx武器箱【注:未设置爬取频率,可能会被禁用api(请谨慎!!用小号!!)】
| 鲁迅说过 | 鲁迅说过 \[文本] | 示例:鲁迅说过 真寻世界第一可爱
| 假消息 | 假消息 \[网址] \[标题] \[内容]? \[图片]? | 构造虚假的分享消息
| 商店系统 | 商店/我的金币/购买道具 \[名称或序号] \[数量](默认1)/使用道具 \[名称或序号] | 示例:<br>购买道具 1 3<br>购买道具 好感度双倍加持卡Ⅰ 3<br>使用道具 1<br>使用道具 好感度双倍加持卡Ⅰ
| 抽卡系统 | 原神/明日方舟/赛马娘/坎公骑冠剑/碧蓝航线/阴阳师/公主连结(pcr)/FGO N抽/一井 | 详细帮助请查看: [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw) <br>示例:原神90抽
| 我有一个朋友 | 我有一个朋友他说/想问问/\[文本] | 会将文本中的(他,她,它)替换成 '我'<br>示例:我有一个朋友想问问他喜不喜欢真寻
| 昵称系统 | 以后叫我\[昵称]/以后请叫我\[昵称]/我是谁/我叫什么 | 此昵称会替换与真寻聊天中 '你' 的名称(群名片),群与群与私聊的昵称相互独立
| 原神黄历 | 原神黄历 | 查看今日原神黄历,含有每日10:25的定时任务
| 原神材料 | 今日素材 | 发送可莉特调的截图
| 丘丘语翻译 | 丘丘翻译/丘丘一下/丘丘语翻译 | 示例:丘丘一下 mimi
| 原神资源查询 | 原神资源查询 \[资源名称] \[路线]?/\[资源名称]在哪/哪里有\[资源名称]/原神资源列表 | 如果资源名称末尾添加‘路线’的话将生成残缺缺缺版的优先路径<br>示例:嘟嘟莲在哪<br>原神资源查询嘟嘟莲路线
| 俄罗斯轮盘 | 装弹\[子弹数] \[金额](默认200)/开枪/结算/我的战绩/胜场排行/败场排行/欧洲人排行/慈善家排行 | 紧张刺激的群内小游戏,使用每日签到的金币作为赌注,具体玩法请发送 真寻帮助 俄罗斯轮盘
| 红包系统 | 塞红包\[金额] \[数量](默认5)/抢/开/戳一戳/退回 | 仿微信明日方舟红包的样式(pil拼图大师!),每个红包金额随机生成,最多会是红包总金额的1/3,退回用于退回一分钟后还未开完的红包
| 金币排行 | 金币排行 | 字面意思
|网易云热评 | 到点了/12点了/网易云热评/网易云评论 | 防下塔
| 古诗 | 念诗/念首诗/来首诗 | 突然文艺起来了
|微博热搜 | 微博热搜/微博热搜[序号]? | 快捷热搜查询方式
| pil对图片的操作 | 修改尺寸/等比压缩/旋转图片/水平翻转/铅笔滤镜/模糊效果/锐化效果/高斯模糊/边缘检测/底色替换 | 选项较多,请直接发送 真寻图片帮助
| BUFF皮肤底价查询 | 查询皮肤 \[武器名称] \[皮肤名称] | 网络不友好的话会经常超时<br>示例:查询皮肤 沙漠之鹰 印花集
| 天气查询 | \[城市]天气 | 非常常见的插件,第一个入门插件
| 疫情查询 | 疫情/查询疫情 \[城市名或省份名] | 示例:疫情杭州
| bt磁力搜索 | bt \[关键词] \[页数]?(默认第1页) | 该功能仅仅提供给私聊,因为可以搜到一些色色的东西,示例:bt钢铁侠 5
| 上车 | 略 | 直接查看真寻帮助 上车,每日限制次数(默认5)
| 以图识番 | 识番 \[图片] | 以图搜翻,图片越清晰越完整正确率越高
| 以图搜图 | 识图 (asc)? \[图片] | 参数asc更换搜索引擎为ascii2d,默认为saucenao
| 点歌 | 点歌 \[歌名] | 网易云点歌小助手
| 搜番 | 搜番 \[关键字] | 群聊只返回5个结果,私聊返回20个结果
| epic白嫖游戏通知 | epic | 通知你又到了白嫖游戏的时候,可以不玩,不能没有
| P站排行榜 | p站排行 \[排行类型参数]? \[数量]? \[日期]?| 9种不同排行榜,r18类型仅可私聊,通过参数选择,查看真寻帮助p站排行<br>示例:p站排行榜 1 9 2018-4-25
| 搜图 | 搜图 \[关键词] \[数量]? \[排序方式]? \[r18]?| r18仅可私聊,查看真寻帮助搜图
| 通过PID搜索图片 | p搜 [pid] | 在群内使用此功能会在30秒内撤回
| 翻译 | 英翻/日翻/韩翻/翻韩/翻日/翻英 \[文本] | 三种语言互相翻译
| 获取b站视频封面 | b封面 [链接/av/bv/cv/直播id] | 快捷的封面获取方式
| 群欢迎消息 | 群欢迎消息/查看群欢迎消息/查看当前群欢迎消息 | 查看给真寻设置的群欢迎消息
| 自我介绍 | 自我介绍 | 没错,一份正经的真寻自我介绍
| 我的权限 | 我的权限 | 真寻内部定义的一套权限系统
| 我的信息 | 我的信息 | 唯一的作用就是看看什么时候加入群
| 撤回 | 撤回 \[消息位置]?(默认为最新一条消息) | 按顺序撤回发送的消息,示例:撤回 1
| 滴滴滴- | 滴滴滴- \[文本] | 用于用户联系真寻的超级用户
|功能调用统计可视化 | 功能调用统计(自记录以来的功能调用统计)<br>周功能调用统计 [plugin_name]<br>月功能调用统计 [plugin_name]| 当plugin_name为空时为7天或30内的所有功能统计
| pix | pix/PIX [tags/uid/pid:pid] [num] | 无参数时随机查看pix图库的图片(无r18),num数量默认=1,tags:查看相关tags图片,uid:查找相关画师图片,pid:pid:指定查看pid图片<br>示例:pix原神 3<br>pix23493844<br>pixpid:29429933
| 添加pix关键词/uid/pid | 添加pix关键词/uid/pid *[关键词/uid/pid]| 添加关键词或uid或pid用于下次搜索,关键词搜索相关tag,uid会收录作者下收藏符合标准的作品,pid收录单张作品<br>示例:添加pix关键词 原神<br> 添加pixuid 123441<br>添加pixpid 2748937|
| 查看pix图库 | 查看pix图库 [tags] | 查看已收录的tag相关图片数量<br>示例:查看pix图库 原神 莫娜
|显示pix关键词 | 显示pix关键词 | 查看已收录的所有关键词/UID/PID
| b了 | b了 [at] | 使真寻完全忽略一个用户的所有信息
| B站订阅 | 添加订阅 [主播/UP/番剧] [id/链接/番名] / 删除订阅 [id] / 查看订阅 | 可以通过直接间链接或主播间id添加订阅主播开播提醒,动态和投稿,可以通过番名,番剧的id,或者番剧链接添加番剧订阅(是番剧id,md开头,不是集数id,ep开头的)更新, 可以通过UP个人id或UP主页链接订阅UP动态和投稿
### 管理员功能
**群主与群管理员默认5级权限**
| 功能 | 权限等级 | 指令 | 说明
| -------------| --------------| :--------------------------------------:| :------------------------:
| 更新群组成员信息 | 1 | 更新群组成员信息/更新群组成员列表 | 存储群员的基本信息,虽然有自动更新,但备个命令以防万一
| 群功能开关 | 2 | 开启/关闭\[指令名]功能 | 群帮助中左边带有√的功能都可以通过此命令开启或关闭,示例:开启色图
| 查看群被动技能 | 2 | 群通知状态 | 详细请查看被动技能列表
| 被动技能开关 | 2 | 开启/关闭被动技能 | 有时候花里胡哨通知也会很烦人
| 自定义群欢迎消息 | 2 | 自定义群欢迎消息 \[文本] \[图片] | 文本和图片至少需要一个,在文本内添加"\[at]"字符串可以用来设置艾特进群的新群员
| 黑名单 | 5 | .ban/.unban \[at] \[小时]? \[分钟]?| 不提供具体时间的话则ban掉永久,且权限低的用户无法unban高权限用户的ban,同级权限也无法进行ban/unban <br>示例:.ban@笨蛋 1 50
| 刷屏检测相关 | 5 | 刷屏检测设置/设置检测时间 \[文本]/设置检测次数 \[文本]/设置禁言时长 \[分钟]| 非常讨厌刷屏的人,打算给他们一点教训
| 上传图片 | 6 | 上传图片 \[图库] \[图片]... | 上传图片至指定图库,虽然并不打算开放给群员,但还是写了,支持批量图片<br>示例:上传图片 美图 \[图片]..
| 删除图片 | 6 | 删除图片 [图库] \[图片id] | 通过指定本地图片id来删除指定图库的图片<br>示例:删除图片 美图 1
| 移动图片 | 6 | 移动图片 \[移出的图库] \[移入的图库] \[图片id] | 移动指定图库中的图片到指定的新图库中,移入的图片id更改为移入图库的最后一位,移除的图库中原本图片的id又最后一位图片替代<br>示例:移动图片 美图 萝莉 22
|B站订阅 | 5 | 功能同上,就是在群中有权限限制 | 略
### 超级用户功能
| 功能 | 指令 | 说明
| ----------------------| :--------------------------------------:| :------------------------:
| 权限增删 | 添加/删除权限 \[at] \[level]<br>添加/删除权限 [qq] [group] [level] | 用于添加或修改权限等级,且该权限不会被自动更新取消
| 所有群组/好友 | 所有群组/好友 | 查看真寻添加的群组与好友
| 广播 | 广播- [文本] | 广播所有群组
| 更新色图 | 更新色图 | 更新群友搜索色图时保存的url
| 回复 | /t | 命令较多,请查看/t帮助,省略群号则私聊用户(必须要有用户的好友)
| 更新cookie | 更新cookie \[cookie] | 用于更新开箱数据和查询buff皮肤
| 开启广播通知 | 开启/关闭广播通知 \[群号] | 用于开启/关闭是否对某些群进行广播(上边的广播方法)
| 退群 | 退群 \[群号] | 用于退出某一些群
| 检查系统状态 | 自检 | 略
| 更新好友/群组信息| 更新好友/群组信息 | 包含自动更新,被t出群等等有更好的可视信息
| 重载卡池 | 略 | 重载抽卡的游戏卡池,请查看 \[nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw)
| 添加商品 | 添加商品 \[名称]-\[价格]-\[描述]-\[折扣](小数)?-\[限时时间](分钟)? | 为真寻的商店添加一点点道具<br>示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60
| 删除商品 | 删除商品 \[名称或序号] | 在真寻的商店中删除一点东西
| 修改商品 | 修改商品 -name \[名称或序号] -price \[价格] -des \[描述] -discount \[折扣] -time \[限时]| 注意空格,不需要的参数可以不加<br>示例:修改商品 -name 1 -price 900 【修改序号为1的商品的价格为900】
| 节日红包 | 节日红包 \[金额] \[数量] \[祝福语]? \[群号]?... | 群号支持批量,使用空格隔开,不使用群号则对所有群发送节日红包,节日红包有效时间为24小时,祝福语默认为“恭喜发财 大吉大利”<br>示例:节日红包 10000 15 真寻真可爱 123324423 23423423
| 修改群权限 | 修改群权限 \[group] \[level] | 所以说这功能是对内鬼的无奈,默认群权限为5,默认无法使用 色图/coser/p站排行/搜图(这些功能都要9级权限)
|更新原神今日素材| 更新原神今日素材 | 自动更新原神每日素材失败时可以手动触发
|更新原神资源信息| 更新原神资源信息 | 除了每日自动更新的资源外,额外更新大地图
| 清理数据 | 清理数据 | 清理 temp,rar,r18_rar 文件夹的文件数据
|添加pix关键词/uid/pid | 添加pix关键词/uid/pid [keyword/pid:pid/uid:uid] [-f]? | 与普通功能相同,额外可以通过参数 -f 强制通过检测
|删除pix关键词 | 删除pix关键词 *[keyword/uid/pid:pid] | 删除已收录的keyword/uid/pid
|更新pix关键词 | 更新pix关键词 [keyword/pid:pid/uid:uid] [num]?| 更新keyword,uid,pid或指定uid,pid,未指定时,则更新全部,当num未指定时为keyword/uid/pid更新全部<br>示例:更新pix关键词<br>更新pix关键词uid 8<br>更新pix关键词pid:83457477<br>num:倒叙更新数量
|删除pix图片 | 删除pix图片 [*pid] [-b]? | [-b]参数为删除的同时加入黑名单(不再更新),虽然是pid,但是_p也可以<br>示例:删除pix图片3458344 8235234_p1 -b
|显示pix关键词 | 显示pix关键词 | 与普通功能相同,额外显示待收录和黑名单
|pix检测更新 | pix检测更新 [update]? | 检测从未更新过的pid或uid,-update参数将在检测后直接更新未更新过的pid或uid<br>示例:pix检测更新 update
| 检查更新真寻 | 检查更新真寻 | 不再需要麻烦的clone第一步
| 关闭功能 | 关闭[功能] [group/private]/*[群号]? | 关闭色图:维护功能(关闭总开关)<br>关闭色图 g:在群内限制功能<br>关闭色图 p:在私聊限制功能<br>关闭色图 1234678:禁用12345678的色图功能
| 群白名单 | 添加/删除群白名单 *[群号] / 查看群白名单 | 白名单内的群不会受到 维护 限制
| 功能状态 | 功能状态 | 查看功能开关状态
| pix | pix [-s/-r] [keyword] | 可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
| 重载插件配置 |重载插件配置 |用于生效手动修改配文件
|帮助 -super | 帮助[功能] -super | 显示该插件的超级用户帮助
</details>
## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
## 部署
## 简单部署
```
@@ -294,8 +190,7 @@ pip install -r requirements.txt
python bot.py
```
## 配置
在 configs/config.py 中的 USE_CONFIG_FILE,默认为False
## 简单配置
```
1.在.env.dev文件中
@@ -303,12 +198,10 @@ python bot.py
SUPERUSERS = [""] # 填写你的QQ
2.在configs/config.py文件中
必填:
1. API KEY
2.数据库配置
* 数据库配置
在./configs/config.py中配置基本配置(除API KEY ,数据库和代理外都含有默认值)
在./configs/path_config.py配置路径(含有默认配置)
3.在configs/config.yaml文件中 # 该文件需要启动一次后生成
* 修改插件配置项
```
@@ -317,6 +210,83 @@ python bot.py
## 更新
### 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/)
### 2021/12/1 \[v0.0.6.5/6]
* 群权限-1时超级用户命令依旧生效
* 修复以真寻为开头的词条不会被回复
* 修复购买道具可以为负数
* P站排行/搜图提供配置项,将略过大于指定张数的作品
* 昵称提供关键词屏蔽配置项,会将指定关键词替换为“*”
* 取消了自动更新,改为自动检测版本
* 自动更新不再覆盖config.py和移动config.yaml
### 2021/11/29 \[v0.0.6.4]
* 新增cos图撤回配置项
* 新增默认群权限配置项
* 修复权限等级类配置无法正常应用
### 2021/11/24 \[v0.0.6.3]
* 修复在线搜索色图出错
* 修复pix无法正确获取HIBIAPI
### 2021/11/23 \[v0.0.6.2]
* 替换cos API
* 提供私聊b了,即跨群b了用户
* 修复游戏抽卡导入角色失败(原神)
* 修复无Pixiv代理时报错
* 将项目中大部分aiohttp替换为httpx
* 删除了丘丘人翻译插件
* 新增群词条
* 修复游戏抽卡碧蓝航线bwiki格式更改导致获取报错
* 首次启动会生成配置文件后停止程序,配置后再次启动即可
### 2021/11/18
* 修复超级用户无法正确拉真寻入群
### 2021/11/14
* 修复功能总开关无法正确开启
### 2021/11/12
* 修复PIX无法url无法正确获取
### 2021/11/10
* 修复PIX表重复创建导致首次无法运行
* 检测Omage图库改为命令方式:检测omega图库
### 2021/11/9
* 修复管理员帮助无法正常响应
* 修复被ban时会一直回复被ban提醒
### 2021/11/5
* 修复ai没有图灵key时报错
+1 -1
View File
@@ -1 +1 @@
__version__: v0.0.5.1
__version__: v0.0.6.5
Regular → Executable
View File
+1 -1
View File
@@ -4,7 +4,7 @@ import nonebot
Config.add_plugin_config(
"admin_bot_manage:custom_welcome_message",
"SET_GROUP_WELCOME_MESSAGE_LEVEL",
"SET_GROUP_WELCOME_MESSAGE_LEVEL [LEVEL]",
2,
name="群管理员操作",
help_="设置群欢迎消息权限",
View File
View File
+42 -19
View File
@@ -11,9 +11,8 @@ from services.db_context import db
from models.level_user import LevelUser
from configs.config import Config
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
from utils.image_utils import CreateImg
import aiofiles
import aiohttp
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
import asyncio
import time
import os
@@ -73,12 +72,9 @@ async def custom_group_welcome(
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}")
result += msg
if img:
async with aiohttp.ClientSession() as session:
async with session.get(img, proxy=get_local_proxy()) as response:
async with aiofiles.open(
DATA_PATH + f"custom_welcome_msg/{group_id}.jpg", "wb"
) as f:
await f.write(await response.read())
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:
@@ -113,7 +109,16 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
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]
@@ -138,14 +143,14 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
if not group_manager.get_plugin_status(module, group_id):
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
group_manager.block_plugin(module, group_id)
if group_help_file.exists():
group_help_file.unlink()
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
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"
_help_image = Path(DATA_PATH) / "group_help" / f"{group_id}.png"
if _help_image.exists():
_help_image.unlink()
return f"{status} {cmd} 功能!"
@@ -164,8 +169,8 @@ def set_plugin_status(cmd: str, block_type: str = "all"):
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
for file in os.listdir(Path(DATA_PATH) / "group_help"):
file = Path(DATA_PATH) / "group_help" / file
file.unlink()
@@ -201,11 +206,11 @@ def _get_plugin_status() -> MessageSegment:
rst += "\n"
flag_str += f"{flag}\n"
height = len(rst.split("\n")) * 24
a = CreateImg(250, height, font_size=20)
a = BuildImage(250, height, font_size=20)
a.text((10, 10), rst)
b = CreateImg(200, height, font_size=20)
b = BuildImage(200, height, font_size=20)
b.text((10, 10), flag_str)
A = CreateImg(500, height)
A = BuildImage(500, height)
A.paste(a)
A.paste(b, (270, 0))
return image(b64=A.pic2bs4())
@@ -294,3 +299,21 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
)
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 "那我先睡觉了..."
+2 -2
View File
@@ -14,10 +14,10 @@ def switch_rule(bot: Bot, event: Event, state: T_State) -> bool:
: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]}")
+19 -1
View File
@@ -1,4 +1,4 @@
from nonebot import on_command, on_message
from nonebot import on_command, on_message, on_regex
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP
from .data_source import (
@@ -6,12 +6,14 @@ from .data_source import (
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 .rule import switch_rule
import re
__zx_plugin_name__ = "群功能开关 [Admin]"
@@ -24,6 +26,7 @@ usage:
群被动状态
开启全部被动
关闭全部被动
醒来/休息吧
示例:开启/关闭色图
""".strip()
__plugin_superuser_usage__ = """
@@ -40,6 +43,7 @@ __plugin_cmd__ = [
"群被动状态",
"开启全部被动",
"关闭全部被动",
"醒来/休息吧",
"功能状态 [_superuser]",
"开启/关闭[功能] [group] [_superuser]",
"开启/关闭[功能] ['private'/'group'] [_superuser]",
@@ -57,6 +61,8 @@ 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):
@@ -105,3 +111,15 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@group_task_status.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await group_task_status.send(await group_current_status(event.group_id))
@group_status.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
r = re.search("^(休息吧|醒来)$", get_message_text(event.json()))
if r:
if r.group(1) == "休息吧":
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} 使用总开关命令:{r.group(1)}")
View File
View File
View File
+3 -3
View File
@@ -1,4 +1,4 @@
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
@@ -84,8 +84,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)
+58 -2
View File
@@ -5,8 +5,10 @@ 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 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)
# 早上好
@@ -106,6 +134,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}")
# 一次性任务
# 固定时间触发,仅触发一次:
#
Regular → Executable
+15 -5
View File
@@ -3,7 +3,7 @@ from models.ban_user import BanUser
from models.level_user import LevelUser
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent, MessageEvent
from utils.utils import get_message_at, get_message_text, is_number
from configs.config import NICKNAME, Config
from nonebot.permission import SUPERUSER
@@ -24,10 +24,14 @@ usage:
""".strip()
__plugin_superuser_usage__ = """
usage:
屏蔽用户消息,相当于最上级.ban
b了=屏蔽用户消息,相当于最上级.ban
跨群ban以及跨群b了
指令:
b了 [at]
b了 [at/qq]
.ban [user_id] ?[小时] ?[分钟]
示例:b了 @user
示例:b了 1234567
示例:.ban 12345567
""".strip()
__plugin_des__ = '你被逮捕了!丢进小黑屋!'
__plugin_cmd__ = ['.ban [at] ?[小时] ?[分钟]', '.unban [at]', 'b了 [at] [_superuser]']
@@ -182,8 +186,14 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
@super_ban.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
qq = get_message_at(event.json())
async def _(bot: Bot, event: MessageEvent, state: T_State):
if isinstance(event, GroupMessageEvent):
qq = get_message_at(event.json())
else:
qq = get_message_text(event.json())
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)
+8
View File
@@ -7,6 +7,7 @@ from utils.utils import get_message_text, get_message_imgs
from services.log import logger
from utils.message_builder import image
from utils.manager import group_manager
from configs.config import Config
__zx_plugin_name__ = "广播 [Superuser]"
__plugin_usage__ = """
@@ -20,6 +21,13 @@ __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)
+22 -6
View File
@@ -30,15 +30,31 @@ __plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"group_welcome": "进群欢迎", "refund_group_remind": "退群提醒"}
Config.add_plugin_config(
"auto_invite", "message", f"请不要未经同意就拉{NICKNAME}入群!告辞!", help_="强制拉群后进群回复的内容.."
"invite_manager", "message", f"请不要未经同意就拉{NICKNAME}入群!告辞!", help_="强制拉群后进群回复的内容.."
)
Config.add_plugin_config(
"auto_invite", "flag", True, help_="被强制拉群后是否直接退出", default_value=True
"invite_manager", "flag", True, help_="被强制拉群后是否直接退出", default_value=True
)
Config.add_plugin_config(
"auto_invite", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
"invite_manager", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
)
_flmt = FreqLimiter(Config.get_config("auto_invite", "welcome_msg_cd"))
Config.add_plugin_config(
"_task",
"DEFAULT_GROUP_WELCOME",
True,
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"))
# 群员增加处理
@@ -55,10 +71,10 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
group = await GroupInfo.get_group_info(event.group_id)
# 群聊不存在或被强制拉群,退出该群
if (not group or group.group_flag == 0) and Config.get_config(
"auto_invite", "flag"
"invite_manager", "flag"
):
try:
msg = Config.get_config("auto_invite", "message")
msg = Config.get_config("invite_manager", "message")
if msg:
await bot.send_group_msg(group_id=event.group_id, message=msg)
await bot.set_group_leave(group_id=event.group_id)
Regular → Executable
View File
+14 -14
View File
@@ -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,
@@ -50,7 +50,7 @@ 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:
@@ -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,8 +353,8 @@ 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",
Regular → Executable
-2
View File
@@ -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")
Regular → Executable
+40 -15
View File
@@ -13,13 +13,14 @@ from nonebot.adapters.cqhttp import (
Bot,
MessageEvent,
GroupMessageEvent,
PokeNotifyEvent,
PokeNotifyEvent
)
from configs.config import Config
from models.ban_user import BanUser
from utils.utils import FreqLimiter
from utils.message_builder import at
from models.level_user import LevelUser
import nonebot
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
@@ -36,20 +37,44 @@ ignore_rst_module = ["ai", "poke", "dialogue"]
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
module = matcher.module
plugins2info_dict = plugins2settings_manager.get_data()
if (
(not isinstance(event, MessageEvent) and module != "poke")
or await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
) or (
str(event.user_id) in bot.config.superusers
and plugins2info_dict.get(module)
and not plugins2info_dict[module]["limit_superuser"]
):
return
# 群黑名单检测
if isinstance(event, GroupMessageEvent):
if group_manager.get_group_level(event.group_id) < 0:
raise IgnoredException("群黑名单")
try:
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
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.module == "poke":
try:
if group_manager.get_group_level(event.group_id) < 0:
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):
# 个人权限
Regular → Executable
+5 -2
View File
@@ -9,7 +9,7 @@ from nonebot.adapters.cqhttp import (
)
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
@@ -20,6 +20,8 @@ Config.add_plugin_config(
help_="对被ban用户发送的消息",
)
_flmt = FreqLimiter(300)
# 检查是否被ban
@run_preprocessor
@@ -55,7 +57,8 @@ 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):
_flmt.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id,
message=at(event.user_id)
View File
View File
View File
Regular → Executable
View File
View File
+10
View File
@@ -9,10 +9,13 @@ from .init_plugins_limit import (
init_plugins_count_limit,
init_plugins_cd_limit,
)
from .init import init
from .check_plugin_status import check_plugin_status
from utils.manager import admin_manager
from nonebot.adapters.cqhttp import Bot
from configs.path_config import DATA_PATH
from services.log import logger
from pathlib import Path
from nonebot import Driver
import nonebot
@@ -30,6 +33,11 @@ def _():
"""
初始化数据
"""
_flag = False
config_file = Path(DATA_PATH) / "configs" / "plugins2config.yaml"
if not config_file.exists():
_flag = True
init()
init_plugins_settings(DATA_PATH)
init_plugins_cd_limit(DATA_PATH)
init_plugins_block_limit(DATA_PATH)
@@ -42,6 +50,8 @@ def _():
if x:
for key in x.keys():
plugins_manager.block_plugin(key, block_type=x[key])
if _flag:
raise Exception("首次运行,已在configs目录下生成配置文件config.yaml,修改后重启即可...")
logger.info("初始化数据完成...")
View File
+14
View File
@@ -0,0 +1,14 @@
from utils.manager import plugins2settings_manager
def init():
if plugins2settings_manager.get("update_pic"):
plugins2settings_manager["update_picture"] = plugins2settings_manager["update_pic"]
plugins2settings_manager.delete("update_pic")
if plugins2settings_manager.get("white2black_img"):
plugins2settings_manager["white2black_image"] = plugins2settings_manager["white2black_img"]
plugins2settings_manager.delete("white2black_img")
if plugins2settings_manager.get("send_img"):
plugins2settings_manager["send_image"] = plugins2settings_manager["send_img"]
plugins2settings_manager.delete("send_img")
View File
View File
+3
View File
@@ -92,11 +92,14 @@ def init_plugins_config(data_path):
if user_config_file.exists():
with open(user_config_file, "r", encoding="utf8") as f:
_data = _yaml.load(f)
# 数据替换
for plugin in Config.keys():
_tmp_data[plugin] = {}
for k in Config[plugin].keys():
if _data.get(plugin) and k in _data[plugin].keys():
Config.set_config(plugin, k, _data[plugin][k])
if level2module := Config.get_level2module(plugin, k):
admin_manager.set_admin_level(level2module, _data[plugin][k])
_tmp_data[plugin][k] = Config.get_config(plugin, k)
Config.save()
temp_file = Path() / "configs" / "temp_config.yaml"
View File
View File
View File
+12 -16
View File
@@ -17,23 +17,19 @@ def init_plugins_settings(data_path: str):
plugins2settings_file = Path(data_path) / "configs" / "plugins2settings.yaml"
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
_matchers = get_matchers()
_data = {}
if plugins2settings_file.exists():
with open(plugins2settings_file, "r", encoding="utf8") as f:
_data = _yaml.load(f)
_data = _data["PluginSettings"] if _data else {}
_tmp_module = {}
_tmp = []
for x in plugins2settings_manager.keys():
try:
_plugin = nonebot.plugin.get_plugin(x)
_module = _plugin.module
plugin_name = _module.__getattribute__("__zx_plugin_name__")
_tmp_module[x] = plugin_name
except (KeyError, AttributeError) as e:
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
_tmp_module[x] = ""
for matcher in _matchers:
if matcher.module in _data.keys():
plugins2settings_manager.add_plugin_settings(
matcher.module,
plugin_type=_data[matcher.module]["plugin_type"],
data_dict=_data[matcher.module],
)
if _data[matcher.module]["cmd"]:
_tmp_module[matcher.module] = _data[matcher.module]["cmd"][0]
else:
if matcher.module not in plugins2settings_manager.keys():
_plugin = nonebot.plugin.get_plugin(matcher.module)
try:
_module = _plugin.module
@@ -52,7 +48,7 @@ def init_plugins_settings(data_path: str):
except (AttributeError, KeyError):
level = 5
cmd = None
if not level:
if level is None:
level = 5
admin_manager.add_admin_plugin_settings(
matcher.module, cmd, level
@@ -76,7 +72,7 @@ def init_plugins_settings(data_path: str):
"__plugin_settings__"
)
if (
plugin_settings["cmd"]
plugin_settings["cmd"] is not None
and plugin_name not in plugin_settings["cmd"]
):
plugin_settings["cmd"].append(plugin_name)
@@ -25,14 +25,13 @@ __plugin_configs__ = {
friend_req = on_request(priority=5, block=True)
group_req = on_request(priority=5, block=True)
x = on_message(priority=5, block=False)
x = on_message(priority=9, block=False)
exists_data = {"private": {}, "group": {}}
@friend_req.handle()
async def _(bot: Bot, event: FriendRequestEvent, state: dict):
print(event)
global exists_data
if exists_data["private"].get(event.user_id):
if time.time() - exists_data["private"][event.user_id] < 60 * 5:
@@ -47,11 +46,11 @@ async def _(bot: Bot, event: FriendRequestEvent, state: dict):
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份好友申请*****\n"
f"昵称:{nickname}({event.user_id})\n"
f"自动同意:{'√' if Config.get_config('auto_invite', 'AUTO_ADD_FRIEND') else '×'}\n"
f"自动同意:{'√' if Config.get_config('invite_manager', 'AUTO_ADD_FRIEND') else '×'}\n"
f"日期:{str(datetime.now()).split('.')[0]}\n"
f"备注:{event.comment}",
)
if Config.get_config("auto_invite", "AUTO_ADD_FRIEND"):
if Config.get_config("invite_manager", "AUTO_ADD_FRIEND"):
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.add_friend_info(user["user_id"], user["nickname"])
else:
@@ -72,9 +71,6 @@ async def _(bot: Bot, event: GroupRequestEvent, state: dict):
if event.sub_type == "invite":
if str(event.user_id) in bot.config.superusers:
try:
await bot.set_group_add_request(
flag=event.flag, sub_type="invite", approve=True
)
if await GroupInfo.get_group_info(event.group_id):
await GroupInfo.set_group_flag(event.group_id, 1)
else:
@@ -86,6 +82,9 @@ async def _(bot: Bot, event: GroupRequestEvent, state: dict):
group_info["member_count"],
1,
)
await bot.set_group_add_request(
flag=event.flag, sub_type="invite", approve=True
)
except ActionFailed:
pass
else:
Regular → Executable
+51 -44
View File
@@ -8,7 +8,7 @@ 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
__zx_plugin_name__ = "昵称系统"
@@ -23,6 +23,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",
@@ -47,52 +54,52 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
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()
Regular → Executable
+24 -32
View File
@@ -3,12 +3,11 @@ from services.db_context import db
from asyncpg.exceptions import DuplicateColumnError
from models.group_info import GroupInfo
from nonebot.adapters.cqhttp import Bot
from utils.user_agent import get_user_agent
from services.log import logger
from configs.path_config import TEXT_PATH
from asyncio.exceptions import TimeoutError
from utils.http_utils import AsyncHttpx
from pathlib import Path
import aiohttp
import nonebot
try:
@@ -25,30 +24,34 @@ async def update_city():
"""
部分插件需要中国省份城市
这里直接更新,避免插件内代码重复
:return:
"""
china_city = Path(TEXT_PATH) / "china_city.json"
data = {}
try:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
) as res:
provinces_data = json.loads(await res.text(encoding="utf8"))
for province in provinces_data.keys():
data[provinces_data[province]] = []
async with session.get(
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
timeout=5,
) as res:
city_data = json.loads(await res.text(encoding="utf8"))
for city in city_data.keys():
data[provinces_data[province]].append(city_data[city])
res = await AsyncHttpx.get(
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
)
res.encoding = "utf8"
provinces_data = json.loads(res.text)
for province in provinces_data.keys():
data[provinces_data[province]] = []
res = await AsyncHttpx.get(
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
timeout=5,
)
res.encoding = "utf8"
city_data = json.loads(res.text)
for city in city_data.keys():
data[provinces_data[province]].append(city_data[city])
with open(china_city, "w", encoding="utf8") as f:
json.dump(data, f, indent=4, ensure_ascii=False)
logger.info("自动更新城市列表完成.....")
except TimeoutError:
logger.info("自动更新城市列表超时.....")
logger.warning("自动更新城市列表超时.....")
except ValueError:
logger.warning("自动城市列表失败.....")
except Exception as e:
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
@driver.on_startup
@@ -57,7 +60,7 @@ async def _():
数据库表结构变换
"""
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_flag
]
for sql in sql_str:
try:
@@ -75,13 +78,7 @@ async def _(bot: Bot):
# 清空不存在的群聊信息,并将已所有已存在的群聊group_flag设置为1(认证所有已存在的群)
if not await GroupInfo.get_group_info(114514):
# 标识符,该功能只需执行一次
await GroupInfo.add_group_info(
114514,
"114514",
114514,
114514,
1
)
await GroupInfo.add_group_info(114514, "114514", 114514, 114514, 1)
group_list = await bot.get_group_list()
group_list = [g["group_id"] for g in group_list]
_gl = [x.group_id for x in await GroupInfo.get_all_group()]
@@ -98,14 +95,9 @@ async def _(bot: Bot):
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
1,
)
logger.info(f"已将群聊 {group_id} 添加认证...")
else:
await GroupInfo.delete_group_info(group_id)
logger.info(f"移除不存在的群聊信息:{group_id}")
View File
View File
View File
View File
+38
View File
@@ -0,0 +1,38 @@
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 services.db_context import db
from utils.utils import get_message_text
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 _(bot: Bot, event: MessageEvent, state: T_State):
sql = get_message_text(event.json())
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}")
View File
+5 -1
View File
@@ -15,6 +15,10 @@ __zx_plugin_name__ = "重载插件配置 [Superuser]"
__plugin_usage__ = """
usage:
重载插件配置
plugins2settings,
plugins2cd
plugins2block
group_manager
指令:
重载插件配置
""".strip()
@@ -27,7 +31,7 @@ __plugin_author__ = "HibiKier"
reload_plugins_manager = on_command(
"重载插件限制", rule=to_me(), permission=SUPERUSER, priority=1, block=True
"重载配置", rule=to_me(), permission=SUPERUSER, priority=1, block=True
)
+2 -6
View File
@@ -40,7 +40,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
group_id = -1
level = 0
try:
args = get_message_text(event.json()).strip().split()
args = get_message_text(event.json()).split()
qq = get_message_at(event.json())
flag = -1
if not qq:
@@ -55,7 +55,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
else:
await super_cmd.finish(
"权限参数不完全\n\t格式:添加/删除权限 [at] [level]"
"\n\t格式:添加/删除权限 [qq] [group] [level]",
"\n\t格式:添加/删除权限 [qq] [group_id] [level]",
at_sender=True,
)
else:
@@ -63,10 +63,6 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
group_id = event.group_id
flag = 2
if state["_prefix"]["raw_command"][:2] == "添加":
if is_number(args[0]):
level = int(args[0])
else:
await super_cmd.finish("权限等级必须是数字!", at_sender=True)
if await LevelUser.set_level(qq, group_id, level, 1):
result = "添加管理成功, 权限: " + str(level)
else:
View File
View File
View File
+4 -4
View File
@@ -1,4 +1,4 @@
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
@@ -32,7 +32,7 @@ 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:
@@ -72,8 +72,8 @@ def _create_help_image():
)
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)
Regular → Executable
View File
+3 -1
View File
@@ -9,10 +9,12 @@ driver.register_adapter("cqhttp", CQHTTPBot)
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
View File
@@ -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")
+22 -6
View File
@@ -29,7 +29,7 @@ class ConfigsManager:
name: Optional[str] = None,
help_: Optional[str] = None,
default_value: Optional[str] = None,
_override: bool = False
_override: bool = False,
):
"""
为插件添加一个配置,不会被覆盖,只有第一个生效
@@ -61,6 +61,7 @@ class ConfigsManager:
"name": name.strip() if isinstance(name, str) else name,
"help": help_.strip() if isinstance(help_, str) else help_,
"default_value": default_value,
"level_module": _module,
}
def remove_plugin_config(self, module: str):
@@ -104,20 +105,35 @@ class ConfigsManager:
if self._data[module].get(key) is not None:
self._data[module][key]["default_value"] = value
def get_config(self, module: str, key: str) -> Optional[Any]:
def get_config(self, module: str, key: str, default: Optional[Any] = None) -> Optional[Any]:
"""
获取指定配置值
:param module: 模块名
:param key: 配置名称
:param default: 没有key值内容的默认返回值
"""
key = key.upper()
if module in self._data.keys():
if self._data[module].get(key) is not None:
if self._data[module][key]["value"] is None:
return self._data[module][key]["default_value"]
return self._data[module][key]["value"]
for key in [key, f"{key} [LEVEL]"]:
if self._data[module].get(key) is not None:
if self._data[module][key]["value"] is None:
return self._data[module][key]["default_value"]
return self._data[module][key]["value"]
if default is not None:
return default
return None
def get_level2module(self, module: str, key: str) -> Optional[str]:
"""
获取指定key所绑定的module,一般为权限等级
:param module: 模块名
:param key: 配置名称
:return:
"""
if self._data.get(module) is not None:
if self._data[module].get(key) is not None:
return self._data[module][key].get("level_module")
def get(self, key: str):
"""
获取插件配置数据
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 694 KiB

Regular → Executable
View File
Regular → Executable
+1 -1
View File
@@ -82,7 +82,7 @@ class BanUser(db.Model):
参数:
:param user_qq: 目标用户qq号
:param ban_level: 使用ban命令用户的权限
:param duration: ban时长
:param duration: ban时长,秒
"""
query = cls.query.where((cls.user_qq == user_qq))
query = query.with_for_update()
Regular → Executable
+7 -1
View File
@@ -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
Regular → Executable
View File
Regular → Executable
+18 -2
View File
@@ -1,5 +1,5 @@
from datetime import datetime
from configs.config import Config
from services.db_context import db
from typing import List, Optional
@@ -128,6 +128,17 @@ class GroupInfoUser(db.Model):
return True
return False
@classmethod
async def get_user_all_group(cls, user_qq: int) -> List[int]:
"""
获取该用户所在的所有群聊
:param user_qq: 用户qq
"""
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
if query:
query = [x.belonging_group for x in query]
return query
@classmethod
async def get_group_member_nickname(cls, user_qq: int, belonging_group: int) -> str:
"""
@@ -143,7 +154,12 @@ class GroupInfoUser(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
Regular → Executable
View File
Regular → Executable
+29 -1
View File
@@ -1,5 +1,5 @@
from datetime import datetime
from typing import List
from services.db_context import db
@@ -26,6 +26,14 @@ class SignGroupUser(db.Model):
async def ensure(
cls, user_qq: int, belonging_group: int, for_update: bool = False
) -> "SignGroupUser":
"""
说明:
获取签到用户
参数:
:param user_qq: 用户qq
:param belonging_group: 所在群聊
:param for_update: 是否存在修改数据
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
@@ -40,8 +48,28 @@ class SignGroupUser(db.Model):
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,
View File
Regular → Executable
View File
+45
View File
@@ -0,0 +1,45 @@
from nonebot import on_regex
from nonebot.adapters.cqhttp import Bot, MessageEvent
from nonebot.typing import T_State
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 _(bot: Bot, event: MessageEvent, state: T_State):
ver_file = Path() / '__version__'
version = None
if ver_file.exists():
with open(ver_file, 'r', encoding='utf8') as f:
version = f.read().split(':')[-1].strip()
msg = f"""
『绪山真寻Bot』
版本:{version}
简介:基于Nonebot2与go-cqhttp开发,是一个非常可爱的Bot呀,希望与大家要好好相处
项目地址:https://github.com/HibiKier/zhenxun_bot
文档地址:https://hibikier.github.io/zhenxun_bot/
""".strip()
await about.send(msg)
Regular → Executable
View File
Regular → Executable
-2
View File
@@ -24,8 +24,6 @@ __plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["Ai", "ai", "AI", "aI"],
}
__plugin_configs__ = {
Regular → Executable
+64 -65
View File
@@ -1,13 +1,12 @@
import os
import random
import re
import aiohttp
from aiohttp.client import ClientSession
from utils.http_utils import AsyncHttpx
from configs.path_config import IMAGE_PATH, DATA_PATH
from services.log import logger
from utils.message_builder import image, face
from configs.config import Config, NICKNAME
from .utils import ai_message_manager
try:
import ujson as json
@@ -26,7 +25,7 @@ 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:
"""
获取 AI 返回值,顺序:图灵 -> 青云客
获取 AI 返回值,顺序: 特殊回复 -> 图灵 -> 青云客
:param text: 问题
:param img_url: 图片链接
:param user_id: 用户id
@@ -34,6 +33,11 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str)
:return: 回答
"""
global index
ai_message_manager.add_message(user_id, text)
special_rst = await ai_message_manager.get_result(user_id, nickname)
if special_rst:
ai_message_manager.add_result(user_id, special_rst)
return special_rst
if index == 5:
index = 0
if len(text) < 6 and random.random() < 0.6:
@@ -41,10 +45,9 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str)
for key in keys:
if text.find(key) != -1:
return random.choice(anime_data[key]).replace("你", nickname)
async with aiohttp.ClientSession() as sess:
rst = await tu_ling(text, img_url, user_id, sess)
if not rst:
rst = await xie_ai(text, sess)
rst = await tu_ling(text, img_url, user_id)
if not rst:
rst = await xie_ai(text)
if not rst:
return no_result()
if nickname:
@@ -55,23 +58,24 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str)
if nickname.find("大人") == -1:
nickname += "大~人~"
rst = rst.replace("小主人", nickname).replace("小朋友", nickname)
ai_message_manager.add_result(user_id, rst)
return rst
# 图灵接口
async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession) -> str:
async def tu_ling(text: str, img_url: str, user_id: int) -> str:
"""
获取图灵接口的回复
:param text: 问题
:param img_url: 图片链接
:param user_id: 用户id
:param sess: AIOHTTP SESSION
:return: 图灵回复
"""
global index
TL_KEY = Config.get_config("ai", "TL_KEY")
req = None
if not TL_KEY:
return ''
return ""
try:
if text:
req = {
@@ -98,62 +102,59 @@ async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession) ->
index = 0
return ""
text = ""
async with sess.post(url, json=req) as response:
if response.status != 200:
return no_result()
resp_payload = json.loads(await response.text())
if int(resp_payload["intent"]["code"]) in [4003]:
return ""
if resp_payload["results"]:
for result in resp_payload["results"]:
if result["resultType"] == "text":
text = result["values"]["text"]
if "请求次数超过" in text:
text = ""
response = await AsyncHttpx.post(url, json=req)
if response.status_code != 200:
return no_result()
resp_payload = json.loads(response.text)
if int(resp_payload["intent"]["code"]) in [4003]:
return ""
if resp_payload["results"]:
for result in resp_payload["results"]:
if result["resultType"] == "text":
text = result["values"]["text"]
if "请求次数超过" in text:
text = ""
return text
# 屑 AI
async def xie_ai(text: str, sess: ClientSession) -> str:
async def xie_ai(text: str) -> str:
"""
获取青云客回复
:param text: 问题
:param sess: AIOHTTP SESSION
:return: 青云可回复
"""
async with sess.get(
f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}"
) as res:
content = ""
data = json.loads(await res.text())
if data["result"] == 0:
content = data["content"]
if "菲菲" in content:
content = content.replace("菲菲", NICKNAME)
if "艳儿" in content:
content = content.replace("艳儿", NICKNAME)
if "公众号" in content:
content = ""
if "{br}" in content:
content = content.replace("{br}", "\n")
if "提示" in content:
content = content[: content.find("提示")]
if "淘宝" in content:
return ""
while True:
r = re.search("{face:(.*)}", content)
if r:
id_ = r.group(1)
content = content.replace(
"{" + f"face:{id_}" + "}", str(face(int(id_)))
)
else:
break
return (
content
if not content and not Config.get_config("ai", "ALAPI_AI_CHECK")
else await check_text(content, sess)
)
res = await AsyncHttpx.get(f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}")
content = ""
data = json.loads(res.text)
if data["result"] == 0:
content = data["content"]
if "菲菲" in content:
content = content.replace("菲菲", NICKNAME)
if "艳儿" in content:
content = content.replace("艳儿", NICKNAME)
if "公众号" in content:
content = ""
if "{br}" in content:
content = content.replace("{br}", "\n")
if "提示" in content:
content = content[: content.find("提示")]
if "淘宝" in content:
return ""
while True:
r = re.search("{face:(.*)}", content)
if r:
id_ = r.group(1)
content = content.replace(
"{" + f"face:{id_}" + "}", str(face(int(id_)))
)
else:
break
return (
content
if not content and not Config.get_config("ai", "ALAPI_AI_CHECK")
else await check_text(content)
)
def hello() -> str:
@@ -196,21 +197,19 @@ def no_result() -> str:
)
async def check_text(text: str, sess: ClientSession) -> str:
async def check_text(text: str) -> str:
"""
ALAPI文本检测,主要针对青云客API,检测为恶俗文本改为无回复的回答
:param text: 回复
:param sess: AIOHTTP SESSION
"""
if not Config.get_config("alapi", "ALAPI_TOKEN"):
return text
params = {"token": Config.get_config("alapi", "ALAPI_TOKEN"), "text": text}
try:
async with sess.get(check_url, timeout=2, params=params) as response:
data = await response.json()
if data["code"] == 200:
if data["data"]["conclusion_type"] == 2:
return ""
data = (await AsyncHttpx.get(check_url, timeout=2, params=params)).json()
if data["code"] == 200:
if data["data"]["conclusion_type"] == 2:
return ""
except Exception as e:
logger.error(f"检测违规文本错误...{type(e)}:{e}")
return text
+140
View File
@@ -0,0 +1,140 @@
from utils.manager import StaticData
from configs.config import NICKNAME
from models.ban_user import BanUser
from typing import Optional
import random
import time
class AiMessageManager(StaticData):
def __init__(self):
super().__init__(None)
self._same_message = [
"为什么要发一样的话?",
"请不要再重复对我说一句话了,不然我就要生气了!",
"别再发这句话了,我已经知道了...",
"你是只会说这一句话吗?",
"[*],你发我也发!",
"[uname],[*]",
f"救命!有笨蛋一直给{NICKNAME}发一样的话!",
"这句话你已经给我发了{}次了,再发就生气!",
]
self._repeat_message = [
f"请不要学{NICKNAME}说话",
f"为什么要一直学{NICKNAME}说话?",
"你再学!你再学我就生气了!",
f"呜呜,你是想欺负{NICKNAME}嘛..",
"[uname]不要再学我说话了!",
"再学我说话,我就把你拉进黑名单(生气",
"你再学![uname]是个笨蛋!",
"你已经学我说话{}次了!别再学了!",
]
def add_message(self, user_id: int, message: str):
"""
添加用户消息
:param user_id: 用户id
:param message: 消息内容
"""
if message:
if self._data.get(user_id) is None:
self._data[user_id] = {
"time": time.time(),
"message": [],
"result": [],
"repeat_count": 0,
}
if time.time() - self._data[user_id]["time"] > 60 * 10:
self._data[user_id]["message"].clear()
self._data[user_id]["time"] = time.time()
self._data[user_id]["message"].append(message.strip())
def add_result(self, user_id: int, message: str):
"""
添加回复用户的消息
:param user_id: 用户id
:param message: 回复消息内容
"""
if message:
if self._data.get(user_id) is None:
self._data[user_id] = {
"time": time.time(),
"message": [],
"result": [],
"repeat_count": 0,
}
if time.time() - self._data[user_id]["time"] > 60 * 10:
self._data[user_id]["result"].clear()
self._data[user_id]["repeat_count"] = 0
self._data[user_id]["time"] = time.time()
self._data[user_id]["result"].append(message.strip())
async def get_result(self, user_id: int, nickname: str) -> Optional[str]:
"""
特殊消息特殊回复
:param user_id: 用户id
:param nickname: 用户昵称
"""
try:
if len(self._data[user_id]["message"]) < 2:
return None
except KeyError:
return None
msg = await self._get_user_repeat_message_result(user_id)
if not msg:
msg = await self._get_user_same_message_result(user_id)
if msg:
if "[uname]" in msg:
msg = msg.replace("[uname]", nickname)
if not msg.startswith("生气了!你好烦,闭嘴!") and "[*]" in msg:
msg = msg.replace("[*]", self._data[user_id]["message"][-1])
return msg
async def _get_user_same_message_result(self, user_id: int) -> Optional[str]:
"""
重复消息回复
:param user_id: 用户id
"""
msg = self._data[user_id]["message"][-1]
cnt = 0
_tmp = self._data[user_id]["message"][:-1]
_tmp.reverse()
for s in _tmp:
if s == msg:
cnt += 1
else:
break
if cnt > 1:
if random.random() < 0.5 and cnt > 3:
rand = random.randint(60, 300)
await BanUser.ban(user_id, 9, rand)
self._data[user_id]["message"].clear()
return f"生气了!你好烦,闭嘴!给我老实安静{rand}秒"
return random.choice(self._same_message).format(cnt)
return None
async def _get_user_repeat_message_result(self, user_id: int) -> Optional[str]:
"""
复读真寻的消息回复
:param user_id: 用户id
"""
msg = self._data[user_id]["message"][-1]
if self._data[user_id]["result"]:
rst = self._data[user_id]["result"][-1]
else:
return None
if msg == rst:
self._data[user_id]["repeat_count"] += 1
cnt = self._data[user_id]["repeat_count"]
if cnt > 1:
if random.random() < 0.5 and cnt > 3:
rand = random.randint(60, 300)
await BanUser.ban(user_id, 9, rand)
self._data[user_id]["result"].clear()
self._data[user_id]["repeat_count"] = 0
return f"生气了!你好烦,闭嘴!给我老实安静{rand}秒"
return random.choice(self._repeat_message).format(cnt)
return None
ai_message_manager = AiMessageManager()
Regular → Executable
+4 -1
View File
@@ -1,7 +1,6 @@
from configs.config import Config
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")
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
+16 -18
View File
@@ -1,10 +1,10 @@
from nonebot.adapters.cqhttp import MessageSegment
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from typing import Optional
from configs.config import Config
import aiohttp
from utils.http_utils import AsyncHttpx
async def get_data(url: str, params: Optional[dict] = None) -> "Union[dict, str], int":
@@ -16,18 +16,16 @@ async def get_data(url: str, params: Optional[dict] = None) -> "Union[dict, str]
if not params:
params = {}
params["token"] = Config.get_config("alapi", "ALAPI_TOKEN")
async with aiohttp.ClientSession() as session:
try:
async with session.get(url, timeout=2, params=params) as response:
data = await response.json()
if data["code"] == 200:
if not data["data"]:
return "没有搜索到...", 997
return data, 200
else:
return f'发生了错误...code:{data["code"]}', 999
except TimeoutError:
return "超时了....", 998
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:
@@ -35,14 +33,14 @@ 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 = 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 = CreateImg(700, 32 * 50, 700, 32, color="#797979")
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 = CreateImg(700, 30, font_size=20)
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)
+48
View File
@@ -0,0 +1,48 @@
from nonebot import on_command
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
__zx_plugin_name__ = "鸡汤"
__plugin_usage__ = """
usage:
不喝点什么感觉有点不舒服
指令:
鸡汤
""".strip()
__plugin_des__ = "喏,亲手为你煮的鸡汤"
__plugin_cmd__ = ["鸡汤"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["鸡汤", "毒鸡汤"],
}
url = "https://v2.alapi.cn/api/soul"
jitang = on_command("鸡汤", aliases={"毒鸡汤"}, priority=5, block=True)
@jitang.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
try:
data, code = await get_data(url)
if code != 200:
await jitang.finish(data, at_sender=True)
await jitang.send(data["data"]["content"])
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送鸡汤:" + data["data"]["content"]
)
except Exception as e:
await jitang.send("鸡汤煮坏掉了...")
logger.error(f"鸡汤煮坏掉了 {type(e)}:{e}")
Regular → Executable
View File
Regular → Executable
+25 -30
View File
@@ -3,13 +3,13 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State
from services.log import logger
from .data_source import get_data, gen_wbtop_pic
from utils.browser import get_browser
from utils.utils import get_message_text, is_number
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from utils.http_utils import AsyncPlaywright
import asyncio
__zx_plugin_name__ = '微博热搜'
__zx_plugin_name__ = "微博热搜"
__plugin_usage__ = """
usage:
在QQ上吃个瓜
@@ -18,21 +18,21 @@ usage:
微博热搜 [id]:截图该热搜页面
示例:微博热搜 5
""".strip()
__plugin_des__ = '刚买完瓜,在吃瓜现场'
__plugin_cmd__ = ['微博热搜', '微博热搜 [id]']
__plugin_des__ = "刚买完瓜,在吃瓜现场"
__plugin_cmd__ = ["微博热搜", "微博热搜 [id]"]
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ['微博热搜'],
"cmd": ["微博热搜"],
}
wbtop = on_command("wbtop", aliases={'微博热搜'}, priority=5, block=True)
wbtop = on_command("wbtop", aliases={"微博热搜"}, priority=5, block=True)
wbtop_url = 'https://v2.alapi.cn/api/new/wbtop'
wbtop_url = "https://v2.alapi.cn/api/new/wbtop"
wbtop_data = []
@@ -45,32 +45,27 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
data, code = await get_data(wbtop_url)
if code != 200:
await wbtop.finish(data, at_sender=True)
wbtop_data = data['data']
wbtop_data = data["data"]
if not msg:
img = await asyncio.get_event_loop().run_in_executor(None, gen_wbtop_pic, wbtop_data)
img = await asyncio.get_event_loop().run_in_executor(
None, gen_wbtop_pic, wbtop_data
)
await wbtop.send(img)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询微博热搜")
f" 查询微博热搜"
)
if is_number(msg) and 0 < int(msg) <= 50:
url = wbtop_data[int(msg) - 1]['url']
browser = await get_browser()
page = None
url = wbtop_data[int(msg) - 1]["url"]
try:
if not browser:
logger.warning('获取 browser 失败,请部署至 linux 环境....')
await wbtop.finish('获取 browser 对象失败...')
page = await browser.new_page()
await page.goto(url, wait_until='networkidle', timeout=10000)
await page.set_viewport_size({"width": 2560, "height": 1080})
await asyncio.sleep(5)
div = await page.query_selector("#pl_feedlist_index")
await div.screenshot(path=f'{IMAGE_PATH}/temp/wbtop_{event.user_id}.png', timeout=100000)
await page.close()
await wbtop.send(image(f'wbtop_{event.user_id}.png', 'temp'))
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)
except Exception as e:
logger.error(f'微博热搜截图出错... {type(e)}: {e}')
if page:
await page.close()
await wbtop.send('发生了一些错误.....')
logger.error(f"微博热搜截图出错... {type(e)}: {e}")
await wbtop.send("发生了一些错误.....")
Regular → Executable
+1
View File
@@ -206,6 +206,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}")
rst = await get_sub_status(sub.sub_id, sub.sub_type)
await send_sub_msg(rst, sub, bot)
if sub.sub_type == "live":
+23 -26
View File
@@ -14,7 +14,7 @@ from datetime import datetime
from utils.browser import get_browser
from services.db_context import db
from services.log import logger
import aiohttp
from utils.http_utils import AsyncHttpx
import random
@@ -150,7 +150,7 @@ async def delete_sub(sub_id: str, sub_user: str) -> str:
:param sub_id: 订阅 id
:param sub_user: 订阅用户 id # 7384933:private or 7384933:2342344(group)
"""
if await BilibiliSub.delete_bilibili_sub(sub_id, sub_user):
if await BilibiliSub.delete_bilibili_sub(int(sub_id), sub_user):
return f"已成功取消订阅:{sub_id}"
else:
return f"取消订阅:{sub_id} 失败,请检查是否订阅过该Id...."
@@ -162,30 +162,27 @@ async def get_media_id(keyword: str) -> dict:
:param keyword: 番剧名称
"""
params = {"keyword": keyword}
async with aiohttp.ClientSession() as session:
for _ in range(3):
try:
_season_data = {}
async with session.get(
bilibili_search_url, timeout=5, params=params
) as response:
if response.status == 200:
data = await response.json()
if data.get("data"):
for item in data["data"]["result"]:
if item["result_type"] == "media_bangumi":
idx = 0
for x in item["data"]:
_season_data[idx] = {
"media_id": x["media_id"],
"title": x["title"]
.replace('<em class="keyword">', "")
.replace("</em>", ""),
}
idx += 1
return _season_data
except TimeoutError:
pass
for _ in range(3):
try:
_season_data = {}
response = await AsyncHttpx.get(bilibili_search_url, params=params, timeout=5)
if response.status_code == 200:
data = response.json()
if data.get("data"):
for item in data["data"]["result"]:
if item["result_type"] == "media_bangumi":
idx = 0
for x in item["data"]:
_season_data[idx] = {
"media_id": x["media_id"],
"title": x["title"]
.replace('<em class="keyword">', "")
.replace("</em>", ""),
}
idx += 1
return _season_data
except TimeoutError:
pass
return {}
Regular → Executable
View File
Regular → Executable
+24 -25
View File
@@ -1,12 +1,12 @@
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
import aiohttp
BORDER_PATH = Path(IMAGE_PATH) / 'border'
BORDER_PATH = Path(IMAGE_PATH) / "border"
BORDER_PATH.mkdir(parents=True, exist_ok=True)
@@ -16,9 +16,7 @@ async def get_pic(url: str) -> bytes:
:param url: 图像链接
:return: 图像二进制
"""
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=2) as response:
return await response.read()
return (await AsyncHttpx.get(url, timeout=10)).content
async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des: str):
@@ -33,17 +31,26 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
"""
u = user.User(uid)
user_info = await u.get_user_info()
name = user_info['name']
sex = user_info['sex']
face = user_info['face']
sign = user_info['sign']
ava = CreateImg(100, 100, background=BytesIO(await get_pic(face)))
name = user_info["name"]
sex = user_info["sex"]
face = user_info["face"]
sign = user_info["sign"]
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, tags: str, des: str, user_name: str, sex: str, sign: str, ava: CreateImg):
def _create_live_des_image(
title: str,
cover: BuildImage,
tags: str,
des: str,
user_name: str,
sex: str,
sign: str,
ava: BuildImage,
):
"""
生成主播简介图片
:param title: 直播间标题
@@ -56,17 +63,9 @@ def _create_live_des_image(title: str, cover: CreateImg, tags: str, des: str, us
:param ava: 主播头像
:return:
"""
border = BORDER_PATH / '0.png'
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)
bk.paste(cover, (0, 100), center_type='by_width')
border_img = BuildImage(1772, 2657, background=border)
bk = BuildImage(1772, 2657, font_size=30)
bk.paste(cover, (0, 100), center_type="by_width")
Regular → Executable
+1 -4
View File
@@ -7,7 +7,6 @@ from nonebot.adapters.cqhttp import PrivateMessageEvent
from utils.utils import get_message_text
from nonebot.adapters.cqhttp.permission import PRIVATE
from asyncio.exceptions import TimeoutError
from aiohttp.client_exceptions import ServerDisconnectedError
__zx_plugin_name__ = "磁力搜索"
__plugin_usage__ = """
@@ -89,11 +88,9 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
send_flag = True
except TimeoutError:
await bt.finish(f"搜索 {keyword} 超时...")
except ServerDisconnectedError:
await bt.finish(f"搜索 {keyword} 连接失败")
except Exception as e:
await bt.finish(f"bt 其他未知错误..")
logger.error(f"bt 错误 e:{e}")
logger.error(f"bt 错误 {type(e)}:{e}")
if not send_flag:
await bt.send(f"{keyword} 未搜索到...")
logger.info(f"USER {event.user_id} BT搜索 {keyword} 第 {page} 页")
Regular → Executable
+35 -34
View File
@@ -1,8 +1,6 @@
from utils.user_agent import get_user_agent
import aiohttp
from utils.http_utils import AsyncHttpx
from configs.config import Config
from bs4 import BeautifulSoup
from utils.utils import get_local_proxy
import platform
if platform.system() == "Windows":
@@ -15,36 +13,39 @@ url = "http://www.eclzz.world"
async def get_bt_info(keyword: str, page: str):
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
f"{url}/s/{keyword}_rel_{page}.html", proxy=get_local_proxy(), timeout=5
) as response:
text = await response.text()
if text.find("大约0条结果") != -1:
return
soup = BeautifulSoup(text, "lxml")
item_lst = soup.find_all("div", {"class": "search-item"})
bt_max_num = Config.get_config("bt", "BT_MAX_NUM")
bt_max_num = bt_max_num if bt_max_num < len(item_lst) else len(item_lst)
for item in item_lst[:bt_max_num]:
divs = item.find_all("div")
title = (
str(divs[0].find("a").text)
.replace("<em>", "")
.replace("</em>", "")
.strip()
)
spans = divs[2].find_all("span")
itype = 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"], session)
yield title, itype, create_time, file_size, link
"""
获取资源信息
:param keyword: 关键词
:param page: 页数
"""
text = (await AsyncHttpx.get(f"{url}/s/{keyword}_rel_{page}.html", timeout=5)).text
if text.find("大约0条结果") != -1:
return
soup = BeautifulSoup(text, "lxml")
item_lst = soup.find_all("div", {"class": "search-item"})
bt_max_num = Config.get_config("bt", "BT_MAX_NUM")
bt_max_num = bt_max_num if bt_max_num < len(item_lst) else len(item_lst)
for item in item_lst[:bt_max_num]:
divs = item.find_all("div")
title = (
str(divs[0].find("a").text)
.replace("<em>", "")
.replace("</em>", "")
.strip()
)
spans = divs[2].find_all("span")
itype = 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
async def get_download_link(_url: str, session) -> str:
async with session.get(
f"{url}{_url}", proxy=get_local_proxy(), timeout=30
) as response:
soup = BeautifulSoup(await response.text(), "lxml")
return soup.find("a", {"id": "down-url"})["href"]
async def get_download_link(_url: str) -> str:
"""
获取资源下载地址
:param _url: 链接
"""
text = (await AsyncHttpx.get(f"{url}{_url}")).text
soup = BeautifulSoup(text, "lxml")
return soup.find("a", {"id": "down-url"})["href"]
Regular → Executable
+6 -6
View File
@@ -25,22 +25,22 @@ __plugin_settings__ = {
}
songpicker = on_command("点歌", priority=5, block=True)
music = on_command("点歌", priority=5, block=True)
@songpicker.handle()
@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
@songpicker.got("song_name", prompt="歌名是?")
@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 songpicker.finish("没有找到这首歌!", at_sender=True)
await music.finish("没有找到这首歌!", at_sender=True)
for _ in range(3):
song_content = [{"type": "music", "data": {"type": 163, "id": song_id}}]
logger.info(
@@ -48,9 +48,9 @@ async def _(bot: Bot, event: Event, state: T_State):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 点歌 :{song}"
)
await songpicker.finish(song_content)
await music.finish(song_content)
else:
await songpicker.finish("网易云繁忙...")
await music.finish("网易云繁忙...")
Regular → Executable
+25 -31
View File
@@ -1,4 +1,4 @@
import aiohttp
from utils.http_utils import AsyncHttpx
import json
@@ -7,41 +7,35 @@ cookies = {"appver": "2.0.2"}
async def search_song(song_name: str):
async with aiohttp.ClientSession(
headers=headers, cookies=cookies
) as session:
async with session.post(
f"http://music.163.com/api/search/get/",
data={"s": song_name, "limit": 1, "type": 1, "offset": 0},
) as r:
if r.status != 200:
return None
r = await r.text()
return json.loads(r)
"""
搜索歌曲
:param song_name: 歌名
"""
r = await AsyncHttpx.post(
f"http://music.163.com/api/search/get/",
data={"s": song_name, "limit": 1, "type": 1, "offset": 0},
)
if r.status_code != 200:
return None
return json.loads(r.text)
async def get_song_id(songName: str) -> int:
"""
根据用户输入的songName 获取候选songId列表 [默认songId数量:5]
"""
r = await search_song(songName)
return r["result"]["songs"][0]["id"]
async def get_song_id(song_name: str) -> int:
""" """
r = await search_song(song_name)
try:
return r["result"]["songs"][0]["id"]
except KeyError:
return 0
async def get_song_info(songId: int):
"""
获取歌曲信息
"""
async with aiohttp.ClientSession(
headers=headers, cookies=cookies
) as session:
async with session.post(
f"http://music.163.com/api/song/detail/?id={songId}&ids=%5B{songId}%5D",
) as r:
if r.status != 200:
return None
r = await r.text()
return json.loads(r)
r = await AsyncHttpx.post(
f"http://music.163.com/api/song/detail/?id={songId}&ids=%5B{songId}%5D",
)
if r.status_code != 200:
return None
return json.loads(r.text)
Regular → Executable
View File
Regular → Executable
+15 -26
View File
@@ -1,12 +1,8 @@
import psutil
import aiohttp
import time
from datetime import datetime
from utils.user_agent import get_user_agent
from asyncio.exceptions import TimeoutError
from aiohttp.client_exceptions import ClientConnectorError
from utils.utils import get_local_proxy
from utils.image_utils import CreateImg
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH
from pathlib import Path
import asyncio
@@ -34,23 +30,16 @@ class Check:
self.disk = psutil.disk_usage("/").percent
async def check_network(self):
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
try:
async with session.get(
"https://www.baidu.com/", proxy=get_local_proxy(), timeout=3
) as response:
pass
except (TimeoutError, ClientConnectorError) as e:
logger.warning(f"访问BaiDu失败... e: {e}")
self.baidu = 404
try:
async with session.get(
"https://www.google.com/", proxy=get_local_proxy(), timeout=3
) as response:
pass
except (TimeoutError, ClientConnectorError) as e:
logger.warning(f"访问Google失败... e: {e}")
self.google = 404
try:
await AsyncHttpx.get("https://www.baidu.com/", timeout=5)
except Exception as e:
logger.warning(f"访问BaiDu失败... {type(e)}: {e}")
self.baidu = 404
try:
await AsyncHttpx.get("https://www.google.com/", timeout=5)
except Exception as e:
logger.warning(f"访问Google失败... {type(e)}: {e}")
self.google = 404
def check_user(self):
rst = ""
@@ -60,7 +49,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"
@@ -80,10 +69,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=Path(IMAGE_PATH) / "background" / "check" / "0.jpg")
bk.paste(A, alpha=True, center_type='center')
return bk.pic2bs4()
+14 -14
View File
@@ -110,17 +110,17 @@ async def _():
f"当前版本:{_version},最新版本:{latest_version}\n"
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"更新完毕,请重启真寻....",
)
# 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"更新完毕,请重启真寻....",
# )
+50 -66
View File
@@ -1,18 +1,14 @@
from aiohttp.client_exceptions import ClientConnectorError
from nonebot.adapters.cqhttp import Bot, Message
from utils.user_agent import get_user_agent
from utils.utils import get_local_proxy
from utils.image_utils import CreateImg
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
from typing import List
from services.log import logger
from pathlib import Path
import ujson as json
import nonebot
import asyncio
import aiofiles
import aiohttp
import platform
import tarfile
import shutil
@@ -77,7 +73,7 @@ async def check_update(bot: Bot) -> 'int, str':
message=f"检测真寻已更新,当前版本:{_version},最新版本:{latest_version}\n" f"开始更新.....",
)
logger.info(f"开始下载真寻最新版文件....")
if await download_latest_file(tar_gz_url):
if await AsyncHttpx.download_file(tar_gz_url, zhenxun_latest_tar_gz):
logger.info("下载真寻最新版文件完成....")
error = await asyncio.get_event_loop().run_in_executor(
None, _file_handle, latest_version
@@ -89,12 +85,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(
@@ -132,21 +128,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():
@@ -161,23 +168,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():
@@ -194,38 +193,23 @@ def _file_handle(latest_version: str) -> str:
# 获取最新版本号
async def get_latest_version_data() -> dict:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
for _ in range(3):
try:
async with session.get(release_url, proxy=get_local_proxy()) as res:
if res.status == 200:
return await res.json()
except (TimeoutError, ClientConnectorError):
pass
for _ in range(3):
try:
res = await AsyncHttpx.get(release_url)
if res.status_code == 200:
return res.json()
except TimeoutError:
pass
except Exception as e:
logger.error(f"检查更新真寻获取版本失败 {type(e)}:{e}")
return {}
# 下载文件
async def download_latest_file(url_: str) -> bool:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
for _ in range(3):
try:
async with session.get(url_, proxy=get_local_proxy()) as res:
if res.status == 200:
async with aiofiles.open(zhenxun_latest_tar_gz, "wb") as f:
await f.write(await res.read())
return True
except (TimeoutError, ClientConnectorError):
pass
return False
# 逐行检测
def check_old_lines(lines: List[str], line: str) -> str:
if "=" not in line:
return line
for l in lines:
if "=" in l and l.split("=")[0].strip() == line.split("=")[0].strip():
if l.split("=")[1].strip() == 'None':
return l
return l
return line
Regular → Executable
+22 -38
View File
@@ -1,13 +1,10 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from services.log import logger
from asyncio.exceptions import TimeoutError
from nonebot.adapters.cqhttp import Bot, MessageEvent
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from utils.utils import get_local_proxy
import aiohttp
import aiofiles
from services.log import logger
from utils.manager import withdraw_message_manager
from configs.config import Config
__zx_plugin_name__ = "coser"
__plugin_usage__ = """
@@ -26,44 +23,31 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["cos", "coser", "括丝", "COS", "Cos", "cOS", "coS"],
}
__plugin_configs__ = {
"WITHDRAW_COS_MESSAGE": {
"value": (0, 1),
"help": "自动撤回,参1:延迟撤回色图时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)",
"default_value": (0, 1),
},
}
coser = on_command(
"cos", aliases={"coser", "括丝", "COS", "Cos", "cOS", "coS"}, priority=5, block=True
)
url = "http://ovooa.com/API/cosplay/api.php"
url = "http://iw233.cn/API/cos.php"
@coser.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
async with aiohttp.ClientSession() as session:
try:
for _ in range(3):
try:
async with session.get(url, proxy=get_local_proxy(), timeout=2, verify_ssl=False) as response:
_url = (await response.json())['text']
async with session.get(
_url, timeout=5, proxy=get_local_proxy(), verify_ssl=False
) as res:
if res.status == 200:
async with aiofiles.open(
f"{IMAGE_PATH}/temp/{event.user_id}_coser.jpg", "wb"
) as f:
await f.write(await res.read())
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送COSER"
)
await coser.send(
image(f"{event.user_id}_coser.jpg", "temp")
)
break
except (TimeoutError, KeyError):
pass
else:
await coser.send("你cos给我看!")
except Exception as e:
await coser.send("发生了预料之外的错误..请稍后再试或联系管理员修复...")
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
try:
msg_id = await coser.send(image(url))
withdraw_message_manager.withdraw_message(
event,
msg_id["message_id"],
Config.get_config("coser", "WITHDRAW_COS_MESSAGE"),
)
except Exception as e:
await coser.send("你cos给我看!")
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
-69
View File
@@ -1,69 +0,0 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
from utils.utils import get_message_text, is_number
from .data_source import get_csgola_data, get_5e_data
from services.log import logger
__zx_plugin_name__ = "cs国服/平台信息查找"
__plugin_usage__ = """
usage:
快速查询csgo战绩和数据
指令:
cs国服查询 [steam主页个人id]
5e查询 [5e战绩个人名称]
示例:cs国服查询 23848238483
示例:5e查询 poster
"""
__plugin_des__ = "什么?你也是rush B玩家?"
__plugin_cmd__ = ["cs国服查询 [steam主页个人id]", "5e查询 [5e战绩个人名称]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["csgo战绩查询", "cs国服查询", "5e查询"],
}
csgola = on_command("cs国服查询", priority=5, block=True)
csgo5e = on_command("5e查询", priority=5, block=True)
@csgola.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if "http" in msg:
msg = msg[:-1] if msg[-1] == "/" else msg
msg = msg.split("/")[-1]
if not is_number(msg):
await csgola.finish("Id必须为数字!", at_sender=True)
await csgola.send("开始查找...")
img, code = await get_csgola_data(int(msg))
if code == 200:
await csgola.send(img, at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询csgo国服战绩:{msg}"
)
else:
await csgola.send(img, at_sender=True)
@csgo5e.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
await csgola.send("开始查找...")
img, code = await get_5e_data(msg)
if code == 200:
await csgo5e.send(img, at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询csgo国服战绩:{msg}"
)
else:
await csgo5e.send(img, at_sender=True)
-130
View File
@@ -1,130 +0,0 @@
from configs.path_config import IMAGE_PATH
from utils.image_utils import CreateImg
from utils.message_builder import image
from services.log import logger
from utils.browser import get_browser
from playwright._impl._api_types import TimeoutError
csgola_url = "https://www.csgola.com/player/"
_5e_url = "https://arena.5eplay.com/data/player/"
async def get_csgola_data(uid: int) -> "str, int":
page = None
try:
browser = await get_browser()
if not browser:
return "", 997
page = await browser.new_page()
for _ in range(3):
try:
await page.goto(f"{csgola_url}{uid}", wait_until="networkidle", timeout=10000)
break
except TimeoutError:
pass
else:
return '连接超时...', 995
await page.set_viewport_size({"width": 2560, "height": 1080})
data = await page.query_selector_all(".panel-body")
if not data:
return "未查询到该Id....", 999
await data[0].screenshot(path=f"{IMAGE_PATH}/temp/{uid}_1.png", timeout=100000)
await data[3].screenshot(path=f"{IMAGE_PATH}/temp/{uid}_2.png", timeout=100000)
await data[5].screenshot(path=f"{IMAGE_PATH}/temp/{uid}_3.png", timeout=100000)
await data[7].screenshot(path=f"{IMAGE_PATH}/temp/{uid}_5.png", timeout=100000)
ava = await page.query_selector("div.container:nth-child(4) > div:nth-child(1)")
await ava.screenshot(path=f"{IMAGE_PATH}/temp/{uid}_0.png", timeout=100000)
weapon_data = await page.query_selector(".gun-stats-sec")
await weapon_data.screenshot(
path=f"{IMAGE_PATH}/temp/{uid}_4.png", timeout=100000
)
ava = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_0.png")
statistical_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_1.png")
combined_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_2.png")
detailed_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_3.png")
weapon_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_4.png")
map_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_5.png")
if statistical_data.h > 300:
statistical_data.crop((0, 0, statistical_data.w, 300))
if combined_data.h > 260:
combined_data.crop((0, 0, combined_data.w, 260))
if detailed_data.h > 400:
detailed_data.crop((0, 0, detailed_data.w, 400))
weapon_data.crop((0, 100, weapon_data.w, weapon_data.h))
map_data.crop((0, 310, map_data.w, map_data.h))
height = (
ava.h
+ statistical_data.h
+ combined_data.h
+ detailed_data.h
+ weapon_data.h
+ map_data.h
)
bk = CreateImg(1168, height)
current_h = 0
for img in [
ava,
statistical_data,
combined_data,
detailed_data,
weapon_data,
map_data,
]:
bk.paste(img, (0, current_h))
current_h += img.h
bk.save(f"{IMAGE_PATH}/temp/csgo_{uid}.png")
except Exception as e:
logger.error(f"生成csgola图片错误 {type(e)}:{e}")
if page:
await page.close()
return "发生了错误....", 998
if page:
await page.close()
return image(f"csgo_{uid}.png", "temp"), 200
async def get_5e_data(uname: str) -> "str, int":
page = None
try:
browser = await get_browser()
if not browser:
return "", 997
page = await browser.new_page()
await page.goto(f"{_5e_url}{uname}", wait_until="networkidle", timeout=10000)
if "HTTP ERROR 404" in await page.content():
return "未查询到该玩家...", 999
await page.set_viewport_size({"width": 2560, "height": 1080})
body = await page.query_selector("body")
await body.screenshot(
path=f"{IMAGE_PATH}/temp/csgo_{uname}_0.png", timeout=100000
)
await page.click("a.match-tab-item:nth-child(2)")
body = await page.query_selector("body")
await body.screenshot(
path=f"{IMAGE_PATH}/temp/csgo_{uname}_1.png", timeout=100000
)
await page.click("a.match-tab-item:nth-child(1)")
body = await page.query_selector("body")
await body.screenshot(
path=f"{IMAGE_PATH}/temp/csgo_{uname}_2.png", timeout=100000
)
bk = CreateImg(1344 * 3, 2307)
current_w = 0
for i in range(3):
body = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/csgo_{uname}_{i}.png")
body.crop((600, 90, body.w - 600, body.h - 410))
bk.paste(body, (current_w, 0))
current_w += 1344
bk.save(f"{IMAGE_PATH}/temp/csgo_{uname}.png")
except Exception as e:
logger.error(f"生成5e图片错误 {type(e)}:{e}")
if page:
await page.close()
return "发生了错误...", 998
if page:
await page.close()
return image(f"csgo_{uname}.png", "temp"), 200
Regular → Executable
+1 -1
View File
@@ -65,7 +65,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
img_msg = _text("")
for img in get_message_imgs(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
Regular → Executable
View File
+26 -33
View File
@@ -1,11 +1,11 @@
import aiohttp
from bs4 import BeautifulSoup
import re
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:
@@ -66,16 +66,14 @@ class PrtsAnnouncement:
self.game_name = '明日方舟'
async def _get_announcement_text(self):
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get(prts_url, timeout=7) as res:
soup = BeautifulSoup(await res.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']
async with session.get(f'https://ak.hypergryph.com{a}', headers=headers, timeout=7) as res:
return await res.text()
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)
@@ -147,9 +145,7 @@ class GenshinAnnouncement:
self.game_name = '原神'
async def _get_announcement_text(self):
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get(genshin_url, timeout=7) as res:
return await res.text()
return (await AsyncHttpx.get(genshin_url)).text
async def update_up_char(self):
genshin_up_char.parent.mkdir(exist_ok=True, parents=True)
@@ -218,21 +214,20 @@ class PrettyAnnouncement:
self.game_name = '赛马娘'
async def _get_announcement_text(self):
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get(pretty_url, timeout=7) as res:
soup = BeautifulSoup(await res.text(), 'lxml')
divs = soup.find('div', {'id': 'mw-content-text'}).find('div').find_all('div')
for div in divs:
a = div.find('a')
try:
title = a['title']
except (KeyError, TypeError):
continue
if title.find('新角色追加') != -1:
url = a['href']
break
async with session.get(f'https://wiki.biligame.com/{url}', timeout=7) as res:
return await res.text(), title[:-2]
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)
@@ -343,9 +338,7 @@ class GuardianAnnouncement:
self.game_name = '坎公骑冠剑'
async def _get_announcement_text(self):
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get(guardian_url, timeout=7) as res:
return await res.text()
return (await AsyncHttpx.get(guardian_url)).text
async def update_up_char(self):
data = {
View File
Regular → Executable
View File
Regular → Executable
View File

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