mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-01 09:39:59 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5de5667f80 | ||
|
|
69b3ba47b3 | ||
|
|
11c1d0b827 | ||
|
|
8f97880754 | ||
|
|
ff435bea95 | ||
|
|
cd66b7f5b8 | ||
|
|
a60286c328 | ||
|
|
49e38862af | ||
|
|
75b8cc0766 | ||
|
|
a8e2f00e16 | ||
|
|
d099a85c59 | ||
|
|
55b2a86397 | ||
|
|
d39dfbe62f | ||
|
|
a41e62cefe | ||
|
|
c981562f90 | ||
|
|
e6cd57cc26 | ||
|
|
074152ae14 | ||
|
|
91ca7b40b8 | ||
|
|
5321c8d9c0 | ||
|
|
b7f753ebb6 | ||
|
|
c5e8ba3cdf | ||
|
|
658ef5309b | ||
|
|
823f642225 | ||
|
|
57ea6bad07 | ||
|
|
109c645e68 | ||
|
|
5ef0ce5aa8 | ||
|
|
f6d9e083b8 | ||
|
|
499517e882 | ||
|
|
648db532bb | ||
|
|
1ce4537605 | ||
|
|
701812ed9d | ||
|
|
8d9e81827b | ||
|
|
f51a2816b4 | ||
|
|
3d4a7950c5 | ||
|
|
ba6668f144 | ||
|
|
e1f7a77d15 | ||
|
|
64e2c512d3 | ||
|
|
6082e68a1f | ||
|
|
f135d48e55 | ||
|
|
751fc8fdb4 | ||
|
|
df73e79ee4 | ||
|
|
fa6cfdb609 | ||
|
|
b057a05520 | ||
|
|
cb0938721c | ||
|
|
4f3f8de734 | ||
|
|
5ba303aada | ||
|
|
bd42fefe4e | ||
|
|
d24c081973 | ||
|
|
1b9eddd905 | ||
|
|
0bfe398dc4 | ||
|
|
e9216a472f | ||
|
|
8b93ec0df6 | ||
|
|
7497706a0d | ||
|
|
6e41cb0630 | ||
|
|
62d99e7e90 | ||
|
|
43cddb3580 | ||
|
|
c9c1beda75 | ||
|
|
3ee9ae5fb8 | ||
|
|
ea6344fae1 | ||
|
|
6f54e91f5c | ||
|
|
27fb3aaa19 | ||
|
|
86d736745d | ||
|
|
821fe21c2b | ||
|
|
7f4aa518dc | ||
|
|
8cf589e433 | ||
|
|
105a29cd70 | ||
|
|
cb6a5e81e7 | ||
|
|
9c073383ad | ||
|
|
5e0756825d | ||
|
|
933523ae6d | ||
|
|
ed6b05605c | ||
|
|
71a9c34620 | ||
|
|
e29f2cb920 | ||
|
|
d47dd88d6c | ||
|
|
fb34bbce7a | ||
|
|
100236da83 | ||
|
|
a45a3002d5 | ||
|
|
9214a4c978 | ||
|
|
70761dc222 | ||
|
|
32e8136f71 | ||
|
|
8b20d99b2c | ||
|
|
1174b5cc7f | ||
|
|
ec448cfdfb | ||
|
|
f3e44b1baf |
@@ -1,38 +0,0 @@
|
||||
name: Generate poetry.lock
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
paths:
|
||||
- 'pyproject.toml'
|
||||
|
||||
jobs:
|
||||
poetry_lock:
|
||||
name: Generate
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: he0119/setup-python@main
|
||||
with:
|
||||
python-version: "3.9"
|
||||
- name: poetry lock
|
||||
run: |
|
||||
rm -f poetry.lock
|
||||
sed -i.bak "8,11d" pyproject.toml
|
||||
poetry lock
|
||||
mv pyproject.toml.bak pyproject.toml
|
||||
# commit
|
||||
- name: commit file
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add poetry.lock
|
||||
git commit -m "Auto generate poetry.lock" -a
|
||||
# push
|
||||
- name: push changes
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -13,7 +13,9 @@
|
||||
|
||||
如果该项目的图片等等侵犯猫豆腐老师权益请联系我删除!
|
||||
|
||||
如果希望有个地方讨论绪山真寻Bot,或者有问题或建议,可以发送issues或加入[ <strong>[是真寻酱哒](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>]
|
||||
是新手!希望有个地方讨论绪山真寻Bot,或者有问题或建议,可以发送issues或加入[ <strong>[是真寻酱哒(萌新版)](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>]
|
||||
|
||||
[//]: # (是老手!讨论插件开发,nonebot2开发,可以加入[ <strong>[真寻酱的技术群](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>])
|
||||
|
||||
## 声明
|
||||
此项目仅用于学习交流,请勿用于非法用途
|
||||
@@ -252,6 +254,21 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
|
||||
|
||||
### 感谢名单
|
||||
(可以告诉我你的 __github__ 地址,我偷偷换掉0v|)
|
||||
|
||||
[阿奎](https://afdian.net/u/da41f72845d511ed930d52540025c377)
|
||||
[醉梦尘逸](https://afdian.net/u/bc11d2683cd011ed99b552540025c377)
|
||||
[Abc](https://afdian.net/u/870dc10a3cd311ed828852540025c377)
|
||||
[本喵无敌哒](https://afdian.net/u/dffaa9005bc911ebb69b52540025c377)
|
||||
[椎名冬羽](https://afdian.net/u/ca1ebd64395e11ed81b452540025c377)
|
||||
[kaito](https://afdian.net/u/a055e20a498811eab1f052540025c377)
|
||||
[笑柒XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377)
|
||||
[请问一份爱多少钱](https://afdian.net/u/f57ef6602dbd11ed977f52540025c377)
|
||||
[咸鱼鱼鱼鱼](https://afdian.net/u/8e39b9a400e011ed9f4a52540025c377)
|
||||
[Kafka](https://afdian.net/u/41d66798ef6911ecbc5952540025c377)
|
||||
[墨然](https://afdian.net/u/8aa5874a644d11eb8a6752540025c377)
|
||||
[爱发电用户_T9e4](https://afdian.net/u/2ad1bb82f3a711eca22852540025c377)
|
||||
[笑柒XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377)
|
||||
[noahzark](https://afdian.net/a/noahzark)
|
||||
[腊条](https://afdian.net/u/f739c4d69eca11eba94b52540025c377)
|
||||
[ze roller](https://afdian.net/u/0e599e96257211ed805152540025c377)
|
||||
[爱发电用户_4jrf](https://afdian.net/u/6b2cdcc817c611ed949152540025c377)
|
||||
@@ -263,7 +280,7 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
|
||||
[爱发电用户_eNr9](https://afdian.net/u/05fdb41c0c9a11ed814952540025c377)
|
||||
[MangataAkihi](https://github.com/Sakuracio)
|
||||
[炀](https://afdian.net/u/69b76e9ec77b11ec874f52540025c377)
|
||||
[爱发电用户_Bc6j](https://afdian.net/u/8546be24f44111eca64052540025c377)
|
||||
[爱发电用户_Bc6j](https://afdian.net/u/8546be24f44111eca64052540025c377)
|
||||
[大魔王](https://github.com/xipesoy)
|
||||
[CopilotLaLaLa](https://github.com/CopilotLaLaLa)
|
||||
[嘿小欧](https://afdian.net/u/daa4bec4f24911ec82e552540025c377)
|
||||
@@ -279,6 +296,97 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
|
||||
|
||||
## 更新
|
||||
|
||||
### 2022/11/21 \[v0.1.6.5]
|
||||
|
||||
* 优化manager, hook代码
|
||||
* 修复pid搜图 [@pull/1180](https://github.com/HibiKier/zhenxun_bot/pull/1180)
|
||||
|
||||
### 2022/11/19
|
||||
|
||||
* 修改优化帮助图片生成逻辑
|
||||
|
||||
### 2022/11/18
|
||||
|
||||
* poetry添加适配器依赖,更新支持py3.10 [@pull/1176](https://github.com/HibiKier/zhenxun_bot/pull/1176)
|
||||
|
||||
### 2022/11/13
|
||||
|
||||
* 更新天气api
|
||||
* 使用道具可以附带额外信息供函数使用
|
||||
* 限制帮助图片最小宽度
|
||||
|
||||
### 2022/11/12
|
||||
|
||||
* 更新yiqing插件数据显示 [@pull/1168](https://github.com/HibiKier/zhenxun_bot/pull/1168)
|
||||
|
||||
### 2022/11/11
|
||||
|
||||
* fix: B站直播订阅的相关问题 [@pull/1158](https://github.com/HibiKier/zhenxun_bot/pull/1158)
|
||||
|
||||
### 2022/10/30
|
||||
|
||||
* 商店简介动态行数,根据文字长度自动换行
|
||||
|
||||
### 2022/10/28
|
||||
|
||||
* 为exec指令进行了SELECT语句适配,添加了查看所有表指令 [@pull/1155](https://github.com/HibiKier/zhenxun_bot/pull/1155)
|
||||
* 修复复读 [@pull/1154](https://github.com/HibiKier/zhenxun_bot/pull/1154)
|
||||
|
||||
### 2022/10/23
|
||||
|
||||
* 复读修改回图片下载
|
||||
|
||||
### 2022/10/22
|
||||
|
||||
* 更新依赖注入
|
||||
|
||||
### 2022/10/16 \[v0.1.6.4]
|
||||
|
||||
* 修改商店道具icon可以为空
|
||||
|
||||
### 2022/10/15
|
||||
|
||||
* nonebot2版本更新为rc1
|
||||
* 我的道具改为图片形式
|
||||
* 商品添加图标与是否为被动道具(被动道具无法被主动使用)
|
||||
* 商品添加使用前方法和使用后方法(类似hook),使用方法具体查看文档或签到商品文件中注册的例子
|
||||
* 新增用户使用道具,花费金币(包括插件)及用途记录
|
||||
* 更细致的金币使用依赖注入
|
||||
* 更多的依赖注入(包含图片获取等等..
|
||||
* 修复我的道具仅有被动或主动道具时图片显示错误
|
||||
* 色图插件p站反向代理失效 [@pull/1139](https://github.com/HibiKier/zhenxun_bot/pull/1139)
|
||||
|
||||
### 2022/10/9
|
||||
|
||||
* 修复碧蓝档案角色获取问题,换源 [@pull/1124](https://github.com/HibiKier/zhenxun_bot/pull/1124)
|
||||
|
||||
### 2022/10/7
|
||||
|
||||
* 修复 B 站请求返回 -401 错误 [@pull/1119](https://github.com/HibiKier/zhenxun_bot/pull/1119)
|
||||
* 关闭功能与被动时不再区分大小写,同名时仅被动关闭操作生效
|
||||
|
||||
### 2022/9/30
|
||||
|
||||
* 修改重置开箱的使用权限 [@pull/1118](https://github.com/HibiKier/zhenxun_bot/pull/1118)
|
||||
|
||||
### 2022/9/27
|
||||
|
||||
* 更新b站转发解析 [@pull/1117](https://github.com/HibiKier/zhenxun_bot/pull/1117)
|
||||
|
||||
### 2022/9/24
|
||||
|
||||
* 修复b站订阅 [@pull/1112](https://github.com/HibiKier/zhenxun_bot/pull/1112)
|
||||
* fix: 重载赛马娘卡池失败 [@pull/1114](https://github.com/HibiKier/zhenxun_bot/pull/1114)
|
||||
|
||||
### 2022/9/19
|
||||
|
||||
* 更换bilibili_sub获取用户昵称用的API&尝试修了一下get_video() [@pull/1097](https://github.com/HibiKier/zhenxun_bot/pull/1097)
|
||||
* 修复csgo每日开箱可以多开一次
|
||||
|
||||
### 2022/9/18
|
||||
|
||||
* 修复 bilireq 版本过低导致 B 站视频解析错误 [@pull/1090](https://github.com/HibiKier/zhenxun_bot/pull/1096)
|
||||
|
||||
### 2022/9/16
|
||||
|
||||
* fix: bilibili_sub, azur_draw_card [@pull/1090](https://github.com/HibiKier/zhenxun_bot/pull/1090)
|
||||
@@ -334,7 +442,7 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
|
||||
* 修复b站转发解析av号无法解析
|
||||
* B站订阅直播订阅支持短号
|
||||
* 开箱提供重置开箱命令,重置今日所有开箱数据(重置次数,并不会删除今日已开箱记录)
|
||||
* 提供全局字典GDict,通过from utils.manager import GDict导入
|
||||
* 提供全局字典GDict,通过from utils.utils import GDict导入
|
||||
* 适配omega 13w张图的数据结构表(建议删表重导)
|
||||
* 除首次启动外将配置替换加入单次定时任务,加快启动速度
|
||||
* fix: WordBank.check() [@pull/1008](https://github.com/HibiKier/zhenxun_bot/pull/1008)
|
||||
@@ -360,481 +468,6 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
|
||||
|
||||
* 修复了原神自动签到返回invalid request的问题,新增查看我的cookie命令 [@pull/971](https://github.com/HibiKier/zhenxun_bot/pull/971)
|
||||
|
||||
### 2022/7/31
|
||||
|
||||
* 对nonebot.beta4中PluginMeta进行解析
|
||||
* 修改webui元祖类型无法正确转换类型
|
||||
* 查看订阅以图片形式发送
|
||||
* 修复pix无图时不会提醒而是出错
|
||||
|
||||
### 2022/7/30
|
||||
|
||||
* 替换了cos和bt的url [@pull/951](https://github.com/HibiKier/zhenxun_bot/pull/951)
|
||||
* 发言记录统计添加日消息统计 [@pull/953](https://github.com/HibiKier/zhenxun_bot/pull/953)
|
||||
|
||||
### 2022/7/24 \[v0.1.6.2]
|
||||
|
||||
* 订阅up动态提供直链
|
||||
|
||||
### 2022/7/23
|
||||
|
||||
* 优化开箱次数判断
|
||||
|
||||
### 2022/7/16
|
||||
|
||||
* cos提供连发命令
|
||||
* 修复B站视频解析中b23解析错误
|
||||
|
||||
### 2022/7/13
|
||||
|
||||
* B站订阅提供配置项`LIVE_MSG_AT_ALL`,`UP_MSG_AT_ALL`:控制UP动态投稿和直播是否AT全体
|
||||
* 修改了Omega图库检测的数据库文件名
|
||||
* game_utils提供了Game类
|
||||
|
||||
### 2022/7/7
|
||||
|
||||
* 微博热搜选择单条热搜时也会检测时效性 [@pull/891](https://github.com/HibiKier/zhenxun_bot/pull/891)
|
||||
|
||||
### 2022/7/4
|
||||
|
||||
* 修复商品未设置限购时无法购买
|
||||
* 修复B站订阅UP动态 [@pull/886](https://github.com/HibiKier/zhenxun_bot/pull/886)
|
||||
* 修复色图命令带tag时配置项`MAX_ONCE_NUM2FORWARD`无法生效
|
||||
|
||||
### 2022/7/3 \[v0.1.6.1]
|
||||
|
||||
* BagUser提供方法`check_props`方法,用于判断用户是否含有该道具并是否使用
|
||||
* 优化商品显示图片,提供限制,限购,折扣提示
|
||||
* 修复图库内图片无法被连续删除的问题 [@pull/879](https://github.com/HibiKier/zhenxun_bot/pull/879)
|
||||
* 色图提供配置项`MAX_ONCE_NUM2FORWARD`:群聊中单次发送图片数量达到指定时使用合并转发
|
||||
* 优化修复了商品修改命令
|
||||
* B站订阅UP动态改为详情页截图
|
||||
|
||||
### 2022/6/28
|
||||
|
||||
* 修复色图插件api修改无法搜索图片 [@pull/866](https://github.com/HibiKier/zhenxun_bot/pull/866)
|
||||
|
||||
### 2022/6/26
|
||||
|
||||
* 替换了bt URL
|
||||
* PIX当使用pid查询图片时,会发送该pid下所有图片
|
||||
* 商店提供了每日购买次数限制
|
||||
|
||||
### 2022/6/24
|
||||
|
||||
* 对WSL虚拟机 代理 添加写法 [@pull/847](https://github.com/HibiKier/zhenxun_bot/pull/847)
|
||||
|
||||
### 2022/6/21
|
||||
|
||||
* update parse_bilibili [@pull/840](https://github.com/HibiKier/zhenxun_bot/pull/840)
|
||||
|
||||
### 2022/6/19 \[v0.1.6.0]
|
||||
|
||||
* 暂时使用hook修复webui中plugins2setting修改时会改变plugins2setting.cmd为字符串
|
||||
* 修复原神树脂重复提醒的bug [@pull/828](https://github.com/HibiKier/zhenxun_bot/pull/828)
|
||||
* 词条优化问题展示,修改含机器人昵称和@逻辑 [@pull/835](https://github.com/HibiKier/zhenxun_bot/pull/835)
|
||||
|
||||
### 2022/6/18
|
||||
|
||||
* 修复昵称系统`BLACK_WORD`为空时造成报错
|
||||
* 修复特殊头像时背景透明化出错
|
||||
* 修复text2image纯文本时换行时颜色不统一
|
||||
* 优化webUI,当有插件出错时不会影响其他插件显示
|
||||
* 优化Config类型注释 [@pull/830](https://github.com/HibiKier/zhenxun_bot/pull/830)
|
||||
* 优化browser
|
||||
|
||||
### 2022/6/17
|
||||
|
||||
* 修复wordbank的一些小问题 @pull/820
|
||||
|
||||
### 2022/6/14
|
||||
|
||||
* AsyncHttpx提供可关闭 ssl 验证参数 [@pull/812](https://github.com/HibiKier/zhenxun_bot/pull/812)
|
||||
* fix: 自动更新群组 [@pull/810](https://github.com/HibiKier/zhenxun_bot/pull/810)
|
||||
* fix: 修复添加词条时对answer中图片的处理 [@pull/806](https://github.com/HibiKier/zhenxun_bot/pull/806)
|
||||
* 修复pix中指定num无法生效
|
||||
* 替换了bt URL
|
||||
|
||||
### 2022/6/13
|
||||
|
||||
* Windows 重启适配 [@pull/804](https://github.com/HibiKier/zhenxun_bot/pull/804)
|
||||
* 色图等提供修改md5方法 [@pull/800](https://github.com/HibiKier/zhenxun_bot/pull/800)
|
||||
* webui中token.json文件写入补充 [@pull/798](https://github.com/HibiKier/zhenxun_bot/pull/798)
|
||||
* 修复识图某些图片可能会出错
|
||||
|
||||
### 2022/6/11
|
||||
|
||||
* pix当只有一个tag时且为数字时可以通过添加'#'防止判定为数量
|
||||
|
||||
### 2022/6/9
|
||||
|
||||
* 修复b站订阅同群二人以上相同订阅时发送多次信息
|
||||
* 修复超级用户帮助中缺少了 ‘插件商店’ 相关帮助
|
||||
* 昵称系统提供了详细帮助
|
||||
|
||||
### 2022/6/5 \[v0.1.5.9]
|
||||
|
||||
* webui修复plugin2setting中cmd从list转变为str
|
||||
* 当命令`我的金币`被风控时将以图片形式发送
|
||||
* fix gold_redbag [@pull/763](https://github.com/HibiKier/zhenxun_bot/pull/763)
|
||||
* 金币红包功能增加更多封面 [@pull/764](https://github.com/HibiKier/zhenxun_bot/pull/764)
|
||||
|
||||
### 2022/6/3
|
||||
|
||||
* 插件仓库在已安装插件边上会提示\[已安装]
|
||||
* 修复ShopRegister kwargs某些字段无效
|
||||
* 调整了一下查看所有请求中的年龄绘制 [@pull/745](https://github.com/HibiKier/zhenxun_bot/pull/745)
|
||||
* 修复原神树脂提醒bug [@pull/756](https://github.com/HibiKier/zhenxun_bot/pull/756)
|
||||
|
||||
### 2022/5/31
|
||||
|
||||
* 修复开启/关闭全部功能时帮助图片未重绘 [@pull/721](https://github.com/HibiKier/zhenxun_bot/pull/721)
|
||||
* bot_friend_group将group_handle.修改为friend_handle. [@pull/711](https://github.com/HibiKier/zhenxun_bot/pull/711)
|
||||
* 修复发红包图片背景未透明化;修复原神树脂提醒参数错误 [@pull/712](https://github.com/HibiKier/zhenxun_bot/pull/712)
|
||||
* 修复抽卡插件:方舟更新UP池信息时,若公告的第一个池子过期会导致无法更新UP池信息 [@pull/707](https://github.com/HibiKier/zhenxun_bot/pull/707)
|
||||
* 商店插件判断是否有requirements.txt文件 [@pull/705](https://github.com/HibiKier/zhenxun_bot/pull/705)
|
||||
* 删除原神玩家查询api返回变更的多余键值
|
||||
* 优化了text2image方法
|
||||
|
||||
### 2022/5/29 \[v0.1.5.8]
|
||||
|
||||
* 提供了真寻适配仓库的插件 安装/卸载 操作
|
||||
* 暂时关闭了插件资源清空
|
||||
* 通过指令安装插件时会在插件目录下生成plugin_info.json记录当前插件信息
|
||||
|
||||
### 2022/5/28
|
||||
|
||||
* 修复私聊无法添加昵称
|
||||
* 修复原神玩家查询层岩巨渊地下矿区没开时报错
|
||||
* 修复 ```休息吧``` 无法阻断戳一戳
|
||||
* 当图库无图片时,戳一戳将略过发送图片
|
||||
* 新增搜图提供配置项```ALLOW_GROUP_R18```:允许在群聊中使用r18参数
|
||||
* 新增自动更新插件```UPDATE_REMIND```:新版本提醒,原配置项```AUTO_UPDATE_ZHENXUN```改为自动更新升级
|
||||
* black_word新增当群权限为-1时不再检测该群
|
||||
* 修复非超级用户绑定原神cookie会被black_word阻拦
|
||||
* 修复微博热搜报错,发红包小bug [@pull/688](https://github.com/HibiKier/zhenxun_bot/pull/688)
|
||||
* 更多的中文提示
|
||||
|
||||
### 2022/5/26
|
||||
|
||||
* 修复\[滴滴滴]会被转义成[滴滴滴]导致无法触发的问题
|
||||
* 将一些错误以中文提示输出
|
||||
* 更新BT搜索源地址 [@pull/668](https://github.com/HibiKier/zhenxun_bot/pull/668)
|
||||
* 更新抽卡插件 [@pull/667](https://github.com/HibiKier/zhenxun_bot/pull/667)
|
||||
|
||||
### 2022/5/25
|
||||
|
||||
* 修复webui中CountLimit字段limit_type类型错误
|
||||
* 修改nickname插件:一处文案错误,添加敏感词 [@pull/624](https://github.com/HibiKier/zhenxun_bot/pull/624)
|
||||
* gamedraw的ba卡池搬运了过来并且进行了真寻的适配 [@pull/617](https://github.com/HibiKier/zhenxun_bot/pull/617)
|
||||
* feat: stream downloading and progress [@pull/607](https://github.com/HibiKier/zhenxun_bot/pull/607)
|
||||
* 修改翻译插件,添加缺失的冒号 [@pull/602](https://github.com/HibiKier/zhenxun_bot/pull/602)
|
||||
* 修复碧蓝航线/明日方舟up池解析出错的问题 [@pull/610](https://github.com/HibiKier/zhenxun_bot/pull/602)
|
||||
|
||||
### 2022/5/24
|
||||
|
||||
* fix: 修正了签到时日期时间的显示不补齐零的bug (符合日期时间表示法 ISO 8601)[@pull/600](https://github.com/HibiKier/zhenxun_bot/pull/600)
|
||||
* 更新"微博热搜"接口 [@pull/579](https://github.com/HibiKier/zhenxun_bot/pull/579)
|
||||
* refactor&fix(manager): modify argument [@pull/576](https://github.com/HibiKier/zhenxun_bot/pull/576)
|
||||
* 修复复读不能复读图片的问题 [@pull/573](https://github.com/HibiKier/zhenxun_bot/pull/573)
|
||||
* 修复抽卡插件:方舟抽卡的抽取和显示问题 [@pull/581](https://github.com/HibiKier/zhenxun_bot/pull/581)
|
||||
|
||||
### 2022/5/23 \[v0.1.5.6]
|
||||
|
||||
* 修复"清除已删除插件数据" [@pull/545](https://github.com/HibiKier/zhenxun_bot/pull/545)
|
||||
* 修复有置顶的up主B站动态获取失败 [@pull/552](https://github.com/HibiKier/zhenxun_bot/pull/552)
|
||||
* 添加pixiv搜图多关键词支持;修复p站搜图数量参数问题 [@pull/441](https://github.com/HibiKier/zhenxun_bot/pull/441)
|
||||
* 修复开箱更新价格错误传参
|
||||
* 修复pix无法正确查询uid
|
||||
* 新增色图插件添加配置项```ALLOW_GROUP_R18```:允许群聊中使用色图r
|
||||
* 新增PIX插件添加配置项```ALLOW_GROUP_SETU```:允许非超级用户使用-s参数
|
||||
* 新增PIX插件添加配置项```ALLOW_GROUP_R18```:允许非超级用户使用-r参数
|
||||
|
||||
### 2022/5/22 \[v0.1.5.4]
|
||||
|
||||
* 使用action自动更新poetry.lock [@pull/515](https://github.com/HibiKier/zhenxun_bot/pull/515)
|
||||
* fix(bilibili_sub): card is None and timeout [@pull/516](https://github.com/HibiKier/zhenxun_bot/pull/516)
|
||||
* 修复了epic有时获取新免费游戏消息时获取不到图片
|
||||
* 修复好感度满时签到出错(虽然是不可能满的
|
||||
* 修复原神资源图标下载路径错误
|
||||
* 修复自动更新群组可能失败
|
||||
|
||||
### 2022/5/21
|
||||
|
||||
* 修复搜番无结果时报错无正确反馈
|
||||
* 解锁了windows上无法使用playwright的限制
|
||||
* 修复p搜对应pid有多张图时出错,改为连续发送图片
|
||||
* 修复p搜对数字的错误判断
|
||||
* 修复添加商品折扣无法正确添加
|
||||
* 修复了bilibili订阅直播间订阅up名称不一致的问题
|
||||
* 修复原神玩家查询没开地图时报错
|
||||
* 最低priority修改为 999
|
||||
* 修复刷屏检测失效
|
||||
* 修复刷屏检测设置命令无法生效
|
||||
* 优化刷屏显示设置禁言时长显示,并改为分钟
|
||||
* 修复了多连开箱无法指定武器箱
|
||||
* 修复识番链接无法正确获取
|
||||
* 新增真寻入群时即刻刷新权限
|
||||
* 提高了微博热搜截图的等待时间
|
||||
|
||||
### 2022/5/19
|
||||
|
||||
* fix: mihoyo bbs api changed [@pull/357](https://github.com/HibiKier/zhenxun_bot/pull/357)
|
||||
* Add word_clouds [@pull/265](https://github.com/HibiKier/zhenxun_bot/pull/265)
|
||||
* Fix wrong live streamer name [@pull/284](https://github.com/HibiKier/zhenxun_bot/pull/284)
|
||||
|
||||
### 2022/5/16
|
||||
|
||||
* 词条支持图片和@问题 [@pull/160](https://github.com/HibiKier/zhenxun_bot/pull/160)
|
||||
|
||||
### 2022/5/15
|
||||
|
||||
* 修复了商店商品无法正确添加
|
||||
* 修复了多张色图无法正确发送
|
||||
|
||||
### 2022/5/14
|
||||
|
||||
* 修复B站动态生成失败的问题 [@pull/159](https://github.com/HibiKier/zhenxun_bot/pull/159)
|
||||
|
||||
### 2022/5/11
|
||||
|
||||
* fix: 更改p搜api,解决p搜无法使用的问题 [@pull/155](https://github.com/HibiKier/zhenxun_bot/pull/155)
|
||||
|
||||
### 2022/5/9 \[v0.1.5.3]
|
||||
|
||||
* 替换了疫情API
|
||||
* 修复了私聊.ban/.unban出错
|
||||
|
||||
### 2022/5/5
|
||||
|
||||
* 修改bilibili_sub插件在windows平台下报错 [@pull/153](https://github.com/HibiKier/zhenxun_bot/pull/153)
|
||||
|
||||
### 2022/5/3 \[v0.1.5.2]
|
||||
|
||||
* 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数
|
||||
* 添加商品注册装饰器shop_register
|
||||
* 修复商品函数kwargs无法获取参数值
|
||||
|
||||
|
||||
### 2022/5/1
|
||||
|
||||
* 删除了`group_last_chat`插件(该功能可由`chat_history`替代
|
||||
* 新增敏感词检测(全新反击系统,是时候重拳出击了
|
||||
|
||||
### 2022/4/26
|
||||
|
||||
* 修复了群白名单无法正确添加
|
||||
* 优化了管理员帮助图片,背景图层将位于最下层
|
||||
* 修复了树脂140时不断提醒(未测试
|
||||
* 新增了消息记录的消息排行
|
||||
* WebUI新增CPU,内存,磁盘监控
|
||||
* WebUI新增资源文件夹统计可视化
|
||||
|
||||
### 2022/4/12
|
||||
|
||||
* 修复b了命令私聊出错
|
||||
|
||||
### 2022/4/10 \[v0.1.4.7]
|
||||
|
||||
* 新增消息记录模块
|
||||
* 丰富处理请求操作提示
|
||||
* web ui新增配置项修改
|
||||
|
||||
### 2022/4/9
|
||||
|
||||
* fix: 更新问题,戳一戳图片路径问题 [@pull/144](https://github.com/HibiKier/zhenxun_bot/pull/144)
|
||||
|
||||
### 2022/4/8
|
||||
|
||||
* 修复原神玩家查询
|
||||
|
||||
### 2022/4/6
|
||||
|
||||
* update search_type [@pull/143](https://github.com/HibiKier/zhenxun_bot/pull/143)
|
||||
|
||||
### 2022/4/5 \[v0.1.4.6]
|
||||
|
||||
* 修复web修改插件后帮助图片生成错误
|
||||
|
||||
### 2022/4/4 \[v0.1.4.5]
|
||||
|
||||
* 替换了bt搜索URL
|
||||
* 优化使用playwright的相关代码
|
||||
* 原神玩家查询新增层岩巨渊探索
|
||||
* 修复原神便笺角色头像黑框
|
||||
* 修复同意群聊请求错误
|
||||
* 提供webui方面的api
|
||||
* 新增web-ui(前端简易管理页面插件)插件
|
||||
|
||||
### 2022/3/21
|
||||
|
||||
* 修复statistics_handle.py乱码
|
||||
|
||||
### 2022/3/18 \[v0.1.4.4]
|
||||
|
||||
* 修复戳一戳无法功能关闭与ban禁用
|
||||
* 新增图片搜索 search_image
|
||||
|
||||
### 2022/3/7
|
||||
|
||||
* 优化增删权限插件
|
||||
|
||||
### 2022/3/6
|
||||
|
||||
* 修复树脂提醒无法开启
|
||||
* 修复p搜图片路径错误
|
||||
|
||||
### 2022/3/3 \[v0.1.4.3]
|
||||
|
||||
* 修复手动同意群聊请求依旧退出
|
||||
|
||||
### 2022/3/1 \[v0.1.4.2]
|
||||
|
||||
* 0.1.4内容
|
||||
|
||||
### 2022/2/27 \[v0.1.4.1]
|
||||
|
||||
* 优化抽卡
|
||||
|
||||
### 2022/2/25 \[v0.1.4]
|
||||
|
||||
* PIX提供配置MAX_ONCE_NUM2FORWARD:当单次发送图片超过指定张数且在群聊时,将转为合并消息
|
||||
* 修复点歌无法正确发送
|
||||
* 修复我有一个朋友有时文本会包含CQ码
|
||||
* 修复群欢消息被动控制文本未删除 [@pull/124](https://github.com/HibiKier/zhenxun_bot/pull/124)
|
||||
* message_builder.image不再提供参数:abspath
|
||||
|
||||
### 2022/2/23
|
||||
|
||||
* 插件状态将从已加载插件模块中读取
|
||||
* 修复b站订阅插件订阅失败问题
|
||||
* 修复重启命令无法使用
|
||||
|
||||
### 2022/2/21 \[v0.1.3.2]
|
||||
|
||||
* 群权限为-1时,超级用户发送的命令依旧生效
|
||||
* 当群权限为-1时,被动技能也将不会发送
|
||||
* 修复功能开关,b站转发解析,复读 ignore无法使用
|
||||
* 修复色图下载文件名与路径错误
|
||||
* 修复被动技能提醒有时无法删除控制文本
|
||||
|
||||
|
||||
### 2022/2/20 \[v0.1.3.1]
|
||||
|
||||
* 修复pix下载临时文件目录错误
|
||||
* 修复AI,天气,发送图片ignore导致无法使用
|
||||
* 修复纯文本被动技能提醒有时无法删除控制文本
|
||||
|
||||
### 2022/2/19 \[v0.1.3] (nonebot beta2!)
|
||||
|
||||
* 由于nonebot升级版本,提供更新建议(__该次升级将会导致nonebot.beta1以下的插件无法使用__
|
||||
* 保证services,utils,configs,plugins,basic_plugins,文件夹均为最新
|
||||
* 根目录有pyproject.toml与poetry.lock
|
||||
* 执行命令:
|
||||
* pip3 install poetry
|
||||
* poetry install
|
||||
* poetry shell
|
||||
* playwright install chromium
|
||||
* python3 bot.py
|
||||
|
||||
|
||||
* 适配nonebot.beta2
|
||||
* 删除图片搜索 nonebot_plugin_picsearcher
|
||||
* 替换cos api
|
||||
* 原神签到树脂提醒新增绑定群里,在某群绑定uid就会在某群发送提醒信息(有好友则私聊,需要重新绑定uid
|
||||
* 修改update_info.json
|
||||
* 修复原神资源查询下载数据失败时导致报错
|
||||
* 优化BuildImage.circle()锯齿问题 [@pull/109](https://github.com/HibiKier/zhenxun_bot/pull/109)
|
||||
* epic restful 替换 [@pull/119](https://github.com/HibiKier/zhenxun_bot/pull/119)
|
||||
* fix: 修复远古时期残留的epic推送问题 [@pull/122](https://github.com/HibiKier/zhenxun_bot/pull/122)
|
||||
|
||||
### 2022/2/11
|
||||
|
||||
* 修复pix不使用反代无法下载图片
|
||||
|
||||
### 2022/2/10 \[v0.1.1]
|
||||
|
||||
* 修复购买道具出错
|
||||
|
||||
### 2022/2/9 \[v0.1]
|
||||
|
||||
* 新增原神自动签到和手动签到
|
||||
* 新增原神树脂提醒
|
||||
* 新增手动重载Config.yaml命令以及重载配置定时任务(极少部分帮助或配置可能需要重启
|
||||
* 修改了发送本地图库的matcher,改为on_message
|
||||
* register_use可以通过返回值发送消息
|
||||
* 修复修改商品时限制时间出错
|
||||
* 修复超时商品依旧可以被购买
|
||||
|
||||
### 2022/1/16 \[v0.0.9.0]
|
||||
|
||||
* Ai提供文本敏感词过滤器
|
||||
* 疫情插件适配新版腾讯API
|
||||
* 修复/t回复带空格切分
|
||||
* 修复原神玩家查询缺少渊下宫和稻妻家园以及角色不完全
|
||||
* 修复方法 text2image 中 padding 和 font 无法对纯文本生效
|
||||
* 修复签到图片中信息并未使用配置文件中的色图概率
|
||||
* 修改原神大地图合成方式,改为先压缩再合成
|
||||
* bag_user弃用字段props(该字段会在下次更新删除),使用新字段property
|
||||
* 数据库中所有belonging_group统一修改为group_id
|
||||
* 商店将registered_use和register_goods更名为register_use何register_goods
|
||||
* 商品注册提供了kwargs参数提供:
|
||||
* bot
|
||||
* event
|
||||
* 特殊字段
|
||||
* “send_success_msg”(发送成功的交互信息->即:使用道具 {name} {num} 次成功)
|
||||
* “_max_num_limit”(该道具单次使用的最多个数,默认1)
|
||||
|
||||
### 2022/1/5 \[v0.0.8.2]
|
||||
|
||||
* 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币
|
||||
* 商店插件将作为内置插件移动至basic_plugins
|
||||
* 商店插件通过export提供了方法,不需要修改商店插件代码添加商品数据和生效方法
|
||||
* 修改了hook插件顺序,主要以auth_hook为主
|
||||
* 修改商店图片样式
|
||||
* 取消每次启动更新城市列表(首次除外),采用定时更新,加快bot启动速度
|
||||
* 取消每次启动时截取今日素材,采用调用时截取保存,加快bot启动速度
|
||||
* 更新色图时当图片404时会删除并替换
|
||||
* 疫情消息回复改为图片
|
||||
* 修复商店折扣和限时时间无法生效
|
||||
* 修复原神玩家查询尘歌壶缺少图片
|
||||
|
||||
### 2021/12/26
|
||||
|
||||
* 修复群词条问题 空格 会被录入导致不断回复
|
||||
* 修复米游社app替换api导致无法正常查询
|
||||
|
||||
### 2021/12/24
|
||||
|
||||
* 支持国际疫情数据查询 [@pull/99](https://github.com/HibiKier/zhenxun_bot/pull/99)
|
||||
|
||||
### 2021/12/20
|
||||
|
||||
* 只有发布小于存储时间的新动态/视频的时候才获取并推送 [@pull/96](https://github.com/HibiKier/zhenxun_bot/pull/96)
|
||||
|
||||
### 2021/12/16 \[v0.0.7.0]
|
||||
|
||||
* 提供了真寻群聊功能总开关和对应默认配置项,命令:休息吧 醒来
|
||||
* 新增原神玩家查询,原神便笺查询
|
||||
* 群功能管理提供全部开启/关闭命令:开启/关闭全部功能
|
||||
* 提供主要数据自动备份,且提供自定义配置项
|
||||
* 提供命令:关于,用于介绍Bot之类的
|
||||
* 新增命令exec,用于执行sql语句
|
||||
* 签到提供参数 "all",用于签到所有群聊
|
||||
* Ban提醒提供cd
|
||||
* 本地图库提供配置项SHOW_ID,用于设置发送图片时是否显示id
|
||||
* 色图和PIX提供配置项SHOW_INFO,用于设置发送图片时是否显示图片信息
|
||||
* 所有被动技能提供了进群默认状态配置项
|
||||
* 修复添加权限第二种添加形式无法正确添加正确的权限
|
||||
* 修复签到获取好感度卡时金币不会增加
|
||||
* 修复当红包数量不合法时依旧扣除金币
|
||||
* 修复金币红包再次使用塞红包时无法正确退回上次未开完的金币
|
||||
* 修复 滴滴滴- 只包含图片时不会发送至管理员
|
||||
* 修复添加权限等级错误
|
||||
* 修复群词条以bot名称为开头时无法正确触发
|
||||
* 修改了权限插件加载顺序防止小概率优先加载权限插件引起报错
|
||||
* 本地图库新图库会统一建立在resource/img/image_management文件夹下,如果该文件夹内未找到图库,会从上级目录查找(即:resource/img/)
|
||||
|
||||
<br>
|
||||
|
||||
__..... 更多更新信息请查看文档__
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__: v0.1.6.3-fix1
|
||||
__version__: v0.1.6.5
|
||||
|
||||
@@ -23,7 +23,7 @@ except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
async def group_current_status(group_id: int) -> str:
|
||||
def group_current_status(group_id: int) -> str:
|
||||
"""
|
||||
获取当前所有通知的开关
|
||||
:param group_id: 群号
|
||||
@@ -31,17 +31,17 @@ async def group_current_status(group_id: int) -> str:
|
||||
rst = "[被动技能 状态]\n"
|
||||
_data = group_manager.get_task_data()
|
||||
for task in _data.keys():
|
||||
rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n'
|
||||
rst += f'{_data[task]}: {"√" if group_manager.check_group_task_status(group_id, task) else "×"}\n'
|
||||
return rst.strip()
|
||||
|
||||
|
||||
custom_welcome_msg_json = (
|
||||
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
|
||||
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
|
||||
)
|
||||
|
||||
|
||||
async def custom_group_welcome(
|
||||
msg: str, imgs: List[str], user_id: int, group_id: int
|
||||
msg: str, imgs: List[str], user_id: int, group_id: int
|
||||
) -> str:
|
||||
"""
|
||||
替换群欢迎消息
|
||||
@@ -87,13 +87,13 @@ task_data = None
|
||||
|
||||
|
||||
async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
global task_data
|
||||
"""
|
||||
修改群功能状态
|
||||
:param cmd: 功能名称
|
||||
:param group_id: 群号
|
||||
:param is_super: 是否位超级用户,超级用户用于私聊开关功能状态
|
||||
"""
|
||||
global task_data
|
||||
if not task_data:
|
||||
task_data = group_manager.get_task_data()
|
||||
group_help_file = DATA_PATH / "group_help" / f"{group_id}.png"
|
||||
@@ -104,43 +104,44 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
if cmd == "全部被动":
|
||||
for task in task_data:
|
||||
if status == "开启":
|
||||
if not await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.open_group_task(group_id, task)
|
||||
if not group_manager.check_group_task_status(group_id, task):
|
||||
group_manager.open_group_task(group_id, task)
|
||||
else:
|
||||
if await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.close_group_task(group_id, task)
|
||||
if group_manager.check_group_task_status(group_id, task):
|
||||
group_manager.close_group_task(group_id, task)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
return f"已 {status} 全部被动技能!"
|
||||
if cmd == "全部功能":
|
||||
for f in plugins2settings_manager.get_data():
|
||||
if status == "开启":
|
||||
group_manager.unblock_plugin(f, group_id)
|
||||
group_manager.unblock_plugin(f, group_id, False)
|
||||
else:
|
||||
group_manager.block_plugin(f, group_id)
|
||||
group_manager.block_plugin(f, group_id, False)
|
||||
group_manager.save()
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
return f"已 {status} 全部功能!"
|
||||
if cmd in [task_data[x] for x in task_data.keys()]:
|
||||
if cmd.lower() in [task_data[x].lower() for x in task_data.keys()]:
|
||||
type_ = "task"
|
||||
modules = [x for x in task_data.keys() if task_data[x] == cmd]
|
||||
modules = [x for x in task_data.keys() if task_data[x].lower() == cmd.lower()]
|
||||
for module in modules:
|
||||
if is_super:
|
||||
module = f"{module}:super"
|
||||
if status == "开启":
|
||||
if type_ == "task":
|
||||
if await group_manager.check_group_task_status(group_id, module):
|
||||
if group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
|
||||
await group_manager.open_group_task(group_id, module)
|
||||
group_manager.open_group_task(group_id, module)
|
||||
else:
|
||||
if group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于开启状态!不要重复开启."
|
||||
group_manager.unblock_plugin(module, group_id)
|
||||
else:
|
||||
if type_ == "task":
|
||||
if not await group_manager.check_group_task_status(group_id, module):
|
||||
if not group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
|
||||
await group_manager.close_group_task(group_id, module)
|
||||
group_manager.close_group_task(group_id, module)
|
||||
else:
|
||||
if not group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
|
||||
@@ -197,17 +198,17 @@ def _get_plugin_status() -> MessageSegment:
|
||||
flag = plugins_manager.get_plugin_block_type(module)
|
||||
flag = flag.upper() + " CLOSE" if flag else "OPEN"
|
||||
try:
|
||||
plugin_name = plugins_manager.get(module)["plugin_name"]
|
||||
plugin_name = plugins_manager.get(module).plugin_name
|
||||
if (
|
||||
"[Hidden]" in plugin_name
|
||||
or "[Admin]" in plugin_name
|
||||
or "[Superuser]" in plugin_name
|
||||
"[Hidden]" in plugin_name
|
||||
or "[Admin]" in plugin_name
|
||||
or "[Superuser]" in plugin_name
|
||||
):
|
||||
continue
|
||||
rst += f"{plugin_name}"
|
||||
except KeyError:
|
||||
rst += f"{module}"
|
||||
if plugins_manager.get(module)["error"]:
|
||||
if plugins_manager.get(module).error:
|
||||
rst += "[ERROR]"
|
||||
rst += "\n"
|
||||
flag_str += f"{flag}\n"
|
||||
@@ -238,12 +239,12 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
|
||||
async with db.transaction():
|
||||
# 更新权限
|
||||
if (
|
||||
user_info["role"]
|
||||
in [
|
||||
"owner",
|
||||
"admin",
|
||||
]
|
||||
and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
|
||||
user_info["role"]
|
||||
in [
|
||||
"owner",
|
||||
"admin",
|
||||
]
|
||||
and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
|
||||
):
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"],
|
||||
@@ -272,10 +273,10 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
if await GroupInfoUser.add_member_info(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
nickname,
|
||||
join_time,
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
nickname,
|
||||
join_time,
|
||||
):
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
@@ -317,7 +318,4 @@ def set_group_bot_status(group_id: int, status: bool) -> str:
|
||||
return "呜..醒来了..."
|
||||
else:
|
||||
group_manager.shutdown_group_bot_status(group_id)
|
||||
# for x in group_manager.get_task_data():
|
||||
# group_manager.close_group_task(group_id, x)
|
||||
return "那我先睡觉了..."
|
||||
|
||||
|
||||
@@ -2,18 +2,23 @@ from nonebot.adapters.onebot.v11 import Event
|
||||
from utils.manager import group_manager, plugins2settings_manager
|
||||
from utils.utils import get_message_text
|
||||
from services.log import logger
|
||||
import time
|
||||
|
||||
cmd = []
|
||||
|
||||
v = time.time()
|
||||
|
||||
|
||||
def switch_rule(event: Event) -> bool:
|
||||
"""
|
||||
检测文本是否是关闭功能命令
|
||||
:param event: pass
|
||||
说明:
|
||||
检测文本是否是关闭功能命令
|
||||
参数:
|
||||
:param event: pass
|
||||
"""
|
||||
global cmd
|
||||
try:
|
||||
if not cmd:
|
||||
if not cmd or time.time() - v > 60 * 60:
|
||||
cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"]
|
||||
_data = group_manager.get_task_data()
|
||||
for key in _data:
|
||||
@@ -22,10 +27,10 @@ def switch_rule(event: Event) -> bool:
|
||||
cmd.append(f"开启 {_data[key]}")
|
||||
cmd.append(f"关闭 {_data[key]}")
|
||||
_data = plugins2settings_manager.get_data()
|
||||
for key in _data:
|
||||
for key in _data.keys():
|
||||
try:
|
||||
if isinstance(_data[key]["cmd"], list):
|
||||
for x in _data[key]["cmd"]:
|
||||
if isinstance(_data[key].cmd, list):
|
||||
for x in _data[key].cmd:
|
||||
cmd.append(f"开启{x}")
|
||||
cmd.append(f"关闭{x}")
|
||||
cmd.append(f"开启 {x}")
|
||||
|
||||
@@ -110,7 +110,7 @@ async def _():
|
||||
|
||||
@group_task_status.handle()
|
||||
async def _(event: GroupMessageEvent):
|
||||
await group_task_status.send(await group_current_status(event.group_id))
|
||||
await group_task_status.send(group_current_status(event.group_id))
|
||||
|
||||
|
||||
@group_status.handle()
|
||||
|
||||
@@ -16,9 +16,9 @@ admin_help_image = IMAGE_PATH / 'admin_help_img.png'
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def init_task(bot: Bot = None):
|
||||
async def init_task():
|
||||
if not group_manager.get_task_data():
|
||||
await group_manager.init_group_task()
|
||||
group_manager.load_task()
|
||||
logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.')
|
||||
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
gl = [
|
||||
g["group_id"]
|
||||
for g in gl
|
||||
if await group_manager.check_group_task_status(g["group_id"], "broadcast")
|
||||
if group_manager.check_group_task_status(g["group_id"], "broadcast")
|
||||
]
|
||||
g_cnt = len(gl)
|
||||
cnt = 0
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from .utils import group_image, build_help_image
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.manager import (
|
||||
@@ -6,14 +7,11 @@ from utils.manager import (
|
||||
plugins_manager,
|
||||
group_manager,
|
||||
)
|
||||
from typing import Optional
|
||||
from typing import Optional, List, Tuple
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
from utils.utils import get_matchers
|
||||
import random
|
||||
import asyncio
|
||||
import nonebot
|
||||
import os
|
||||
|
||||
|
||||
random_bk_path = IMAGE_PATH / "background" / "help" / "simple_help"
|
||||
@@ -30,12 +28,10 @@ async def create_help_img(
|
||||
:param help_image: 图片路径
|
||||
:param simple_help_image: 简易帮助图片路径
|
||||
"""
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
None, _create_help_img, group_id, help_image, simple_help_image
|
||||
)
|
||||
return await _create_help_img(group_id, help_image, simple_help_image)
|
||||
|
||||
|
||||
def _create_help_img(
|
||||
async def _create_help_img(
|
||||
group_id: Optional[int], help_image: Path, simple_help_image: Path
|
||||
):
|
||||
"""
|
||||
@@ -44,22 +40,20 @@ def _create_help_img(
|
||||
:param help_image: 图片路径
|
||||
:param simple_help_image: 简易帮助图片路径
|
||||
"""
|
||||
_matchers = get_matchers(True)
|
||||
width = 0
|
||||
matchers_data = {}
|
||||
_des_tmp = {}
|
||||
_plugin_name_tmp = []
|
||||
_tmp = []
|
||||
tmp_img = BuildImage(0, 0, plain_text="1", font_size=24)
|
||||
font_height = tmp_img.h
|
||||
# 插件分类
|
||||
for matcher in _matchers:
|
||||
for matcher in get_matchers(True):
|
||||
plugin_name = None
|
||||
_plugin = matcher.plugin
|
||||
metadata = _plugin.metadata
|
||||
if not _plugin:
|
||||
logger.warning(f"获取 功能:{matcher.plugin_name} 失败...")
|
||||
continue
|
||||
metadata = _plugin.metadata
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = metadata.name if metadata else _module.__getattribute__("__zx_plugin_name__")
|
||||
@@ -71,7 +65,6 @@ def _create_help_img(
|
||||
"[hidden]" in plugin_name.lower()
|
||||
or "[admin]" in plugin_name.lower()
|
||||
or "[superuser]" in plugin_name.lower()
|
||||
or plugin_name in _plugin_name_tmp
|
||||
or plugin_name == "帮助"
|
||||
):
|
||||
continue
|
||||
@@ -79,11 +72,9 @@ def _create_help_img(
|
||||
text_type = 0
|
||||
if plugins2settings_manager.get(
|
||||
matcher.plugin_name
|
||||
) and plugins2settings_manager[matcher.plugin_name].get("plugin_type"):
|
||||
) and plugins2settings_manager.get(matcher.plugin_name).plugin_type:
|
||||
plugin_type = tuple(
|
||||
plugins2settings_manager.get_plugin_data(matcher.plugin_name)[
|
||||
"plugin_type"
|
||||
]
|
||||
plugins2settings_manager.get_plugin_data(matcher.plugin_name).plugin_type
|
||||
)
|
||||
else:
|
||||
try:
|
||||
@@ -132,10 +123,7 @@ def _create_help_img(
|
||||
if plugin_des not in _des_tmp:
|
||||
_des_tmp[plugin_des] = plugin_name
|
||||
except AttributeError as e:
|
||||
if plugin_name not in _plugin_name_tmp:
|
||||
logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e:{e}")
|
||||
if plugin_name not in _plugin_name_tmp:
|
||||
_plugin_name_tmp.append(plugin_name)
|
||||
logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e:{e}")
|
||||
help_img_list = []
|
||||
simple_help_img_list = []
|
||||
types = list(matchers_data.keys())
|
||||
@@ -257,22 +245,8 @@ def _create_help_img(
|
||||
if img.h > height:
|
||||
height = img.h
|
||||
width += img.w + 10
|
||||
B = BuildImage(width + 100, height + 250, font_size=24)
|
||||
width, _ = get_max_width_or_paste(simple_help_img_list, B)
|
||||
bk = None
|
||||
random_bk = os.listdir(random_bk_path)
|
||||
if random_bk:
|
||||
bk = random.choice(random_bk)
|
||||
x = max(width + 50, height + 250)
|
||||
B = BuildImage(
|
||||
x,
|
||||
x,
|
||||
font_size=24,
|
||||
color="#FFEFD5",
|
||||
background=random_bk_path / bk,
|
||||
)
|
||||
B.filter("GaussianBlur", 10)
|
||||
_, B = get_max_width_or_paste(simple_help_img_list, B, True)
|
||||
image_group, h = group_image(simple_help_img_list)
|
||||
B = await build_help_image(image_group, h)
|
||||
w = 10
|
||||
h = 10
|
||||
for msg in ["目前支持的功能列表:", "可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法", "或者使用 ‘详细帮助’ 来获取所有功能方法"]:
|
||||
@@ -302,45 +276,13 @@ def _create_help_img(
|
||||
B.save(simple_help_image)
|
||||
|
||||
|
||||
def get_max_width_or_paste(
|
||||
simple_help_img_list: list, B: BuildImage = None, is_paste: bool = False
|
||||
) -> "int, BuildImage":
|
||||
"""
|
||||
获取最大宽度,或直接贴图
|
||||
:param simple_help_img_list: 简单帮助图片列表
|
||||
:param B: 背景图
|
||||
:param is_paste: 是否直接贴图
|
||||
"""
|
||||
current_width = 50
|
||||
current_height = 180
|
||||
max_width = simple_help_img_list[0].w
|
||||
for i in range(len(simple_help_img_list)):
|
||||
try:
|
||||
if is_paste and B:
|
||||
B.paste(simple_help_img_list[i], (current_width, current_height), True)
|
||||
current_height += simple_help_img_list[i].h + 40
|
||||
if current_height + simple_help_img_list[i + 1].h > B.h - 10:
|
||||
current_height = 180
|
||||
current_width += max_width + 30
|
||||
max_width = 0
|
||||
elif simple_help_img_list[i].w > max_width:
|
||||
max_width = simple_help_img_list[i].w
|
||||
except IndexError:
|
||||
pass
|
||||
if current_width > simple_help_img_list[0].w + 50:
|
||||
current_width += simple_help_img_list[-1].w
|
||||
return current_width, B
|
||||
|
||||
|
||||
def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
|
||||
"""
|
||||
获取功能的帮助信息
|
||||
:param msg: 功能cmd
|
||||
:param is_super: 是否为超级用户
|
||||
"""
|
||||
module = plugins2settings_manager.get_plugin_module(msg)
|
||||
if not module:
|
||||
module = admin_manager.get_plugin_module(msg)
|
||||
module = plugins2settings_manager.get_plugin_module(msg) or admin_manager.get_plugin_module(msg)
|
||||
if module:
|
||||
try:
|
||||
plugin = nonebot.plugin.get_plugin(module)
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
from typing import List, Tuple
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.image_utils import BuildImage
|
||||
import os
|
||||
import random
|
||||
|
||||
|
||||
background_path = IMAGE_PATH / "background" / "help" / "simple_help"
|
||||
|
||||
|
||||
async def build_help_image(image_group: List[List[BuildImage]], h: int):
|
||||
bk = None
|
||||
random_bk = os.listdir(background_path)
|
||||
if random_bk:
|
||||
bk = random.choice(random_bk)
|
||||
A = BuildImage(
|
||||
h,
|
||||
h,
|
||||
font_size=24,
|
||||
color="#FFEFD5",
|
||||
background=(background_path / bk) if bk else None,
|
||||
)
|
||||
curr_w = 50
|
||||
for ig in image_group:
|
||||
curr_h = 180
|
||||
for img in ig:
|
||||
await A.apaste(img, (curr_w, curr_h), True)
|
||||
curr_h += img.h + 10
|
||||
curr_w += max([x.w for x in ig]) + 30
|
||||
return A
|
||||
|
||||
|
||||
def group_image(image_list: List[BuildImage]) -> Tuple[List[List[BuildImage]], int]:
|
||||
"""
|
||||
说明:
|
||||
根据图片大小进行分组
|
||||
参数:
|
||||
:param image_list: 排序图片列表
|
||||
"""
|
||||
image_list.sort(key=lambda x: x.h, reverse=True)
|
||||
max_image = max(image_list, key=lambda x: x.h)
|
||||
|
||||
image_list.remove(max_image)
|
||||
max_h = max_image.h
|
||||
total_w = 0
|
||||
|
||||
# 图片分组
|
||||
image_group = [[max_image]]
|
||||
is_use = []
|
||||
surplus_list = image_list[:]
|
||||
|
||||
for image in image_list:
|
||||
if image.uid not in is_use:
|
||||
group = [image]
|
||||
is_use.append(image.uid)
|
||||
curr_h = image.h
|
||||
while True:
|
||||
surplus_list = [x for x in surplus_list if x.uid not in is_use]
|
||||
for tmp in surplus_list:
|
||||
temp_h = curr_h + tmp.h + 10
|
||||
if temp_h < max_h or abs(max_h - temp_h) < 100:
|
||||
curr_h += tmp.h + 15
|
||||
is_use.append(tmp.uid)
|
||||
group.append(tmp)
|
||||
break
|
||||
else:
|
||||
break
|
||||
total_w += max([x.w for x in group]) + 15
|
||||
image_group.append(group)
|
||||
while surplus_list:
|
||||
surplus_list = [x for x in surplus_list if x.uid not in is_use]
|
||||
if not surplus_list:
|
||||
break
|
||||
surplus_list.sort(key=lambda x: x.h, reverse=True)
|
||||
for img in surplus_list:
|
||||
if img.uid not in is_use:
|
||||
_w = 0
|
||||
index = -1
|
||||
for i, ig in enumerate(image_group):
|
||||
if s := sum([x.h for x in ig]) > _w:
|
||||
_w = s
|
||||
index = i
|
||||
if index != -1:
|
||||
image_group[index].append(img)
|
||||
is_use.append(img.uid)
|
||||
max_h = 0
|
||||
max_w = 0
|
||||
for i, ig in enumerate(image_group):
|
||||
if (_h := sum([x.h + 15 for x in ig])) > max_h:
|
||||
max_h = _h
|
||||
max_w += max([x.w for x in ig]) + 30
|
||||
is_use.clear()
|
||||
while abs(max_h - max_w) > 200 and len(image_group) - 1 >= len(image_group[-1]):
|
||||
for img in image_group[-1]:
|
||||
_min_h = 0
|
||||
_min_index = -1
|
||||
for i, ig in enumerate(image_group):
|
||||
if i not in is_use and (_h := sum([x.h for x in ig]) + img.h) > _min_h:
|
||||
_min_h = _h
|
||||
_min_index = i
|
||||
is_use.append(_min_index)
|
||||
image_group[_min_index].append(img)
|
||||
max_w -= max([x.w for x in image_group[-1]])
|
||||
image_group.pop(-1)
|
||||
return image_group, max(max_h + 250, max_w + 70)
|
||||
@@ -1,5 +1,37 @@
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent
|
||||
from utils.manager import plugins2block_manager, StaticData
|
||||
from typing import Optional
|
||||
|
||||
import nonebot
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
GroupMessageEvent,
|
||||
PrivateMessageEvent,
|
||||
Bot,
|
||||
Event,
|
||||
MessageEvent,
|
||||
Message,
|
||||
PokeNotifyEvent,
|
||||
)
|
||||
from nonebot.exception import ActionFailed, IgnoredException
|
||||
from nonebot.internal.matcher import Matcher
|
||||
|
||||
from models.bag_user import BagUser
|
||||
from models.ban_user import BanUser
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.level_user import LevelUser
|
||||
from models.user_shop_gold_log import UserShopGoldLog
|
||||
from utils.manager import (
|
||||
plugins2block_manager,
|
||||
StaticData,
|
||||
plugins2settings_manager,
|
||||
group_manager,
|
||||
admin_manager,
|
||||
plugins_manager,
|
||||
plugins2cd_manager,
|
||||
plugins2count_manager,
|
||||
)
|
||||
from utils.message_builder import at
|
||||
from utils.utils import FreqLimiter
|
||||
from configs.config import Config
|
||||
import time
|
||||
|
||||
ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
@@ -8,7 +40,6 @@ other_limit_plugins = ["poke"]
|
||||
|
||||
|
||||
class StatusMessageManager(StaticData):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
|
||||
@@ -39,8 +70,8 @@ def set_block_limit_false(event, module):
|
||||
"""
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
check_type = plugin_block_data.check_type
|
||||
limit_type = plugin_block_data.limit_type
|
||||
if not (
|
||||
(isinstance(event, GroupMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, PrivateMessageEvent) and check_type == "group")
|
||||
@@ -50,3 +81,436 @@ def set_block_limit_false(event, module):
|
||||
block_type_ = event.group_id
|
||||
plugins2block_manager.set_false(block_type_, module)
|
||||
|
||||
|
||||
async def send_msg(msg: str, bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
说明:
|
||||
发送信息
|
||||
参数:
|
||||
:param msg: pass
|
||||
:param bot: pass
|
||||
:param event: pass
|
||||
"""
|
||||
if "[uname]" in msg:
|
||||
uname = event.sender.card or event.sender.nickname
|
||||
msg = msg.replace("[uname]", uname)
|
||||
if "[nickname]" in msg:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
else:
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
msg = msg.replace("[nickname]", nickname)
|
||||
if "[at]" in msg and isinstance(event, GroupMessageEvent):
|
||||
msg = msg.replace("[at]", str(at(event.user_id)))
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
status_message_manager.add(event.group_id)
|
||||
await bot.send_group_msg(group_id=event.group_id, message=Message(msg))
|
||||
else:
|
||||
status_message_manager.add(event.user_id)
|
||||
await bot.send_private_msg(user_id=event.user_id, message=Message(msg))
|
||||
except ActionFailed:
|
||||
pass
|
||||
|
||||
|
||||
class ReturnException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AuthChecker:
|
||||
"""
|
||||
权限检查
|
||||
"""
|
||||
|
||||
checker: Optional["AuthChecker"] = None
|
||||
|
||||
def __init__(self):
|
||||
self._flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
self._flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
self._flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
self._flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if not cls.checker:
|
||||
cls.checker = super().__new__(cls)
|
||||
return cls.checker
|
||||
|
||||
async def auth(self, matcher: Matcher, bot: Bot, event: Event):
|
||||
"""
|
||||
说明:
|
||||
权限检查
|
||||
参数:
|
||||
:param matcher: matcher
|
||||
:param bot: bot
|
||||
:param event: event
|
||||
"""
|
||||
try:
|
||||
plugin_name = matcher.plugin_name
|
||||
cost_gold = await self.auth_cost(plugin_name, bot, event)
|
||||
await self.auth_basic(plugin_name, bot, event)
|
||||
self.auth_group(plugin_name, bot, event)
|
||||
await self.auth_admin(plugin_name, matcher, bot, event)
|
||||
await self.auth_plugin(plugin_name, matcher, bot, event)
|
||||
await self.auth_limit(plugin_name, bot, event)
|
||||
if cost_gold and str(event.user_id) not in bot.config.superusers:
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
except ReturnException:
|
||||
return
|
||||
|
||||
async def auth_limit(self, plugin_name: str, bot: Bot, event: Event):
|
||||
"""
|
||||
说明:
|
||||
插件限制
|
||||
参数:
|
||||
:param plugin_name: 模块名
|
||||
:param bot: bot
|
||||
:param event: event
|
||||
"""
|
||||
if plugins2cd_manager.check_plugin_cd_status(plugin_name):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(plugin_name)
|
||||
check_type = plugin_cd_data.check_type
|
||||
limit_type = plugin_cd_data.limit_type
|
||||
msg = plugin_cd_data.rst
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(plugin_name).check_type == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(plugin_name, cd_type_):
|
||||
if msg:
|
||||
await send_msg(msg, bot, event)
|
||||
raise IgnoredException(f"{plugin_name} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(plugin_name, cd_type_)
|
||||
# Block
|
||||
if plugins2block_manager.check_plugin_block_status(plugin_name):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(plugin_name)
|
||||
check_type = plugin_block_data.check_type
|
||||
limit_type = plugin_block_data.limit_type
|
||||
msg = plugin_block_data.rst
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or check_type == "all"
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
if plugins2block_manager.check(block_type_, plugin_name):
|
||||
if msg:
|
||||
await send_msg(msg, bot, event)
|
||||
raise IgnoredException(f"{event.user_id}正在调用{plugin_name}....")
|
||||
else:
|
||||
plugins2block_manager.set_true(block_type_, plugin_name)
|
||||
# Count
|
||||
if (
|
||||
plugins2count_manager.check_plugin_count_status(plugin_name)
|
||||
and event.user_id not in bot.config.superusers
|
||||
):
|
||||
plugin_count_data = plugins2count_manager.get_plugin_count_data(plugin_name)
|
||||
limit_type = plugin_count_data.limit_type
|
||||
msg = plugin_count_data.rst
|
||||
count_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
count_type_ = event.group_id
|
||||
if not plugins2count_manager.check(plugin_name, count_type_):
|
||||
if msg:
|
||||
await send_msg(msg, bot, event)
|
||||
raise IgnoredException(f"{plugin_name} count次数限制...")
|
||||
else:
|
||||
plugins2count_manager.increase(plugin_name, count_type_)
|
||||
|
||||
async def auth_plugin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
|
||||
"""
|
||||
说明:
|
||||
插件状态
|
||||
参数:
|
||||
:param plugin_name: 模块名
|
||||
:param matcher: matcher
|
||||
:param bot: bot
|
||||
:param event: event
|
||||
"""
|
||||
if plugin_name in plugins2settings_manager.keys() and matcher.priority not in [
|
||||
1,
|
||||
999,
|
||||
]:
|
||||
# 戳一戳单独判断
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
or isinstance(event, PokeNotifyEvent)
|
||||
or matcher.plugin_name in other_limit_plugins
|
||||
):
|
||||
if status_message_manager.get(event.group_id) is None:
|
||||
status_message_manager.delete(event.group_id)
|
||||
if plugins2settings_manager[
|
||||
plugin_name
|
||||
].level > group_manager.get_group_level(event.group_id):
|
||||
try:
|
||||
if (
|
||||
self._flmt_g.check(event.user_id)
|
||||
and plugin_name not in ignore_rst_module
|
||||
):
|
||||
self._flmt_g.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="群权限不足..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, plugin_name)
|
||||
raise IgnoredException("群权限不足")
|
||||
# 插件状态
|
||||
if not group_manager.get_plugin_status(plugin_name, event.group_id):
|
||||
try:
|
||||
if plugin_name not in ignore_rst_module and self._flmt_s.check(
|
||||
event.group_id
|
||||
):
|
||||
self._flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="该群未开启此功能.."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, plugin_name)
|
||||
raise IgnoredException("未开启此功能...")
|
||||
# 管理员禁用
|
||||
if not group_manager.get_plugin_status(
|
||||
f"{plugin_name}:super", event.group_id
|
||||
):
|
||||
try:
|
||||
if (
|
||||
self._flmt_s.check(event.group_id)
|
||||
and plugin_name not in ignore_rst_module
|
||||
):
|
||||
self._flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="管理员禁用了此群该功能..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, plugin_name)
|
||||
raise IgnoredException("管理员禁用了此群该功能...")
|
||||
# 群聊禁用
|
||||
if not plugins_manager.get_plugin_status(
|
||||
plugin_name, block_type="group"
|
||||
):
|
||||
try:
|
||||
if (
|
||||
self._flmt_c.check(event.group_id)
|
||||
and plugin_name not in ignore_rst_module
|
||||
):
|
||||
self._flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="该功能在群聊中已被禁用..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, plugin_name)
|
||||
raise IgnoredException("该插件在群聊中已被禁用...")
|
||||
else:
|
||||
# 私聊禁用
|
||||
if not plugins_manager.get_plugin_status(
|
||||
plugin_name, block_type="private"
|
||||
):
|
||||
try:
|
||||
if self._flmt_c.check(event.user_id):
|
||||
self._flmt_c.start_cd(event.user_id)
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id, message="该功能在私聊中已被禁用..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.user_id)
|
||||
set_block_limit_false(event, plugin_name)
|
||||
raise IgnoredException("该插件在私聊中已被禁用...")
|
||||
# 维护
|
||||
if not plugins_manager.get_plugin_status(plugin_name, block_type="all"):
|
||||
if isinstance(
|
||||
event, GroupMessageEvent
|
||||
) and group_manager.check_group_is_white(event.group_id):
|
||||
raise ReturnException()
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if (
|
||||
self._flmt_c.check(event.group_id)
|
||||
and plugin_name not in ignore_rst_module
|
||||
):
|
||||
self._flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="此功能正在维护..."
|
||||
)
|
||||
else:
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id, message="此功能正在维护..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
id_ = (
|
||||
event.group_id
|
||||
if isinstance(event, GroupMessageEvent)
|
||||
else event.user_id
|
||||
)
|
||||
status_message_manager.add(id_)
|
||||
set_block_limit_false(event, plugin_name)
|
||||
raise IgnoredException("此功能正在维护...")
|
||||
|
||||
async def auth_admin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
|
||||
"""
|
||||
说明:
|
||||
管理员命令 个人权限
|
||||
参数:
|
||||
:param plugin_name: 模块名
|
||||
:param matcher: matcher
|
||||
:param bot: bot
|
||||
:param event: event
|
||||
"""
|
||||
if plugin_name in admin_manager.keys() and matcher.priority not in [1, 999]:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
# 个人权限
|
||||
if (
|
||||
not await LevelUser.check_level(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
admin_manager.get_plugin_level(plugin_name),
|
||||
)
|
||||
and admin_manager.get_plugin_level(plugin_name) > 0
|
||||
):
|
||||
try:
|
||||
if self._flmt.check(event.user_id):
|
||||
self._flmt.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
|
||||
f"{admin_manager.get_plugin_level(plugin_name)}",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
set_block_limit_false(event, plugin_name)
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
raise IgnoredException("权限不足")
|
||||
else:
|
||||
if not await LevelUser.check_level(
|
||||
event.user_id, 0, admin_manager.get_plugin_level(plugin_name)
|
||||
):
|
||||
try:
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id,
|
||||
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(plugin_name)}",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
set_block_limit_false(event, plugin_name)
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.user_id)
|
||||
raise IgnoredException("权限不足")
|
||||
|
||||
def auth_group(self, plugin_name: str, bot: Bot, event: Event):
|
||||
"""
|
||||
说明:
|
||||
群黑名单检测 群总开关检测
|
||||
参数:
|
||||
:param plugin_name: 模块名
|
||||
:param bot: bot
|
||||
:param event: event
|
||||
"""
|
||||
if isinstance(event, GroupMessageEvent) or plugin_name in other_limit_plugins:
|
||||
try:
|
||||
if (
|
||||
group_manager.get_group_level(event.group_id) < 0
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
raise IgnoredException("群黑名单")
|
||||
if not group_manager.check_group_bot_status(event.group_id):
|
||||
try:
|
||||
if str(event.get_message()) != "醒来":
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except ValueError:
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
async def auth_basic(self, plugin_name: str, bot: Bot, event: Event):
|
||||
"""
|
||||
说明:
|
||||
检测是否满足超级用户权限,是否被ban等
|
||||
参数:
|
||||
:param plugin_name: 模块名
|
||||
:param bot: bot
|
||||
:param event: event
|
||||
"""
|
||||
ban = await BanUser.is_ban(event.user_id)
|
||||
try:
|
||||
if (
|
||||
(
|
||||
not isinstance(event, MessageEvent)
|
||||
and plugin_name not in other_limit_plugins
|
||||
)
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
) or (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2settings_manager.get_plugin_data(plugin_name)
|
||||
and not plugins2settings_manager.get_plugin_data(
|
||||
plugin_name
|
||||
).limit_superuser
|
||||
):
|
||||
raise ReturnException()
|
||||
_plugin = nonebot.plugin.get_plugin(plugin_name)
|
||||
_module = _plugin.module
|
||||
_plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if (
|
||||
"[superuser]" in _plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
):
|
||||
raise ReturnException()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
async def auth_cost(self, plugin_name: str, bot: Bot, event: Event) -> int:
|
||||
"""
|
||||
说明:
|
||||
检测是否满足金币条件
|
||||
参数:
|
||||
:param plugin_name: 模块名
|
||||
:param bot: bot
|
||||
:param event: event
|
||||
"""
|
||||
cost_gold = 0
|
||||
if isinstance(event, GroupMessageEvent) and (
|
||||
psm := plugins2settings_manager.get_plugin_data(plugin_name)
|
||||
):
|
||||
if psm.cost_gold > 0:
|
||||
if (
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
< psm.cost_gold
|
||||
):
|
||||
await send_msg(f"金币不足..该功能需要{psm.cost_gold}金币..", bot, event)
|
||||
raise IgnoredException(f"{plugin_name} 金币限制...")
|
||||
# 当插件不阻塞超级用户时,超级用户提前扣除金币
|
||||
if (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and not psm.limit_superuser
|
||||
):
|
||||
await BagUser.spend_gold(
|
||||
event.user_id, event.group_id, psm.cost_gold
|
||||
)
|
||||
await UserShopGoldLog.add_shop_log(
|
||||
event.user_id, event.group_id, 2, plugin_name, psm.cost_gold, 1
|
||||
)
|
||||
cost_gold = psm.cost_gold
|
||||
return cost_gold
|
||||
|
||||
@@ -1,393 +1,36 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.bag_user import BagUser
|
||||
from utils.manager import (
|
||||
plugins2settings_manager,
|
||||
admin_manager,
|
||||
group_manager,
|
||||
plugins_manager,
|
||||
plugins2cd_manager,
|
||||
plugins2block_manager,
|
||||
plugins2count_manager,
|
||||
)
|
||||
from ._utils import (
|
||||
set_block_limit_false,
|
||||
status_message_manager,
|
||||
ignore_rst_module,
|
||||
other_limit_plugins,
|
||||
)
|
||||
from nonebot.typing import T_State
|
||||
from typing import Optional
|
||||
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
ActionFailed,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
PokeNotifyEvent,
|
||||
PrivateMessageEvent,
|
||||
Message,
|
||||
Event,
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
from utils.utils import FreqLimiter
|
||||
from utils.message_builder import at
|
||||
from models.level_user import LevelUser
|
||||
import nonebot
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, run_postprocessor
|
||||
from nonebot.typing import T_State
|
||||
|
||||
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
from ._utils import (
|
||||
set_block_limit_false,
|
||||
AuthChecker,
|
||||
)
|
||||
|
||||
|
||||
# 权限检测
|
||||
# # 权限检测
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
||||
module = matcher.plugin_name
|
||||
plugins2info_dict = plugins2settings_manager.get_data()
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
cost_gold = 0
|
||||
if isinstance(
|
||||
event, GroupMessageEvent
|
||||
) and plugins2settings_manager.get_plugin_data(module).get("cost_gold"):
|
||||
cost_gold = plugins2settings_manager.get_plugin_data(module).get("cost_gold")
|
||||
if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
|
||||
await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
|
||||
raise IgnoredException(f"{module} 金币限制...")
|
||||
# 当插件不阻塞超级用户时,超级用户提前扣除金币
|
||||
if (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
try:
|
||||
if (
|
||||
(not isinstance(event, MessageEvent) and module not in other_limit_plugins)
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
) or (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
# 超级用户命令
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(module)
|
||||
_module = _plugin.module
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if (
|
||||
"[superuser]" in plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
# 群黑名单检测 群总开关检测
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
or matcher.plugin_name in other_limit_plugins
|
||||
):
|
||||
try:
|
||||
if (
|
||||
group_manager.get_group_level(event.group_id) < 0
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
raise IgnoredException("群黑名单")
|
||||
if not group_manager.check_group_bot_status(event.group_id):
|
||||
try:
|
||||
if str(event.get_message()) != "醒来":
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except ValueError:
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except AttributeError:
|
||||
pass
|
||||
if module in admin_manager.keys() and matcher.priority not in [1, 999]:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
# 个人权限
|
||||
if (
|
||||
not await LevelUser.check_level(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
admin_manager.get_plugin_level(module),
|
||||
)
|
||||
and admin_manager.get_plugin_level(module) > 0
|
||||
):
|
||||
try:
|
||||
if _flmt.check(event.user_id):
|
||||
_flmt.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
|
||||
f"{admin_manager.get_plugin_level(module)}",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
set_block_limit_false(event, module)
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
raise IgnoredException("权限不足")
|
||||
else:
|
||||
if not await LevelUser.check_level(
|
||||
event.user_id, 0, admin_manager.get_plugin_level(module)
|
||||
):
|
||||
try:
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id,
|
||||
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
set_block_limit_false(event, module)
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.user_id)
|
||||
raise IgnoredException("权限不足")
|
||||
if module in plugins2info_dict.keys() and matcher.priority not in [1, 999]:
|
||||
# 戳一戳单独判断
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
or isinstance(event, PokeNotifyEvent)
|
||||
or matcher.plugin_name in other_limit_plugins
|
||||
):
|
||||
if status_message_manager.get(event.group_id) is None:
|
||||
status_message_manager.delete(event.group_id)
|
||||
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
|
||||
event.group_id
|
||||
):
|
||||
try:
|
||||
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
|
||||
_flmt_g.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="群权限不足..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("群权限不足")
|
||||
# 插件状态
|
||||
if not group_manager.get_plugin_status(module, event.group_id):
|
||||
try:
|
||||
if module not in ignore_rst_module and _flmt_s.check(
|
||||
event.group_id
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="该群未开启此功能.."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("未开启此功能...")
|
||||
# 管理员禁用
|
||||
if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
|
||||
try:
|
||||
if (
|
||||
_flmt_s.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="管理员禁用了此群该功能..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("管理员禁用了此群该功能...")
|
||||
# 群聊禁用
|
||||
if not plugins_manager.get_plugin_status(module, block_type="group"):
|
||||
try:
|
||||
if (
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="该功能在群聊中已被禁用..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.group_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("该插件在群聊中已被禁用...")
|
||||
else:
|
||||
# 私聊禁用
|
||||
if not plugins_manager.get_plugin_status(module, block_type="private"):
|
||||
try:
|
||||
if _flmt_c.check(event.user_id):
|
||||
_flmt_c.start_cd(event.user_id)
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id, message="该功能在私聊中已被禁用..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
status_message_manager.add(event.user_id)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("该插件在私聊中已被禁用...")
|
||||
# 维护
|
||||
if not plugins_manager.get_plugin_status(module, block_type="all"):
|
||||
if isinstance(
|
||||
event, GroupMessageEvent
|
||||
) and group_manager.check_group_is_white(event.group_id):
|
||||
return
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if (
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id, message="此功能正在维护..."
|
||||
)
|
||||
else:
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id, message="此功能正在维护..."
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
if event.is_tome():
|
||||
id_ = (
|
||||
event.group_id
|
||||
if isinstance(event, GroupMessageEvent)
|
||||
else event.user_id
|
||||
)
|
||||
status_message_manager.add(id_)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("此功能正在维护...")
|
||||
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# Cd
|
||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||
check_type = plugin_cd_data["check_type"]
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(module, cd_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(module, cd_type_)
|
||||
# Block
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
rst = plugin_block_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or check_type == "all"
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
if plugins2block_manager.check(block_type_, module):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{event.user_id}正在调用{module}....")
|
||||
else:
|
||||
plugins2block_manager.set_true(block_type_, module)
|
||||
# Count
|
||||
if (
|
||||
plugins2count_manager.check_plugin_count_status(module)
|
||||
and event.user_id not in bot.config.superusers
|
||||
):
|
||||
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
|
||||
limit_type = plugin_count_data["limit_type"]
|
||||
rst = plugin_count_data["rst"]
|
||||
count_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
count_type_ = event.group_id
|
||||
if not plugins2count_manager.check(module, count_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} count次数限制...")
|
||||
else:
|
||||
plugins2count_manager.increase(module, count_type_)
|
||||
# 功能花费的金币 #######################################
|
||||
# 功能花费的金币 #######################################
|
||||
if cost_gold:
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
|
||||
|
||||
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
发送信息
|
||||
:param rst: pass
|
||||
:param bot: pass
|
||||
:param event: pass
|
||||
"""
|
||||
rst = await init_rst(rst, event)
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
status_message_manager.add(event.group_id)
|
||||
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
|
||||
else:
|
||||
status_message_manager.add(event.user_id)
|
||||
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
|
||||
except ActionFailed:
|
||||
pass
|
||||
async def _(matcher: Matcher, bot: Bot, event: Event):
|
||||
await AuthChecker().auth(matcher, bot, event)
|
||||
|
||||
|
||||
# 解除命令block阻塞
|
||||
@run_postprocessor
|
||||
async def _(
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception],
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception],
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
):
|
||||
if not isinstance(event, MessageEvent) and matcher.plugin_name != "poke":
|
||||
return
|
||||
module = matcher.plugin_name
|
||||
set_block_limit_false(event, module)
|
||||
|
||||
|
||||
async def init_rst(rst: str, event: MessageEvent):
|
||||
if "[uname]" in rst:
|
||||
uname = event.sender.card or event.sender.nickname
|
||||
rst = rst.replace("[uname]", uname)
|
||||
if "[nickname]" in rst:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
else:
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
rst = rst.replace("[nickname]", nickname)
|
||||
if "[at]" in rst and isinstance(event, GroupMessageEvent):
|
||||
rst = rst.replace("[at]", str(at(event.user_id)))
|
||||
return rst
|
||||
|
||||
@@ -33,11 +33,13 @@ async def _(bot: Bot, api: str, data: Dict[str, Any]):
|
||||
)
|
||||
and r.group(1) in group_manager.get_task_data().keys()
|
||||
):
|
||||
# if bot.self_id in bot.config.superusers:
|
||||
# raise MockApiException(f"禁止社死...")
|
||||
task = r.group(1)
|
||||
group_id = data["group_id"]
|
||||
if group_manager.get_group_level(
|
||||
group_id
|
||||
) < 0 or not await group_manager.check_group_task_status(group_id, task):
|
||||
) < 0 or not group_manager.check_group_task_status(group_id, task):
|
||||
raise MockApiException(f"被动技能 {task} 处于关闭状态...")
|
||||
else:
|
||||
msg = str(data["message"]).strip()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from configs.path_config import DATA_PATH
|
||||
from .init_group_manager import init_group_manager, group_manager
|
||||
from .init_plugins_config import init_plugins_config
|
||||
from .init_plugins_data import init_plugins_data, plugins_manager
|
||||
@@ -12,7 +13,6 @@ from .init_plugins_limit import (
|
||||
from .init import init
|
||||
from .check_plugin_status import check_plugin_status
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from configs.path_config import DATA_PATH
|
||||
from services.log import logger
|
||||
from nonebot import Driver
|
||||
import nonebot
|
||||
@@ -31,23 +31,21 @@ async def _():
|
||||
"""
|
||||
初始化数据
|
||||
"""
|
||||
_flag = False
|
||||
config_file = DATA_PATH / "configs" / "plugins2config.yaml"
|
||||
if not config_file.exists():
|
||||
_flag = True
|
||||
_flag = not config_file.exists()
|
||||
init()
|
||||
init_plugins_settings(DATA_PATH)
|
||||
init_plugins_cd_limit(DATA_PATH)
|
||||
init_plugins_block_limit(DATA_PATH)
|
||||
init_plugins_count_limit(DATA_PATH)
|
||||
init_plugins_data(DATA_PATH)
|
||||
init_plugins_config(DATA_PATH)
|
||||
init_plugins_settings()
|
||||
init_plugins_cd_limit()
|
||||
init_plugins_block_limit()
|
||||
init_plugins_count_limit()
|
||||
init_plugins_data()
|
||||
init_plugins_config()
|
||||
init_plugins_resources()
|
||||
init_none_plugin_count_manager()
|
||||
x = group_manager.get_super_old_data()
|
||||
if x:
|
||||
for key in x.keys():
|
||||
plugins_manager.block_plugin(key, block_type=x[key])
|
||||
# x = group_manager.get_super_old_data()
|
||||
# if x:
|
||||
# for key in x.keys():
|
||||
# plugins_manager.block_plugin(key, block_type=x[key])
|
||||
if _flag:
|
||||
raise Exception("首次运行,已在configs目录下生成配置文件config.yaml,修改后重启即可...")
|
||||
logger.info("初始化数据完成...")
|
||||
@@ -55,5 +53,5 @@ async def _():
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _(bot: Bot):
|
||||
await init_group_manager()
|
||||
# await init_group_manager()
|
||||
await check_plugin_status(bot)
|
||||
|
||||
@@ -6,13 +6,13 @@ async def check_plugin_status(bot: Bot):
|
||||
"""
|
||||
遍历查看插件加载情况
|
||||
"""
|
||||
rst = ""
|
||||
msg = ""
|
||||
for plugin in plugins_manager.keys():
|
||||
data = plugins_manager.get(plugin)
|
||||
if data.get("error") or data.get("error") is None:
|
||||
rst += f'{plugin}:{data["plugin_name"]}\n'
|
||||
if rst:
|
||||
rst = "以下插件加载失败..\n" + rst
|
||||
if not data.error:
|
||||
msg += f'{plugin}:{data.plugin_name}\n'
|
||||
if msg and bot.config.superusers:
|
||||
msg = "以下插件加载失败..\n" + msg
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=rst[:-1]
|
||||
user_id=int(list(bot.config.superusers)[0]), message=msg.strip()
|
||||
)
|
||||
|
||||
@@ -19,36 +19,44 @@ def init_none_plugin_count_manager():
|
||||
"""
|
||||
清除已删除插件数据
|
||||
"""
|
||||
modules = [x.plugin_name for x in get_matchers()]
|
||||
modules = [x.plugin_name for x in get_matchers(True)]
|
||||
plugins_manager_list = list(plugins_manager.keys())
|
||||
for module in plugins_manager_list:
|
||||
if module not in modules or none_plugin_count_manager.check(module):
|
||||
try:
|
||||
plugin_name = plugins_manager.get(module)["plugin_name"]
|
||||
except (AttributeError, KeyError):
|
||||
plugin_name = ""
|
||||
if none_plugin_count_manager.check(module):
|
||||
try:
|
||||
if module not in modules or none_plugin_count_manager.check(module):
|
||||
try:
|
||||
plugins2settings_manager.delete(module)
|
||||
plugins2settings_manager.save()
|
||||
plugins2count_manager.delete(module)
|
||||
plugins2count_manager.save()
|
||||
plugins2cd_manager.delete(module)
|
||||
plugins2cd_manager.save()
|
||||
plugins2block_manager.delete(module)
|
||||
plugins2block_manager.save()
|
||||
plugins_manager.delete(module)
|
||||
plugins_manager.save()
|
||||
# resources_manager.remove_resource(module)
|
||||
none_plugin_count_manager.delete(module)
|
||||
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}")
|
||||
plugin_name = plugins_manager.get(module).plugin_name
|
||||
except (AttributeError, KeyError):
|
||||
plugin_name = ""
|
||||
if none_plugin_count_manager.check(module):
|
||||
try:
|
||||
plugins2settings_manager.delete(module)
|
||||
plugins2count_manager.delete(module)
|
||||
plugins2cd_manager.delete(module)
|
||||
plugins2block_manager.delete(module)
|
||||
plugins_manager.delete(module)
|
||||
plugins_manager.save()
|
||||
# resources_manager.remove_resource(module)
|
||||
none_plugin_count_manager.delete(module)
|
||||
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}"
|
||||
)
|
||||
else:
|
||||
none_plugin_count_manager.add_count(module)
|
||||
logger.info(
|
||||
f"{module}:{plugin_name} 插件疑似已删除,"
|
||||
f"加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,"
|
||||
f"当前次数:{none_plugin_count_manager._data[module]}"
|
||||
)
|
||||
else:
|
||||
none_plugin_count_manager.add_count(module)
|
||||
logger.info(
|
||||
f"{module}:{plugin_name} 插件疑似已删除,加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,当前次数:{none_plugin_count_manager._data[module]}")
|
||||
else:
|
||||
none_plugin_count_manager.reset(module)
|
||||
none_plugin_count_manager.reset(module)
|
||||
except Exception as e:
|
||||
logger.error(f"清除插件数据错误 {type(e)}:{e}")
|
||||
plugins2settings_manager.save()
|
||||
plugins2count_manager.save()
|
||||
plugins2cd_manager.save()
|
||||
plugins2block_manager.save()
|
||||
plugins_manager.save()
|
||||
none_plugin_count_manager.save()
|
||||
|
||||
@@ -8,40 +8,32 @@ from services.log import logger
|
||||
from utils.text_utils import prompt2cn
|
||||
from utils.utils import get_matchers
|
||||
from utils.utils import scheduler
|
||||
from configs.path_config import DATA_PATH
|
||||
from ruamel import yaml
|
||||
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
def init_plugins_config(data_path):
|
||||
def init_plugins_config():
|
||||
"""
|
||||
初始化插件数据配置
|
||||
"""
|
||||
plugins2config_file = data_path / "configs" / "plugins2config.yaml"
|
||||
plugins2config_file = DATA_PATH / "configs" / "plugins2config.yaml"
|
||||
plugins2config_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
_data = {}
|
||||
if plugins2config_file.exists():
|
||||
_data = _yaml.load(open(plugins2config_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers(True)
|
||||
# 优先使用 metadata 数据
|
||||
for matcher in _matchers:
|
||||
for matcher in [matcher for matcher in get_matchers(True) if matcher.plugin and matcher.plugin.module]:
|
||||
_plugin = matcher.plugin
|
||||
if not _plugin:
|
||||
continue
|
||||
metadata = _plugin.metadata
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
continue
|
||||
_module = _plugin.module
|
||||
plugin_version = None
|
||||
if metadata:
|
||||
plugin_version = metadata.extra.get("version")
|
||||
if not plugin_version:
|
||||
try:
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
except AttributeError:
|
||||
pass
|
||||
if not plugin_version and hasattr(_module, "__plugin_version__"):
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
if metadata and metadata.config:
|
||||
plugin_configs = {}
|
||||
for key, value in metadata.config.__fields__.items():
|
||||
@@ -61,7 +53,7 @@ def init_plugins_config(data_path):
|
||||
_data.get(matcher.plugin_name)
|
||||
and _data[matcher.plugin_name].keys() != plugin_configs.keys()
|
||||
)
|
||||
or plugin_version > plugins_manager.get(matcher.plugin_name)["version"]
|
||||
or plugin_version > plugins_manager.get(matcher.plugin_name).version
|
||||
or matcher.plugin_name not in _data.keys()
|
||||
):
|
||||
for key in plugin_configs:
|
||||
@@ -94,16 +86,16 @@ def init_plugins_config(data_path):
|
||||
_data = round_trip_load(open(plugins2config_file, encoding="utf8"))
|
||||
for plugin in _data.keys():
|
||||
try:
|
||||
plugin_name = plugins_manager.get(plugin)["plugin_name"]
|
||||
plugin_name = plugins_manager.get(plugin).plugin_name
|
||||
except (AttributeError, TypeError):
|
||||
plugin_name = plugin
|
||||
_data[plugin].yaml_set_start_comment(plugin_name, indent=2)
|
||||
# 初始化未设置的管理员权限等级
|
||||
for k, v in Config.get_admin_level_data():
|
||||
try:
|
||||
admin_manager.set_admin_level(k, v)
|
||||
except KeyError as e:
|
||||
raise KeyError(f"{e} ****** 请检查是否有插件加载失败 ******")
|
||||
# try:
|
||||
admin_manager.set_admin_level(k, v)
|
||||
# except KeyError as e:
|
||||
# raise KeyError(f"{e} ****** 请检查是否有插件加载失败 ******")
|
||||
# 存完插件基本设置
|
||||
with open(plugins2config_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(
|
||||
@@ -181,7 +173,7 @@ def _replace_config():
|
||||
plugin_name = None
|
||||
if not plugin_name:
|
||||
try:
|
||||
plugin_name = plugins_manager.get(plugin)["plugin_name"]
|
||||
plugin_name = plugins_manager.get(plugin).plugin_name
|
||||
except (AttributeError, TypeError):
|
||||
plugin_name = plugin
|
||||
plugin_name = (
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from pathlib import Path
|
||||
|
||||
from ruamel.yaml import YAML
|
||||
from utils.manager import plugins_manager
|
||||
from utils.utils import get_matchers
|
||||
import nonebot
|
||||
from services.log import logger
|
||||
from configs.path_config import DATA_PATH
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
@@ -13,17 +14,13 @@ except ModuleNotFoundError:
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
def init_plugins_data(data_path):
|
||||
def init_plugins_data():
|
||||
"""
|
||||
初始化插件数据信息
|
||||
"""
|
||||
plugin2data_file = data_path / "manager" / "plugin_manager.json"
|
||||
plugin2data_file = DATA_PATH / "manager" / "plugin_manager.json"
|
||||
plugin2data_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
_data = {}
|
||||
if plugin2data_file.exists():
|
||||
_data = json.load(open(plugin2data_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers(True)
|
||||
for matcher in _matchers:
|
||||
for matcher in get_matchers(True):
|
||||
_plugin = matcher.plugin
|
||||
if not _plugin:
|
||||
continue
|
||||
@@ -31,66 +28,56 @@ def init_plugins_data(data_path):
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
if matcher.plugin_name not in _data.keys():
|
||||
if matcher.plugin_name not in plugins_manager.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.plugin_name, matcher.plugin_name, error=True
|
||||
)
|
||||
else:
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "error", True)
|
||||
plugin_data = plugins_manager.get(matcher.plugin_name)
|
||||
if plugin_data:
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "version", plugin_data.get("version")
|
||||
)
|
||||
plugins_manager[matcher.plugin_name].error = True
|
||||
else:
|
||||
plugin_version = None
|
||||
if metadata:
|
||||
plugin_version = metadata.extra.get("version")
|
||||
if not plugin_version:
|
||||
try:
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
except AttributeError:
|
||||
pass
|
||||
if metadata:
|
||||
plugin_name = metadata.name
|
||||
else:
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
except AttributeError:
|
||||
plugin_name = matcher.plugin_name
|
||||
plugin_author = None
|
||||
if metadata:
|
||||
plugin_author = metadata.extra.get('author')
|
||||
try:
|
||||
plugin_author = _module.__getattribute__("__plugin_author__")
|
||||
except AttributeError:
|
||||
pass
|
||||
if matcher.plugin_name in plugins_manager.keys():
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "error", False)
|
||||
if matcher.plugin_name not in plugins_manager.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.plugin_name,
|
||||
plugin_name=plugin_name,
|
||||
author=plugin_author,
|
||||
version=plugin_version,
|
||||
)
|
||||
# metadata不检测version
|
||||
elif isinstance(plugin_version, str) or plugins_manager[matcher.plugin_name]["version"] is None or (
|
||||
plugin_version is not None
|
||||
and plugin_version > plugins_manager[matcher.plugin_name]["version"]
|
||||
):
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "plugin_name", plugin_name
|
||||
)
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "author", plugin_author)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "version", plugin_version
|
||||
)
|
||||
if matcher.plugin_name in _data.keys():
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
|
||||
)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
|
||||
)
|
||||
plugin_version = None
|
||||
if metadata:
|
||||
plugin_version = metadata.extra.get("version")
|
||||
if not plugin_version and hasattr(_module, "__plugin_version__"):
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
if metadata:
|
||||
plugin_name = metadata.name
|
||||
else:
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
except AttributeError:
|
||||
plugin_name = matcher.plugin_name
|
||||
plugin_author = None
|
||||
if metadata:
|
||||
plugin_author = metadata.extra.get('author')
|
||||
if not plugin_author and hasattr(_module, "__plugin_author__"):
|
||||
plugin_author = _module.__getattribute__("__plugin_author__")
|
||||
if matcher.plugin_name in plugins_manager.keys():
|
||||
plugins_manager[matcher.plugin_name].error = False
|
||||
if matcher.plugin_name not in plugins_manager.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.plugin_name,
|
||||
plugin_name=plugin_name,
|
||||
author=plugin_author,
|
||||
version=plugin_version,
|
||||
)
|
||||
# metadata不检测version
|
||||
elif isinstance(plugin_version, str) or plugins_manager[matcher.plugin_name].version is None or (
|
||||
plugin_version is not None
|
||||
and plugin_version > float(plugins_manager[matcher.plugin_name].version)
|
||||
):
|
||||
plugins_manager[matcher.plugin_name].plugin_name = plugin_name
|
||||
plugins_manager[matcher.plugin_name].author = plugin_author
|
||||
plugins_manager[matcher.plugin_name].version = plugin_version
|
||||
# if matcher.plugin_name in _data.keys():
|
||||
# plugins_manager[matcher.plugin_name].error = _data[matcher.plugin_name]["error"]
|
||||
# plugins_manager.set_module_data(
|
||||
# matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
|
||||
# )
|
||||
# plugins_manager.set_module_data(
|
||||
# matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
|
||||
# )
|
||||
except Exception as e:
|
||||
logger.error(f"插件数据 {matcher.plugin_name} 加载发生错误 {type(e)}:{e}")
|
||||
plugins_manager.save()
|
||||
|
||||
@@ -1,27 +1,21 @@
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
|
||||
from utils.manager import (
|
||||
plugins2cd_manager,
|
||||
plugins2block_manager,
|
||||
plugins2count_manager,
|
||||
)
|
||||
from utils.utils import get_matchers
|
||||
from ruamel import yaml
|
||||
from configs.path_config import DATA_PATH
|
||||
import nonebot
|
||||
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
def init_plugins_cd_limit(data_path):
|
||||
def init_plugins_cd_limit():
|
||||
"""
|
||||
加载 cd 限制
|
||||
"""
|
||||
plugins2cd_file = data_path / "configs" / "plugins2cd.yaml"
|
||||
plugins2cd_file = DATA_PATH / "configs" / "plugins2cd.yaml"
|
||||
plugins2cd_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
for matcher in get_matchers(True):
|
||||
if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
@@ -36,42 +30,19 @@ def init_plugins_cd_limit(data_path):
|
||||
plugins2cd_manager.add_cd_limit(
|
||||
"这是一个示例"
|
||||
)
|
||||
_tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()}
|
||||
with open(plugins2cd_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
_data = round_trip_load(open(plugins2cd_file, encoding="utf8"))
|
||||
_data["PluginCdLimit"].yaml_set_start_comment(
|
||||
"""# 需要cd的功能
|
||||
# 自定义的功能需要cd也可以在此配置
|
||||
# key:模块名称
|
||||
# cd:cd 时长(秒)
|
||||
# status:此限制的开关状态
|
||||
# check_type:'private'/'group'/'all',限制私聊/群聊/全部
|
||||
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次
|
||||
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
# rst 为 "" 或 None 时则不回复
|
||||
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
|
||||
indent=2,
|
||||
)
|
||||
with open(plugins2cd_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
plugins2cd_manager.save()
|
||||
plugins2cd_manager.reload_cd_limit()
|
||||
|
||||
|
||||
def init_plugins_block_limit(data_path):
|
||||
def init_plugins_block_limit():
|
||||
"""
|
||||
加载阻塞限制
|
||||
"""
|
||||
plugins2block_file = data_path / "configs" / "plugins2block.yaml"
|
||||
plugins2block_file = DATA_PATH / "configs" / "plugins2block.yaml"
|
||||
plugins2block_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
for matcher in get_matchers(True):
|
||||
if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_plugin = matcher.plugin
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
|
||||
@@ -84,36 +55,15 @@ def init_plugins_block_limit(data_path):
|
||||
plugins2block_manager.add_block_limit(
|
||||
"这是一个示例"
|
||||
)
|
||||
_tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()}
|
||||
with open(plugins2block_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
_data = round_trip_load(open(plugins2block_file, encoding="utf8"))
|
||||
_data["PluginBlockLimit"].yaml_set_start_comment(
|
||||
"""# 用户调用阻塞
|
||||
# 即 当用户调用此功能还未结束时
|
||||
# 用发送消息阻止用户重复调用此命令直到该命令结束
|
||||
# key:模块名称
|
||||
# status:此限制的开关状态
|
||||
# check_type:'private'/'group'/'all',限制私聊/群聊/全部
|
||||
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
# 示例:'user':阻塞用户,'group':阻塞群聊
|
||||
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
# rst 为 "" 或 None 时则不回复
|
||||
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
|
||||
indent=2,
|
||||
)
|
||||
with open(plugins2block_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
plugins2block_manager.save()
|
||||
plugins2block_manager.reload_block_limit()
|
||||
|
||||
|
||||
def init_plugins_count_limit(data_path):
|
||||
def init_plugins_count_limit():
|
||||
"""
|
||||
加载次数限制
|
||||
"""
|
||||
plugins2count_file = data_path / "configs" / "plugins2count.yaml"
|
||||
plugins2count_file = DATA_PATH / "configs" / "plugins2count.yaml"
|
||||
plugins2count_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
@@ -132,26 +82,5 @@ def init_plugins_count_limit(data_path):
|
||||
plugins2count_manager.add_count_limit(
|
||||
"这是一个示例"
|
||||
)
|
||||
_tmp_data = {"PluginCountLimit": plugins2count_manager.get_data()}
|
||||
with open(plugins2count_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
_data = round_trip_load(open(plugins2count_file, encoding="utf8"))
|
||||
_data["PluginCountLimit"].yaml_set_start_comment(
|
||||
"""# 命令每日次数限制
|
||||
# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
|
||||
# 每日调用直到 00:00 刷新
|
||||
# key:模块名称
|
||||
# max_count: 每日调用上限
|
||||
# status:此限制的开关状态
|
||||
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
# 示例:'user':用户上限,'group':群聊上限
|
||||
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
# rst 为 "" 或 None 时则不回复
|
||||
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
|
||||
indent=2,
|
||||
)
|
||||
with open(plugins2count_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
plugins2count_manager.save()
|
||||
plugins2count_manager.reload_count_limit()
|
||||
|
||||
@@ -1,24 +1,14 @@
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
|
||||
from utils.manager import plugins2settings_manager, admin_manager
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
from ruamel import yaml
|
||||
import nonebot
|
||||
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
def init_plugins_settings(data_path: str):
|
||||
def init_plugins_settings():
|
||||
"""
|
||||
初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
|
||||
"""
|
||||
plugins2settings_file = data_path / "configs" / "plugins2settings.yaml"
|
||||
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_matchers = get_matchers(True)
|
||||
_tmp_module = {}
|
||||
_tmp = []
|
||||
for x in plugins2settings_manager.keys():
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(x)
|
||||
@@ -33,12 +23,10 @@ def init_plugins_settings(data_path: str):
|
||||
except (KeyError, AttributeError) as e:
|
||||
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
|
||||
_tmp_module[x] = ""
|
||||
for matcher in _matchers:
|
||||
for matcher in [x for x in get_matchers(True) if x.plugin]:
|
||||
try:
|
||||
if matcher.plugin_name not in plugins2settings_manager.keys():
|
||||
_plugin = matcher.plugin
|
||||
if not _plugin:
|
||||
continue
|
||||
metadata = _plugin.metadata
|
||||
try:
|
||||
_module = _plugin.module
|
||||
@@ -46,22 +34,17 @@ def init_plugins_settings(data_path: str):
|
||||
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
|
||||
else:
|
||||
try:
|
||||
if metadata:
|
||||
plugin_name = metadata.name
|
||||
else:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
plugin_name = metadata.name if metadata else _module.__getattribute__("__zx_plugin_name__")
|
||||
# 管理员命令
|
||||
if "[admin]" in plugin_name.lower():
|
||||
try:
|
||||
level = 5
|
||||
cmd = None
|
||||
if hasattr(_module, "__plugin_settings__"):
|
||||
admin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
level = admin_settings["admin_level"]
|
||||
level = admin_settings.get("admin_level", 5)
|
||||
cmd = admin_settings.get("cmd")
|
||||
except (AttributeError, KeyError):
|
||||
level = 5
|
||||
cmd = None
|
||||
if level is None:
|
||||
level = 5
|
||||
admin_manager.add_admin_plugin_settings(
|
||||
matcher.plugin_name, cmd, level
|
||||
)
|
||||
@@ -73,19 +56,18 @@ def init_plugins_settings(data_path: str):
|
||||
):
|
||||
continue
|
||||
except AttributeError:
|
||||
if matcher.plugin_name not in _tmp:
|
||||
logger.warning(
|
||||
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||
)
|
||||
logger.warning(
|
||||
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||
)
|
||||
else:
|
||||
_tmp_module[matcher.plugin_name] = plugin_name
|
||||
try:
|
||||
if hasattr(_module, "__plugin_settings__"):
|
||||
plugin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
except AttributeError:
|
||||
else:
|
||||
plugin_settings = {"cmd": [matcher.plugin_name, plugin_name]}
|
||||
if not plugin_settings.get("cost_gold"):
|
||||
if plugin_settings.get("cost_gold") is None:
|
||||
plugin_settings["cost_gold"] = 0
|
||||
if (
|
||||
plugin_settings.get("cmd") is not None
|
||||
@@ -100,12 +82,12 @@ def init_plugins_settings(data_path: str):
|
||||
plugin_type = tuple(
|
||||
plugins2settings_manager.get_plugin_data(
|
||||
matcher.plugin_name
|
||||
)["plugin_type"]
|
||||
).plugin_type
|
||||
)
|
||||
else:
|
||||
try:
|
||||
if hasattr(_module, "__plugin_type__"):
|
||||
plugin_type = _module.__getattribute__("__plugin_type__")
|
||||
except AttributeError:
|
||||
else:
|
||||
plugin_type = ("normal",)
|
||||
if plugin_settings and matcher.plugin_name:
|
||||
plugins2settings_manager.add_plugin_settings(
|
||||
@@ -115,26 +97,5 @@ def init_plugins_settings(data_path: str):
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'{matcher.plugin_name} 初始化 plugin_settings 发生错误 {type(e)}:{e}')
|
||||
_tmp.append(matcher.plugin_name)
|
||||
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
|
||||
with open(plugins2settings_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
_data = round_trip_load(open(plugins2settings_file, encoding="utf8"))
|
||||
_data["PluginSettings"].yaml_set_start_comment(
|
||||
"""# 模块与对应命令和对应群权限
|
||||
# 用于生成帮助图片 和 开关功能
|
||||
# key:模块名称
|
||||
# level:需要的群等级
|
||||
# default_status:加入群时功能的默认开关状态
|
||||
# limit_superuser: 功能状态是否限制超级用户
|
||||
# cmd: 关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称
|
||||
# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1),1代表帮助命令列向排列,否则为横向排列""",
|
||||
indent=2,
|
||||
)
|
||||
for plugin in _data["PluginSettings"].keys():
|
||||
_data["PluginSettings"][plugin].yaml_set_start_comment(
|
||||
f"{plugin}:{_tmp_module[plugin]}", indent=2
|
||||
)
|
||||
with open(plugins2settings_file, "w", encoding="utf8") as wf:
|
||||
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
plugins2settings_manager.save()
|
||||
logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")
|
||||
|
||||
@@ -15,7 +15,7 @@ from configs.path_config import TEXT_PATH
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from typing import List
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.manager import GDict
|
||||
from utils.utils import GDict
|
||||
from utils.utils import scheduler
|
||||
import nonebot
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import nonebot
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
from utils.decorator.shop import shop_register
|
||||
import nonebot
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
@@ -12,3 +16,8 @@ Config.add_plugin_config(
|
||||
|
||||
|
||||
nonebot.load_plugins("basic_plugins/shop")
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _():
|
||||
await shop_register.load_register()
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from nonebot import on_command
|
||||
|
||||
from models.user_shop_gold_log import UserShopGoldLog
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
@@ -46,10 +48,7 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
for x in await GoodsInfo.get_all_goods()
|
||||
if x.goods_limit_time > time.time() or x.goods_limit_time == 0
|
||||
]
|
||||
goods_name_list = [
|
||||
x.goods_name
|
||||
for x in goods_list
|
||||
]
|
||||
goods_name_list = [x.goods_name for x in goods_list]
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
@@ -77,11 +76,15 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num * goods.goods_discount:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
flag, n = await GoodsInfo.check_user_daily_purchase(goods, event.user_id, event.group_id, num)
|
||||
flag, n = await GoodsInfo.check_user_daily_purchase(
|
||||
goods, event.user_id, event.group_id, num
|
||||
)
|
||||
if flag:
|
||||
await buy.finish(f"该次购买将超过每日次数限制,目前该道具还可以购买{n}次哦", at_sender=True)
|
||||
if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
|
||||
await GoodsInfo.add_user_daily_purchase(goods, event.user_id, event.group_id, num)
|
||||
await GoodsInfo.add_user_daily_purchase(
|
||||
goods, event.user_id, event.group_id, num
|
||||
)
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
@@ -90,6 +93,14 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||
)
|
||||
await UserShopGoldLog.add_shop_log(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
0,
|
||||
goods.goods_name,
|
||||
num,
|
||||
goods.goods_price * num * goods.goods_discount,
|
||||
)
|
||||
else:
|
||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||
logger.info(
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
from nonebot import on_command
|
||||
|
||||
from utils.message_builder import image
|
||||
from ._data_source import create_bag_image
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from models.bag_user import BagUser
|
||||
@@ -32,10 +35,11 @@ my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
async def _(event: GroupMessageEvent):
|
||||
props = await BagUser.get_property(event.user_id, event.group_id)
|
||||
if props:
|
||||
rst = ""
|
||||
for i, p in enumerate(props.keys()):
|
||||
rst += f"{i+1}.{p}\t×{props[p]}\n"
|
||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
await my_props.send(image(b64=await create_bag_image(props)))
|
||||
# rst = ""
|
||||
# for i, p in enumerate(props.keys()):
|
||||
# rst += f"{i+1}.{p}\t×{props[p]}\n"
|
||||
# await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||
else:
|
||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
@@ -0,0 +1,121 @@
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from models.bag_user import BagUser
|
||||
from models.goods_info import GoodsInfo
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
|
||||
|
||||
icon_path = IMAGE_PATH / "shop_icon"
|
||||
|
||||
|
||||
async def create_bag_image(props: Dict[str, int]):
|
||||
"""
|
||||
说明:
|
||||
创建背包道具图片
|
||||
参数:
|
||||
:param props: 道具仓库字典
|
||||
"""
|
||||
goods_list = await GoodsInfo.get_all_goods()
|
||||
active_props = await _init_prop(props, [x for x in goods_list if not x.is_passive])
|
||||
passive_props = await _init_prop(props, [x for x in goods_list if x.is_passive])
|
||||
active_w = 0
|
||||
active_h = 0
|
||||
passive_w = 0
|
||||
passive_h = 0
|
||||
if active_props:
|
||||
img = BuildImage(
|
||||
active_props.w,
|
||||
active_props.h + 70,
|
||||
font="CJGaoDeGuo.otf",
|
||||
font_size=30,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
await img.apaste(active_props, (0, 70))
|
||||
await img.atext((0, 30), "主动道具")
|
||||
active_props = img
|
||||
active_w = img.w
|
||||
active_h = img.h
|
||||
if passive_props:
|
||||
img = BuildImage(
|
||||
passive_props.w,
|
||||
passive_props.h + 70,
|
||||
font="CJGaoDeGuo.otf",
|
||||
font_size=30,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
await img.apaste(passive_props, (0, 70))
|
||||
await img.atext((0, 30), "被动道具")
|
||||
passive_props = img
|
||||
passive_w = img.w
|
||||
passive_h = img.h
|
||||
A = BuildImage(
|
||||
active_w + passive_w + 100,
|
||||
max(active_h, passive_h) + 60,
|
||||
font="CJGaoDeGuo.otf",
|
||||
font_size=30,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
curr_w = 50
|
||||
if active_props:
|
||||
await A.apaste(active_props, (curr_w, 0))
|
||||
curr_w += active_props.w + 10
|
||||
if passive_props:
|
||||
await A.apaste(passive_props, (curr_w, 0))
|
||||
if active_props and passive_props:
|
||||
await A.aline(
|
||||
(active_props.w + 45, 70, active_props.w + 45, A.h - 20), fill=(0, 0, 0)
|
||||
)
|
||||
return A.pic2bs4()
|
||||
|
||||
|
||||
async def _init_prop(
|
||||
props: Dict[str, int], _props: List[GoodsInfo]
|
||||
) -> Optional[BuildImage]:
|
||||
"""
|
||||
说明:
|
||||
构造道具列表图片
|
||||
参数:
|
||||
:param props: 道具仓库字典
|
||||
:param _props: 道具列表
|
||||
"""
|
||||
active_name = [x.goods_name for x in _props]
|
||||
name_list = [x for x in props.keys() if x in active_name]
|
||||
if not name_list:
|
||||
return None
|
||||
temp_img = BuildImage(0, 0, font_size=20)
|
||||
image_list = []
|
||||
num_list = []
|
||||
for i, name in enumerate(name_list):
|
||||
img = BuildImage(
|
||||
temp_img.getsize(name)[0] + 50,
|
||||
30,
|
||||
font="msyh.ttf",
|
||||
font_size=20,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
await img.atext((30, 5), f"{i + 1}.{name}")
|
||||
goods = [x for x in _props if x.goods_name == name][0]
|
||||
if goods.icon and (icon_path / goods.icon).exists():
|
||||
icon = BuildImage(30, 30, background=icon_path / goods.icon)
|
||||
await img.apaste(icon, alpha=True)
|
||||
image_list.append(img)
|
||||
num_list.append(
|
||||
BuildImage(
|
||||
30, 30, font_size=20, font="msyh.ttf", plain_text=f"×{props[name]}"
|
||||
)
|
||||
)
|
||||
max_w = 0
|
||||
num_max_w = 0
|
||||
h = 0
|
||||
for img, num in zip(image_list, num_list):
|
||||
h += img.h
|
||||
max_w = max_w if max_w > img.w else img.w
|
||||
num_max_w = num_max_w if num_max_w > num.w else num.w
|
||||
A = BuildImage(max_w + num_max_w + 30, h, color="#f9f6f2")
|
||||
curr_h = 0
|
||||
for img, num in zip(image_list, num_list):
|
||||
await A.apaste(img, (0, curr_h))
|
||||
await A.apaste(num, (max_w + 20, curr_h + 5), True)
|
||||
curr_h += img.h
|
||||
return A
|
||||
@@ -6,7 +6,6 @@ from utils.message_builder import image
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import is_number, scheduler
|
||||
from nonebot.params import CommandArg
|
||||
from nonebot.plugin import export
|
||||
from services.log import logger
|
||||
import os
|
||||
|
||||
@@ -51,11 +50,6 @@ __plugin_block_limit__ = {
|
||||
"limit_type": "group"
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.register_goods = register_goods
|
||||
export.delete_goods = delete_goods
|
||||
export.update_goods = update_goods
|
||||
|
||||
shop_help = on_command("商店", priority=5, block=True)
|
||||
|
||||
|
||||
@@ -1,50 +1,18 @@
|
||||
from PIL import Image
|
||||
|
||||
from models.goods_info import GoodsInfo
|
||||
from utils.image_utils import BuildImage
|
||||
from models.sign_group_user import SignGroupUser
|
||||
from utils.image_utils import BuildImage, text2image
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional, Union, Tuple
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
from nonebot.plugin import require
|
||||
from utils.decorator.shop import shop_register
|
||||
import nonebot
|
||||
from utils.utils import GDict
|
||||
import time
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
icon_path = IMAGE_PATH / 'shop_icon'
|
||||
|
||||
|
||||
use = require("use")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def init_default_shop_goods():
|
||||
"""
|
||||
导入内置的三个商品
|
||||
"""
|
||||
|
||||
@shop_register(
|
||||
name=("好感度双倍加持卡Ⅰ", "好感度双倍加持卡Ⅱ", "好感度双倍加持卡Ⅲ"),
|
||||
price=(30, 150, 250),
|
||||
des=(
|
||||
"下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
|
||||
"下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)",
|
||||
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
|
||||
),
|
||||
load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
|
||||
daily_limit=(10, 20, 30),
|
||||
** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
|
||||
)
|
||||
async def sign_card(user_id: int, group_id: int, prob: float):
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=prob).apply()
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _():
|
||||
await shop_register.load_register()
|
||||
GDict['run_sql'].append("ALTER TABLE goods_info ADD is_passive boolean DEFAULT False;")
|
||||
GDict['run_sql'].append("ALTER TABLE goods_info ADD icon VARCHAR(255);")
|
||||
|
||||
|
||||
# 创建商店界面
|
||||
@@ -54,28 +22,22 @@ async def create_shop_help() -> str:
|
||||
:return: 图片base64
|
||||
"""
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
idx = 1
|
||||
_dc = {}
|
||||
font_h = BuildImage(0, 0).getsize("正")[1]
|
||||
h = 10
|
||||
_list = []
|
||||
for goods in goods_lst:
|
||||
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time:
|
||||
h += len(goods.goods_description.strip().split("\n")) * font_h + 80
|
||||
_list.append(goods)
|
||||
A = BuildImage(1000, h, color="#f9f6f2")
|
||||
current_h = 0
|
||||
# A = BuildImage(1100, h, color="#f9f6f2")
|
||||
total_n = 0
|
||||
for goods in _list:
|
||||
bk = BuildImage(1180, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
|
||||
goods_image = BuildImage(
|
||||
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
image_list = []
|
||||
for idx, goods in enumerate(_list):
|
||||
name_image = BuildImage(
|
||||
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
await name_image.atext(
|
||||
(15, 0), f"{idx}.{goods.goods_name}", center_type="by_height"
|
||||
(15, 0), f"{idx + 1}.{goods.goods_name}", center_type="by_height"
|
||||
)
|
||||
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
|
||||
await name_image.atext((390, 0), "售价:", center_type="by_height")
|
||||
@@ -102,13 +64,48 @@ async def create_shop_help() -> str:
|
||||
f" 金币",
|
||||
center_type="by_height",
|
||||
)
|
||||
des_image = None
|
||||
font_img = BuildImage(
|
||||
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
p = font_img.getsize('简介:')[0] + 20
|
||||
if goods.goods_description:
|
||||
des_list = goods.goods_description.split('\n')
|
||||
desc = ''
|
||||
for des in des_list:
|
||||
if font_img.getsize(des)[0] > font_img.w - p - 20:
|
||||
msg = ''
|
||||
tmp = ''
|
||||
for i in range(len(des)):
|
||||
if font_img.getsize(tmp)[0] < font_img.w - p - 20:
|
||||
tmp += des[i]
|
||||
else:
|
||||
msg += tmp + '\n'
|
||||
tmp = des[i]
|
||||
desc += msg
|
||||
if tmp:
|
||||
desc += tmp
|
||||
else:
|
||||
desc += des + '\n'
|
||||
if desc[-1] == '\n':
|
||||
desc = desc[:-1]
|
||||
des_image = await text2image(desc, color="#a29ad6")
|
||||
goods_image = BuildImage(
|
||||
600, (50 + des_image.h) if des_image else 50, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
if des_image:
|
||||
await goods_image.atext((15, 50), '简介:')
|
||||
await goods_image.apaste(des_image, (p, 50))
|
||||
await name_image.acircle_corner(5)
|
||||
await goods_image.apaste(name_image, (0, 5), True, center_type="by_width")
|
||||
await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
|
||||
await goods_image.acircle_corner(20)
|
||||
await bk.apaste(goods_image, alpha=True)
|
||||
bk = BuildImage(1180, (50 + des_image.h) if des_image else 50, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
|
||||
if goods.icon and (icon_path / goods.icon).exists():
|
||||
icon = BuildImage(70, 70, background=icon_path / goods.icon)
|
||||
await bk.apaste(icon)
|
||||
await bk.apaste(goods_image, (70, 0), alpha=True)
|
||||
n = 0
|
||||
_w = 550
|
||||
_w = 650
|
||||
# 添加限时图标和时间
|
||||
if goods.goods_limit_time > 0:
|
||||
n += 140
|
||||
@@ -162,14 +159,22 @@ async def create_shop_help() -> str:
|
||||
if total_n < n:
|
||||
total_n = n
|
||||
if n:
|
||||
await bk.aline((550, -1, 550 + n, -1), "#a29ad6", 5)
|
||||
await bk.aline((550, 80, 550 + n, 80), "#a29ad6", 5)
|
||||
await bk.aline((650, -1, 650 + n, -1), "#a29ad6", 5)
|
||||
# await bk.aline((650, 80, 650 + n, 80), "#a29ad6", 5)
|
||||
|
||||
# 添加限时图标和时间
|
||||
idx += 1
|
||||
await A.apaste(bk, (0, current_h), True)
|
||||
current_h += 90
|
||||
w = 850
|
||||
image_list.append(bk)
|
||||
# await A.apaste(bk, (0, current_h), True)
|
||||
# current_h += 90
|
||||
h = 0
|
||||
current_h = 0
|
||||
for img in image_list:
|
||||
h += img.h + 10
|
||||
A = BuildImage(1100, h, color="#f9f6f2")
|
||||
for img in image_list:
|
||||
await A.apaste(img, (0, current_h), True)
|
||||
current_h += img.h + 10
|
||||
w = 950
|
||||
if total_n:
|
||||
w += total_n
|
||||
h = A.h + 230 + 100
|
||||
@@ -197,6 +202,8 @@ async def register_goods(
|
||||
discount: Optional[float] = 1,
|
||||
limit_time: Optional[int] = 0,
|
||||
daily_limit: Optional[int] = 0,
|
||||
is_passive: Optional[bool] = False,
|
||||
icon: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
添加商品
|
||||
@@ -209,6 +216,8 @@ async def register_goods(
|
||||
:param discount: 商品折扣
|
||||
:param limit_time: 商品限时销售时间,单位为小时
|
||||
:param daily_limit: 每日购买次数限制
|
||||
:param is_passive: 是否为被动
|
||||
:param icon: 图标
|
||||
:return: 是否添加成功
|
||||
"""
|
||||
if not await GoodsInfo.get_goods_info(name):
|
||||
@@ -220,7 +229,7 @@ async def register_goods(
|
||||
else 0
|
||||
)
|
||||
return await GoodsInfo.add_goods(
|
||||
name, int(price), des, float(discount), limit_time, daily_limit
|
||||
name, int(price), des, float(discount), limit_time, daily_limit, is_passive, icon
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -272,6 +281,7 @@ async def update_goods(**kwargs) -> Tuple[bool, str, str]:
|
||||
discount = goods.goods_discount
|
||||
limit_time = goods.goods_limit_time
|
||||
daily_limit = goods.daily_limit
|
||||
is_passive = goods.is_passive
|
||||
new_time = 0
|
||||
tmp = ""
|
||||
if kwargs.get("price"):
|
||||
@@ -294,6 +304,9 @@ async def update_goods(**kwargs) -> Tuple[bool, str, str]:
|
||||
if kwargs.get("daily_limit"):
|
||||
tmp += f'每日购买限制:{daily_limit} --> {kwargs["daily_limit"]}\n' if daily_limit else "取消了购买限制\n"
|
||||
daily_limit = int(kwargs["daily_limit"])
|
||||
if kwargs.get("is_passive"):
|
||||
tmp += f'被动道具:{is_passive} --> {kwargs["is_passive"]}\n'
|
||||
des = kwargs["is_passive"]
|
||||
await GoodsInfo.update_goods(
|
||||
name,
|
||||
int(price),
|
||||
@@ -304,7 +317,8 @@ async def update_goods(**kwargs) -> Tuple[bool, str, str]:
|
||||
if limit_time != 0 and new_time
|
||||
else 0
|
||||
),
|
||||
daily_limit
|
||||
daily_limit,
|
||||
is_passive
|
||||
)
|
||||
return True, name, tmp[:-1],
|
||||
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
from nonebot import on_command
|
||||
from typing import Any, Tuple
|
||||
|
||||
from nonebot import on_command, on_regex
|
||||
|
||||
from models.user_shop_gold_log import UserShopGoldLog
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from nonebot.params import CommandArg, RegexGroup
|
||||
|
||||
from utils.decorator.shop import NotMeetUseConditionsException
|
||||
from utils.utils import is_number
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from services.db_context import db
|
||||
from nonebot.plugin import export
|
||||
from .data_source import effect, register_use, func_manager
|
||||
from .data_source import effect, register_use, func_manager, build_params
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 使用道具"
|
||||
@@ -15,12 +20,16 @@ __plugin_usage__ = """
|
||||
usage:
|
||||
普通的使用道具
|
||||
指令:
|
||||
使用道具 [序号或道具名称] ?[数量]=1
|
||||
使用道具 [序号或道具名称] ?[数量]=1 ?[其他信息]
|
||||
示例:使用道具好感度双倍加持卡 使用道具好感度双倍加持卡
|
||||
示例:使用道具1 使用第一个道具
|
||||
示例:使用道具1 10 使用10个第一个道具
|
||||
示例:使用道具1 1 来点色图 使用第一个道具并附带信息
|
||||
* 序号以 ”我的道具“ 为准 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 使用道具"
|
||||
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_type__ = ("商店",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
@@ -30,52 +39,69 @@ __plugin_settings__ = {
|
||||
"cmd": ["商店", "使用道具"],
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.register_use = register_use
|
||||
|
||||
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
||||
use_props = on_command(r"使用道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@use_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
msg = arg.extract_plain_text()
|
||||
num = 1
|
||||
msg_sp = msg.split()
|
||||
if len(msg_sp) > 1 and is_number(msg_sp[-1]) and int(msg_sp[-1]) > 0:
|
||||
num = int(msg.split()[-1])
|
||||
msg = " ".join(msg.split()[:-1])
|
||||
property_ = await BagUser.get_property(event.user_id, event.group_id)
|
||||
text = ""
|
||||
prop_n = None
|
||||
index = None
|
||||
split = msg.split()
|
||||
if size := len(split):
|
||||
if size == 1:
|
||||
prop_n = split[0].strip()
|
||||
index = 1
|
||||
if size > 1 and is_number(split[1].strip()):
|
||||
prop_n = split[0].strip()
|
||||
num = int(split[1].strip())
|
||||
index = 2
|
||||
else:
|
||||
await use_props.finish("缺少参数,请查看帮助", at_sender=True)
|
||||
if index:
|
||||
text = " ".join(split[index:])
|
||||
property_ = await BagUser.get_property(event.user_id, event.group_id, True)
|
||||
if property_:
|
||||
async with db.transaction():
|
||||
if is_number(msg):
|
||||
if 0 < int(msg) <= len(property_):
|
||||
name = list(property_.keys())[int(msg) - 1]
|
||||
else:
|
||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||
name = None
|
||||
if prop_n and is_number(prop_n):
|
||||
if 0 < int(prop_n) <= len(property_):
|
||||
name = list(property_.keys())[int(prop_n) - 1]
|
||||
else:
|
||||
if msg not in property_.keys():
|
||||
await use_props.finish("道具名称错误!", at_sender=True)
|
||||
name = msg
|
||||
_user_prop_count = property_[name]
|
||||
if num > _user_prop_count:
|
||||
await use_props.finish(f"道具数量不足,无法使用{num}次!")
|
||||
if num > (n := func_manager.get_max_num_limit(name)):
|
||||
await use_props.finish(f"该道具单次只能使用 {n} 个!")
|
||||
if await BagUser.delete_property(
|
||||
event.user_id, event.group_id, name, num
|
||||
):
|
||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||
else:
|
||||
if prop_n not in property_.keys():
|
||||
await use_props.finish("道具名称错误!", at_sender=True)
|
||||
name = prop_n
|
||||
_user_prop_count = property_[name]
|
||||
if num > _user_prop_count:
|
||||
await use_props.finish(f"道具数量不足,无法使用{num}次!")
|
||||
if num > (n := func_manager.get_max_num_limit(name)):
|
||||
await use_props.finish(f"该道具单次只能使用 {n} 个!")
|
||||
model, kwargs = build_params(bot, event, name, num, text)
|
||||
try:
|
||||
await func_manager.run_handle(type_="before_handle", param=model, **kwargs)
|
||||
except NotMeetUseConditionsException as e:
|
||||
await use_props.finish(e.get_info(), at_sender=True)
|
||||
async with db.transaction():
|
||||
if await BagUser.delete_property(event.user_id, event.group_id, name, num):
|
||||
if func_manager.check_send_success_message(name):
|
||||
await use_props.send(f"使用道具 {name} {num} 次成功!", at_sender=True)
|
||||
if msg := await effect(bot, event, name, num):
|
||||
if msg := await effect(bot, event, name, num, text, event.message):
|
||||
await use_props.send(msg, at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次成功"
|
||||
)
|
||||
await UserShopGoldLog.add_shop_log(
|
||||
event.user_id, event.group_id, 1, name, num
|
||||
)
|
||||
else:
|
||||
await use_props.send(f"使用道具 {name} {num} 次失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次失败"
|
||||
)
|
||||
await func_manager.run_handle(type_="after_handle", param=model, **kwargs)
|
||||
else:
|
||||
await use_props.send("您的背包里没有任何的道具噢", at_sender=True)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment, Message
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from pydantic import create_model
|
||||
from utils.models import ShopParam
|
||||
from typing import Optional, Union
|
||||
from typing import Optional, Union, Callable, List, Tuple, Dict, Any
|
||||
from types import MappingProxyType
|
||||
import inspect
|
||||
import asyncio
|
||||
@@ -13,6 +13,30 @@ class GoodsUseFuncManager:
|
||||
def __init__(self):
|
||||
self._data = {}
|
||||
|
||||
def register_use_before_handle(self, goods_name: str, fun_list: List[Callable]):
|
||||
"""
|
||||
说明:
|
||||
注册商品使用前函数
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param fun_list: 函数列表
|
||||
"""
|
||||
if fun_list:
|
||||
self._data[goods_name]["before_handle"] = fun_list
|
||||
logger.info(f"register_use_before_handle 成功注册商品:{goods_name} 的{len(fun_list)}个使用前函数")
|
||||
|
||||
def register_use_after_handle(self, goods_name: str, fun_list: List[Callable]):
|
||||
"""
|
||||
说明:
|
||||
注册商品使用后函数
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param fun_list: 函数列表
|
||||
"""
|
||||
if fun_list:
|
||||
self._data[goods_name]["after_handle"] = fun_list
|
||||
logger.info(f"register_use_after_handle 成功注册商品:{goods_name} 的{len(fun_list)}个使用后函数")
|
||||
|
||||
def register_use(self, goods_name: str, **kwargs):
|
||||
"""
|
||||
注册商品使用方法
|
||||
@@ -26,7 +50,7 @@ class GoodsUseFuncManager:
|
||||
判断商品使用方法是否被注册
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
return bool(self ._data.get(goods_name))
|
||||
return bool(self._data.get(goods_name))
|
||||
|
||||
def get_max_num_limit(self, goods_name: str) -> int:
|
||||
"""
|
||||
@@ -37,6 +61,21 @@ class GoodsUseFuncManager:
|
||||
return self._data[goods_name]["kwargs"]["max_num_limit"]
|
||||
return 1
|
||||
|
||||
def _parse_args(self, args_: MappingProxyType, param: ShopParam, **kwargs):
|
||||
param_list_ = []
|
||||
_bot = param.bot
|
||||
param.bot = None
|
||||
param_json = param.dict()
|
||||
param_json["bot"] = _bot
|
||||
for par in args_.keys():
|
||||
if par in ["shop_param"]:
|
||||
param_list_.append(param)
|
||||
elif par not in ["args", "kwargs"]:
|
||||
param_list_.append(param_json.get(par))
|
||||
if kwargs.get(par) is not None:
|
||||
del kwargs[par]
|
||||
return param_list_
|
||||
|
||||
async def use(
|
||||
self, param: ShopParam, **kwargs
|
||||
) -> Optional[Union[str, MessageSegment]]:
|
||||
@@ -45,31 +84,18 @@ class GoodsUseFuncManager:
|
||||
:param param: BaseModel
|
||||
:param kwargs: kwargs
|
||||
"""
|
||||
def parse_args(args_: MappingProxyType):
|
||||
param_list_ = []
|
||||
_bot = param.bot
|
||||
param.bot = None
|
||||
param_json = param.dict()
|
||||
param_json["bot"] = _bot
|
||||
for par in args_.keys():
|
||||
if par in ["shop_param"]:
|
||||
param_list_.append(param)
|
||||
elif par not in ["args", "kwargs"]:
|
||||
param_list_.append(param_json.get(par))
|
||||
if kwargs.get(par) is not None:
|
||||
del kwargs[par]
|
||||
return param_list_
|
||||
goods_name = param.goods_name
|
||||
if self.exists(goods_name):
|
||||
# 使用方法
|
||||
args = inspect.signature(self._data[goods_name]["func"]).parameters
|
||||
if args and list(args.keys())[0] != "kwargs":
|
||||
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
|
||||
return await self._data[goods_name]["func"](
|
||||
*parse_args(args)
|
||||
*self._parse_args(args, param, **kwargs)
|
||||
)
|
||||
else:
|
||||
return self._data[goods_name]["func"](
|
||||
*parse_args(args)
|
||||
*self._parse_args(args, param, **kwargs)
|
||||
)
|
||||
else:
|
||||
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
|
||||
@@ -81,6 +107,21 @@ class GoodsUseFuncManager:
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
async def run_handle(self, goods_name: str, type_: str, param: ShopParam, **kwargs):
|
||||
if self._data[goods_name].get(type_):
|
||||
for func in self._data[goods_name].get(type_):
|
||||
args = inspect.signature(func).parameters
|
||||
if args and list(args.keys())[0] != "kwargs":
|
||||
if asyncio.iscoroutinefunction(func):
|
||||
await func(*self._parse_args(args, param, **kwargs))
|
||||
else:
|
||||
func(*self._parse_args(args, param, **kwargs))
|
||||
else:
|
||||
if asyncio.iscoroutinefunction(func):
|
||||
await func(**kwargs)
|
||||
else:
|
||||
func(**kwargs)
|
||||
|
||||
def check_send_success_message(self, goods_name: str) -> bool:
|
||||
"""
|
||||
检查是否发送使用成功信息
|
||||
@@ -99,7 +140,7 @@ class GoodsUseFuncManager:
|
||||
return self._data[goods_name]["kwargs"]
|
||||
return {}
|
||||
|
||||
def init_model(self, goods_name: str, bot: Bot, event: GroupMessageEvent, num: int):
|
||||
def init_model(self, goods_name: str, bot: Bot, event: GroupMessageEvent, num: int, text: str):
|
||||
return self._data[goods_name]["model"](
|
||||
**{
|
||||
"goods_name": goods_name,
|
||||
@@ -108,6 +149,8 @@ class GoodsUseFuncManager:
|
||||
"user_id": event.user_id,
|
||||
"group_id": event.group_id,
|
||||
"num": num,
|
||||
"message": event.message,
|
||||
"text": text
|
||||
}
|
||||
)
|
||||
|
||||
@@ -115,8 +158,39 @@ class GoodsUseFuncManager:
|
||||
func_manager = GoodsUseFuncManager()
|
||||
|
||||
|
||||
def build_params(
|
||||
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int, text: str
|
||||
) -> Tuple[ShopParam, Dict[str, Any]]:
|
||||
"""
|
||||
说明:
|
||||
构造参数
|
||||
参数:
|
||||
:param bot: bot
|
||||
:param event: event
|
||||
:param goods_name: 商品名称
|
||||
:param num: 数量
|
||||
:param text: 其他信息
|
||||
:return:
|
||||
"""
|
||||
_kwargs = func_manager.get_kwargs(goods_name)
|
||||
return (
|
||||
func_manager.init_model(goods_name, bot, event, num, text),
|
||||
{
|
||||
**_kwargs,
|
||||
"_bot": bot,
|
||||
"event": event,
|
||||
"group_id": event.group_id,
|
||||
"user_id": event.user_id,
|
||||
"num": num,
|
||||
"text": text,
|
||||
"message": event.message,
|
||||
"goods_name": goods_name,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def effect(
|
||||
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int
|
||||
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int, text: str, message: Message
|
||||
) -> Optional[Union[str, MessageSegment]]:
|
||||
"""
|
||||
商品生效
|
||||
@@ -124,30 +198,22 @@ async def effect(
|
||||
:param event: GroupMessageEvent
|
||||
:param goods_name: 商品名称
|
||||
:param num: 使用数量
|
||||
:param text: 其他信息
|
||||
:param message: Message
|
||||
:return: 使用是否成功
|
||||
"""
|
||||
# 优先使用注册的商品插件
|
||||
# try:
|
||||
if func_manager.exists(goods_name):
|
||||
_kwargs = func_manager.get_kwargs(goods_name)
|
||||
return await func_manager.use(
|
||||
func_manager.init_model(goods_name, bot, event, num),
|
||||
**{
|
||||
**_kwargs,
|
||||
"_bot": bot,
|
||||
"event": event,
|
||||
"group_id": event.group_id,
|
||||
"user_id": event.user_id,
|
||||
"num": num,
|
||||
"goods_name": goods_name,
|
||||
},
|
||||
)
|
||||
model, kwargs = build_params(bot, event, goods_name, num, text)
|
||||
return await func_manager.use(model, **kwargs)
|
||||
# except Exception as e:
|
||||
# logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
|
||||
return None
|
||||
|
||||
|
||||
def register_use(goods_name: str, func, **kwargs):
|
||||
def register_use(goods_name: str, func: Callable, **kwargs):
|
||||
"""
|
||||
注册商品使用方法
|
||||
:param goods_name: 商品名称
|
||||
|
||||
@@ -1,37 +1,86 @@
|
||||
from nonebot.adapters.onebot.v11 import Message
|
||||
from nonebot.adapters.onebot.v11 import Message, Bot, MessageEvent
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.rule import to_me
|
||||
from utils.message_builder import custom_forward_msg
|
||||
from services.db_context import db
|
||||
from nonebot.params import CommandArg
|
||||
from services.log import logger
|
||||
|
||||
import asyncio
|
||||
|
||||
__zx_plugin_name__ = "执行sql [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
执行一段sql语句
|
||||
指令:
|
||||
exec [sql语句]
|
||||
exec [sql语句] ([查询页数,19条/页])
|
||||
查看所有表
|
||||
""".strip()
|
||||
__plugin_des__ = "执行一段sql语句"
|
||||
__plugin_cmd__ = [
|
||||
"exec [sql语句]",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_version__ = 0.2
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
exec_ = on_command("exec", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
|
||||
tables = on_command("查看所有表", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
|
||||
@exec_.handle()
|
||||
async def _(arg: Message = CommandArg()):
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
sql = arg.extract_plain_text().strip()
|
||||
async with db.transaction():
|
||||
try:
|
||||
# 判断是否为SELECT语句
|
||||
if sql.lower().startswith("select"):
|
||||
# 分割语句
|
||||
try:
|
||||
page = int(sql.split(" ")[-1]) - 1
|
||||
sql_list = sql.split(" ")[:-1]
|
||||
except ValueError:
|
||||
page = 0
|
||||
sql_list = sql.split(" ")
|
||||
# 拼接语句
|
||||
sql = " ".join(sql_list)
|
||||
query = db.text(sql)
|
||||
res = await db.all(query)
|
||||
msg_list = [f"第{page+1}页查询结果:"]
|
||||
# logger.info(res)
|
||||
# 获取所有字段
|
||||
keys = res[0].keys()
|
||||
# 每页10条
|
||||
for i in res[page * 10 : (page + 1) * 10]:
|
||||
msg = ""
|
||||
for key in keys:
|
||||
msg += f"{key}: {i[key]}\n"
|
||||
msg += f"第{page+1}页第{res.index(i)+1}条"
|
||||
msg_list.append(msg)
|
||||
# 检查是私聊还是群聊
|
||||
try:
|
||||
forward_msg_list = custom_forward_msg(msg_list, bot.self_id)
|
||||
await bot.send_group_forward_msg(group_id=event.group_id, messages=forward_msg_list)
|
||||
except:
|
||||
for msg in msg_list:
|
||||
await exec_.send(msg)
|
||||
await asyncio.sleep(0.2)
|
||||
return
|
||||
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}")
|
||||
|
||||
|
||||
@tables.handle()
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
# 获取所有表
|
||||
query = db.text("select tablename from pg_tables where schemaname = 'public'")
|
||||
res = await db.all(query)
|
||||
msg = "数据库中的所有表名:\n"
|
||||
for tablename in res:
|
||||
msg += str(tablename["tablename"]) + "\n"
|
||||
await tables.finish(msg)
|
||||
|
||||
@@ -122,8 +122,8 @@ async def _(event: GroupMessageEvent):
|
||||
tmp = ""
|
||||
data = plugins2settings_manager.get_data()
|
||||
for module in data:
|
||||
if data[module]["level"] > level:
|
||||
plugin_name = data[module]["cmd"][0]
|
||||
if data[module].level > level:
|
||||
plugin_name = data[module].cmd[0]
|
||||
if plugin_name == "pixiv":
|
||||
plugin_name = "搜图 p站排行"
|
||||
tmp += f"{plugin_name}\n"
|
||||
|
||||
+9
-1
@@ -2,6 +2,7 @@ from services.db_context import db
|
||||
from typing import Dict
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
from .goods_info import GoodsInfo
|
||||
|
||||
|
||||
class BagUser(db.Model):
|
||||
@@ -62,17 +63,24 @@ class BagUser(db.Model):
|
||||
return 100
|
||||
|
||||
@classmethod
|
||||
async def get_property(cls, user_qq: int, group_id: int) -> Dict[str, int]:
|
||||
async def get_property(cls, user_qq: int, group_id: int, only_active: bool = False) -> Dict[str, int]:
|
||||
"""
|
||||
说明:
|
||||
获取当前道具
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param only_active: 仅仅获取主动使用的道具
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
if only_active and user.property:
|
||||
data = {}
|
||||
name_list = [x.goods_name for x in await GoodsInfo.get_all_goods() if not x.is_passive]
|
||||
for key in [x for x in user.property.keys() if x in name_list]:
|
||||
data[key] = user.property[key]
|
||||
return data
|
||||
return user.property
|
||||
else:
|
||||
await cls.create(
|
||||
|
||||
+16
-2
@@ -16,6 +16,8 @@ class GoodsInfo(db.Model):
|
||||
daily_purchase_limit = db.Column(
|
||||
db.JSON(), nullable=False, default={}
|
||||
) # 每日购买限制数据存储
|
||||
is_passive = db.Column(db.Boolean(), nullable=False, default=0) # 是否为被动
|
||||
icon = db.Column(db.String(), default=0) # 图标
|
||||
|
||||
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
|
||||
|
||||
@@ -28,6 +30,8 @@ class GoodsInfo(db.Model):
|
||||
goods_discount: float = 1,
|
||||
goods_limit_time: int = 0,
|
||||
daily_limit: int = 0,
|
||||
is_passive: bool = False,
|
||||
icon: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
@@ -39,6 +43,8 @@ class GoodsInfo(db.Model):
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时
|
||||
:param daily_limit: 每日购买限制
|
||||
:param is_passive: 是否为被动道具
|
||||
:param icon: 图标
|
||||
"""
|
||||
try:
|
||||
if not await cls.get_goods_info(goods_name):
|
||||
@@ -49,10 +55,12 @@ class GoodsInfo(db.Model):
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
daily_limit=daily_limit,
|
||||
is_passive=is_passive,
|
||||
icon=icon
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo add_goods 发生错误 {type(e)}:{e}")
|
||||
logger.error(f"GoodsInfo add_goods {goods_name} 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
@@ -81,7 +89,9 @@ class GoodsInfo(db.Model):
|
||||
goods_description: Optional[str] = None,
|
||||
goods_discount: Optional[float] = None,
|
||||
goods_limit_time: Optional[int] = None,
|
||||
daily_limit: Optional[int] = None
|
||||
daily_limit: Optional[int] = None,
|
||||
is_passive: Optional[bool] = None,
|
||||
icon: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
@@ -93,6 +103,8 @@ class GoodsInfo(db.Model):
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时时间
|
||||
:param daily_limit: 每日次数限制
|
||||
:param is_passive: 是否为被动
|
||||
:param icon: 图标
|
||||
"""
|
||||
try:
|
||||
query = (
|
||||
@@ -108,6 +120,8 @@ class GoodsInfo(db.Model):
|
||||
goods_discount=goods_discount or query.goods_discount,
|
||||
goods_limit_time=goods_limit_time if goods_limit_time is not None else query.goods_limit_time,
|
||||
daily_limit=daily_limit if daily_limit is not None else query.daily_limit,
|
||||
is_passive=is_passive if is_passive is not None else query.is_passive,
|
||||
icon=icon or query.icon
|
||||
).apply()
|
||||
return True
|
||||
except Exception as e:
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
from datetime import datetime
|
||||
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class UserShopGoldLog(db.Model):
|
||||
__tablename__ = "user_shop_gold_log"
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
type = db.Column(db.Integer(), nullable=False) # 0: 购买,1: 使用,2: 插件
|
||||
name = db.Column(db.String())
|
||||
spend_gold = db.Column(db.Integer(), nullable=False)
|
||||
num = db.Column(db.Integer(), nullable=False)
|
||||
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
|
||||
|
||||
@classmethod
|
||||
async def add_shop_log(
|
||||
cls,
|
||||
user_qq: int,
|
||||
group_id: int,
|
||||
type_: int,
|
||||
name: str,
|
||||
num: int,
|
||||
spend_gold: int = 0,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
添加商店购买或使用日志
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param type_: 类型
|
||||
:param name: 商品名称
|
||||
:param num: 数量
|
||||
:param spend_gold: 花费金币
|
||||
"""
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
group_id=group_id,
|
||||
type=type_,
|
||||
name=name,
|
||||
num=num,
|
||||
spend_gold=spend_gold,
|
||||
create_time=datetime.now(),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_user_log(cls, user_qq: int, group_id: int) -> "UserShopGoldLog":
|
||||
"""
|
||||
说明:
|
||||
获取用户日志
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
return await cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.group_qq == group_id)
|
||||
).first()
|
||||
@@ -31,16 +31,16 @@ usage:
|
||||
主播订阅相当于 直播间订阅 + UP订阅
|
||||
指令:[示例Id乱打的,仅做示例]
|
||||
添加订阅 ['主播'/'UP'/'番剧'] [id/链接/番名]
|
||||
删除订阅 [id]
|
||||
删除订阅 ['主播'/'UP'/'id'] [id]
|
||||
查看订阅
|
||||
示例:添加订阅主播 2345344 <-(直播房间id)
|
||||
示例:添加订阅UP 2355543 <-(个人主页id)
|
||||
示例:添加订阅番剧 史莱姆 <-(支持模糊搜索)
|
||||
示例:添加订阅番剧 125344 <-(番剧id)
|
||||
示例:删除订阅 2324344 <-(任意id,通过查看订阅获取)
|
||||
示例:删除订阅id 2324344 <-(任意id,通过查看订阅获取)
|
||||
""".strip()
|
||||
__plugin_des__ = "非常便利的B站订阅通知"
|
||||
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"]
|
||||
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 ['主播'/'UP'/'id'] [id]", "查看订阅"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier & NumberSir"
|
||||
__plugin_settings__ = {
|
||||
@@ -68,7 +68,7 @@ __plugin_configs__ = {
|
||||
}
|
||||
|
||||
add_sub = on_command("添加订阅", priority=5, block=True)
|
||||
del_sub = on_regex(r"^删除订阅(\d+)$", priority=5, block=True)
|
||||
del_sub = on_command("删除订阅", priority=5, block=True)
|
||||
show_sub_info = on_regex("^查看订阅$", priority=5, block=True)
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
@@ -84,6 +84,7 @@ async def _():
|
||||
|
||||
|
||||
@add_sub.handle()
|
||||
@del_sub.handle()
|
||||
async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
if len(msg) < 2:
|
||||
@@ -157,23 +158,30 @@ async def _(
|
||||
)
|
||||
|
||||
|
||||
@del_sub.handle()
|
||||
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||
msg = reg_group[0]
|
||||
id_ = (
|
||||
f"{event.group_id}"
|
||||
if isinstance(event, GroupMessageEvent)
|
||||
else f"{event.user_id}"
|
||||
)
|
||||
if await BilibiliSub.delete_bilibili_sub(int(msg), id_):
|
||||
await del_sub.send(f"删除订阅id:{msg} 成功...")
|
||||
@del_sub.got("sub_type")
|
||||
@del_sub.got("sub_user")
|
||||
@del_sub.got("id")
|
||||
async def _(
|
||||
event: MessageEvent,
|
||||
id_: str = ArgStr("id"),
|
||||
sub_type: str = ArgStr("sub_type"),
|
||||
sub_user: str = ArgStr("sub_user"),
|
||||
):
|
||||
if sub_type in ["主播", "直播"]:
|
||||
result = await BilibiliSub.delete_bilibili_sub(int(id_),sub_user,"live")
|
||||
elif sub_type.lower() in ["up", "用户"]:
|
||||
result = await BilibiliSub.delete_bilibili_sub(int(id_),sub_user,"up")
|
||||
else: result = await BilibiliSub.delete_bilibili_sub(int(id_),sub_user)
|
||||
if result:
|
||||
await del_sub.send(f"删除订阅id:{id_} 成功...")
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 删除订阅 {id_}"
|
||||
)
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 删除订阅 {id_}"
|
||||
)
|
||||
else:
|
||||
await del_sub.send(f"删除订阅id:{msg} 失败...")
|
||||
await del_sub.send(f"删除订阅id:{id_} 失败...")
|
||||
|
||||
|
||||
|
||||
@show_sub_info.handle()
|
||||
|
||||
@@ -7,11 +7,11 @@ from asyncio.exceptions import TimeoutError
|
||||
from utils.utils import get_bot
|
||||
from .model import BilibiliSub
|
||||
from bilireq.live import get_room_info_by_id
|
||||
from .utils import get_meta
|
||||
from .utils import get_meta, get_user_card
|
||||
from utils.message_builder import image
|
||||
from bilireq.user import get_user_info
|
||||
from bilireq.user import get_videos
|
||||
# from .utils import get_videos
|
||||
from bilireq import dynamic
|
||||
from .utils import get_videos
|
||||
from typing import Optional, Tuple
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from datetime import datetime
|
||||
@@ -83,7 +83,7 @@ async def add_up_sub(uid: int, sub_user: str) -> str:
|
||||
async with db.transaction():
|
||||
try:
|
||||
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
|
||||
user_info = await get_user_info(uid)
|
||||
user_info = await get_user_card(uid)
|
||||
except ResponseCodeError:
|
||||
return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
|
||||
uname = user_info["name"]
|
||||
@@ -207,8 +207,8 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
||||
return await _get_up_status(id_)
|
||||
elif sub_type == "season":
|
||||
return await _get_season_status(id_)
|
||||
except ResponseCodeError:
|
||||
logger.error(f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试...")
|
||||
except ResponseCodeError as msg:
|
||||
logger.info(f"Id:{id_} 获取信息失败...{msg}")
|
||||
return None
|
||||
# return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||
# except Exception as e:
|
||||
@@ -230,7 +230,7 @@ async def _get_live_status(id_: int) -> Optional[str]:
|
||||
sub = await BilibiliSub.get_sub(id_)
|
||||
if sub.live_status != live_status:
|
||||
await BilibiliSub.update_sub_info(id_, live_status=live_status)
|
||||
if sub.live_status == 0 and live_status == 1:
|
||||
if sub.live_status in [0, 2] and live_status == 1:
|
||||
return (
|
||||
f""
|
||||
f"{image(cover)}\n"
|
||||
@@ -249,7 +249,7 @@ async def _get_up_status(id_: int) -> Optional[str]:
|
||||
"""
|
||||
_user = await BilibiliSub.get_sub(id_)
|
||||
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
|
||||
user_info = await get_user_info(_user.uid)
|
||||
user_info = await get_user_card(_user.uid)
|
||||
uname = user_info["name"]
|
||||
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
|
||||
video_info = await get_videos(_user.uid)
|
||||
@@ -349,16 +349,8 @@ async def get_user_dynamic(
|
||||
await page.set_viewport_size(
|
||||
{"width": 2560, "height": 1080, "timeout": 10000 * 20}
|
||||
)
|
||||
await page.wait_for_selector(".panel-area")
|
||||
await page.evaluate(
|
||||
"""
|
||||
xs = document.getElementById('internationalHeader');
|
||||
xs.remove();
|
||||
xs = document.getElementsByClassName('panel-area')
|
||||
xs[0].remove();
|
||||
"""
|
||||
)
|
||||
card = page.locator(".detail-card")
|
||||
await page.wait_for_selector(".bili-dyn-item__main")
|
||||
card = page.locator(".bili-dyn-item__main")
|
||||
await card.wait_for()
|
||||
await card.screenshot(
|
||||
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||
|
||||
@@ -66,7 +66,7 @@ class BilibiliSub(db.Model):
|
||||
"""
|
||||
try:
|
||||
query = (
|
||||
await cls.query.where(cls.sub_id == sub_id)
|
||||
await cls.query.where( (cls.sub_id == sub_id) & (cls.sub_type == sub_type) )
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
@@ -107,7 +107,7 @@ class BilibiliSub(db.Model):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str) -> bool:
|
||||
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str,sub_type: Optional[str] = None) -> bool:
|
||||
"""
|
||||
说明:
|
||||
删除订阅
|
||||
@@ -117,13 +117,22 @@ class BilibiliSub(db.Model):
|
||||
"""
|
||||
try:
|
||||
async with db.transaction():
|
||||
query = (
|
||||
await cls.query.where(
|
||||
(cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user))
|
||||
if sub_type:
|
||||
query = (
|
||||
await cls.query.where(
|
||||
(cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user) & (cls.sub_type == sub_type))
|
||||
)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
else:
|
||||
query = (
|
||||
await cls.query.where(
|
||||
(cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user))
|
||||
)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not query:
|
||||
return False
|
||||
await query.update(
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.http_utils import AsyncHttpx, get_user_agent
|
||||
# from bilibili_api import user
|
||||
from bilireq.user import get_user_info
|
||||
from httpx import AsyncClient
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
BORDER_PATH = IMAGE_PATH / "border"
|
||||
BORDER_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
BASE_URL = "https://api.bilibili.com"
|
||||
|
||||
async def get_pic(url: str) -> bytes:
|
||||
"""
|
||||
@@ -78,7 +79,6 @@ async def get_meta(media_id: int, auth=None, reqtype="both", **kwargs):
|
||||
"""
|
||||
from bilireq.utils import get
|
||||
|
||||
BASE_URL = "https://api.bilibili.com"
|
||||
url = f"{BASE_URL}/pgc/review/user"
|
||||
params = {"media_id": media_id}
|
||||
raw_json = await get(url, raw=True, params=params, auth=auth, reqtype=reqtype, **kwargs)
|
||||
@@ -86,8 +86,7 @@ async def get_meta(media_id: int, auth=None, reqtype="both", **kwargs):
|
||||
|
||||
|
||||
async def get_videos(
|
||||
uid: int, tid: int = 0, pn: int = 1, keyword: str = "", order: str = "pubdate",
|
||||
*, auth=None, reqtype="both", **kwargs
|
||||
uid: int, tid: int = 0, pn: int = 1, keyword: str = "", order: str = "pubdate"
|
||||
):
|
||||
"""
|
||||
获取用户投该视频信息
|
||||
@@ -100,15 +99,45 @@ async def get_videos(
|
||||
:param keyword: 搜索关键词
|
||||
:param order: 排序方式,可以为 “pubdate(上传日期从新到旧), stow(收藏从多到少), click(播放量从多到少)”
|
||||
"""
|
||||
from bilireq.utils import get
|
||||
BASE_URL = "https://api.bilibili.com"
|
||||
from bilireq.utils import ResponseCodeError
|
||||
|
||||
url = f"{BASE_URL}/x/space/arc/search"
|
||||
params = {
|
||||
"mid": uid,
|
||||
"ps": 30,
|
||||
"tid": tid,
|
||||
"pn": pn,
|
||||
"keyword": keyword,
|
||||
"order": order
|
||||
}
|
||||
return await get(url, params=params, auth=auth, reqtype=reqtype, **kwargs)
|
||||
headers = get_user_agent()
|
||||
headers["Referer"] = f"https://space.bilibili.com/{uid}/video"
|
||||
async with AsyncClient() as client:
|
||||
r = await client.head(
|
||||
"https://space.bilibili.com",
|
||||
headers=headers,
|
||||
)
|
||||
params = {
|
||||
"mid": uid,
|
||||
"ps": 30,
|
||||
"tid": tid,
|
||||
"pn": pn,
|
||||
"keyword": keyword,
|
||||
"order": order,
|
||||
}
|
||||
raw_json = (
|
||||
await client.get(url, params=params, headers=headers, cookies=r.cookies)
|
||||
).json()
|
||||
if raw_json["code"] != 0:
|
||||
raise ResponseCodeError(
|
||||
code=raw_json["code"],
|
||||
msg=raw_json["message"],
|
||||
data=raw_json.get("data", None),
|
||||
)
|
||||
return raw_json["data"]
|
||||
|
||||
async def get_user_card(mid, photo: bool = False, auth=None, reqtype="both", **kwargs):
|
||||
from bilireq.utils import get
|
||||
|
||||
url = f"{BASE_URL}/x/web-interface/card"
|
||||
return (
|
||||
await get(
|
||||
url,
|
||||
params={"mid": mid, "photo": photo},
|
||||
auth=auth,
|
||||
reqtype=reqtype,
|
||||
**kwargs,
|
||||
)
|
||||
)["card"]
|
||||
|
||||
@@ -9,7 +9,7 @@ import platform
|
||||
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
|
||||
|
||||
url = "http://www.eclzz.cool"
|
||||
url = "http://www.eclzz.love"
|
||||
|
||||
|
||||
async def get_bt_info(keyword: str, page: int):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot import on_command
|
||||
from .data_source import check_update, get_latest_version_data
|
||||
@@ -50,24 +50,24 @@ restart = on_command(
|
||||
|
||||
|
||||
@update_zhenxun.handle()
|
||||
async def _(bot: Bot):
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
try:
|
||||
code, error = await check_update(bot)
|
||||
if error:
|
||||
logger.error(f"更新真寻未知错误 {error}")
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=f"更新真寻未知错误 {error}"
|
||||
user_id=event.user_id, message=f"更新真寻未知错误 {error}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"更新真寻未知错误 {type(e)}:{e}")
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
user_id=event.user_id,
|
||||
message=f"更新真寻未知错误 {type(e)}:{e}",
|
||||
)
|
||||
else:
|
||||
if code == 200:
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=f"更新完毕,请重启真寻...."
|
||||
user_id=event.user_id, message=f"更新完毕,请重启真寻...."
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import random
|
||||
import json
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from lxml import etree
|
||||
from typing import List, Tuple
|
||||
from PIL import ImageDraw
|
||||
@@ -107,27 +109,70 @@ class BaHandle(BaseHandle[BaChar]):
|
||||
else:
|
||||
return 1
|
||||
|
||||
# Bwiki 待恢复
|
||||
# async def _update_info(self):
|
||||
# info = {}
|
||||
# url = "https://wiki.biligame.com/bluearchive/学生筛选"
|
||||
# result = await self.get_url(url)
|
||||
# if not result:
|
||||
# logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
# return
|
||||
# else:
|
||||
# dom = etree.HTML(result, etree.HTMLParser())
|
||||
# char_list = dom.xpath("//div[@class='filters']/table[2]/tbody/tr")
|
||||
# for char in char_list:
|
||||
# try:
|
||||
# name = char.xpath("./td[2]/a/div/text()")[0]
|
||||
# avatar = char.xpath("./td[1]/div/div/a/img/@data-src")[0]
|
||||
# star_pic = char.xpath("./td[4]/img/@alt")[0]
|
||||
# except IndexError:
|
||||
# continue
|
||||
# member_dict = {
|
||||
# "头像": unquote(str(avatar)),
|
||||
# "名称": remove_prohibited_str(name),
|
||||
# "星级": self.title2star(star_pic),
|
||||
# }
|
||||
# info[member_dict["名称"]] = member_dict
|
||||
# self.dump_data(info)
|
||||
# logger.info(f"{self.game_name_cn} 更新成功")
|
||||
# # 下载头像
|
||||
# for value in info.values():
|
||||
# await self.download_img(value["头像"], value["名称"])
|
||||
# # 下载星星
|
||||
# await self.download_img(
|
||||
# "https://patchwiki.biligame.com/images/bluearchive/thumb/e/e0/82nj2x9sxko473g7782r14fztd4zyky.png/15px-Star-1.png",
|
||||
# "star-1",
|
||||
# )
|
||||
# await self.download_img(
|
||||
# "https://patchwiki.biligame.com/images/bluearchive/thumb/0/0b/msaff2g0zk6nlyl1rrn7n1ri4yobcqc.png/30px-Star-2.png",
|
||||
# "star-2",
|
||||
# )
|
||||
# await self.download_img(
|
||||
# "https://patchwiki.biligame.com/images/bluearchive/thumb/8/8a/577yv79x1rwxk8efdccpblo0lozl158.png/46px-Star-3.png",
|
||||
# "star-3"
|
||||
# )
|
||||
|
||||
# 数据来源:SCHALE DB
|
||||
async def _update_info(self):
|
||||
info = {}
|
||||
url = "https://wiki.biligame.com/bluearchive/学生筛选"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
url = "https://lonqie.github.io/SchaleDB/data/cn/students.min.json?v=49"
|
||||
result = await AsyncHttpx.get(url)
|
||||
if result.status_code != 200:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
return
|
||||
else:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath("//div[@class='filters']/table[2]/tbody/tr")
|
||||
char_list = json.loads(result.text)
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./td[2]/a/div/text()")[0]
|
||||
avatar = char.xpath("./td[1]/div/div/a/img/@data-src")[0]
|
||||
star_pic = char.xpath("./td[4]/img/@alt")[0]
|
||||
name = char.get("Name")
|
||||
avatar = "https://lonqie.github.io/SchaleDB/images/student/icon/"+char.get("CollectionTexture")+".png"
|
||||
star = char.get("StarGrade")
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar)),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"星级": self.title2star(star_pic),
|
||||
"星级": star,
|
||||
}
|
||||
info[member_dict["名称"]] = member_dict
|
||||
self.dump_data(info)
|
||||
@@ -147,4 +192,5 @@ class BaHandle(BaseHandle[BaChar]):
|
||||
await self.download_img(
|
||||
"https://patchwiki.biligame.com/images/bluearchive/thumb/8/8a/577yv79x1rwxk8efdccpblo0lozl158.png/46px-Star-3.png",
|
||||
"star-3"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -331,9 +331,7 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
try:
|
||||
title = announcement.xpath("./@title")[0]
|
||||
url = "https://wiki.biligame.com/" + announcement.xpath("./@href")[0]
|
||||
if re.match(r".*?\d{8}$", title) or re.match(
|
||||
r"^\d{1,2}月\d{1,2}日.*?", title
|
||||
):
|
||||
if "卡池" in title:
|
||||
break
|
||||
except IndexError:
|
||||
continue
|
||||
@@ -353,45 +351,42 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
up_chars_name = []
|
||||
up_cards = []
|
||||
up_cards_name = []
|
||||
soup = BeautifulSoup(result, "lxml")
|
||||
heads = soup.find_all("span", {"class": "mw-headline"})
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
content = dom.xpath('//*[@id="mw-content-text"]/div/div/div[1]/div')[0]
|
||||
heads = content.xpath("./div")
|
||||
for head in heads:
|
||||
if "时间" in head.text or "期间" in head.text:
|
||||
time = head.find_next("p").text.split("\n")[0]
|
||||
if "时间" in head.find("./img").tail or "期间" in head.find("./img").tail:
|
||||
time = content.xpath("./p")[1].text.split("\n")[0]
|
||||
if "~" in time:
|
||||
start, end = time.split("~")
|
||||
start_time = dateparser.parse(start)
|
||||
end_time = dateparser.parse(end)
|
||||
elif "赛马娘" in head.text:
|
||||
char_img = head.find_next("center").find("img")[
|
||||
"src"
|
||||
]
|
||||
lines = str(head.find_next("p").text).split("\n")
|
||||
elif "赛马娘" in head.find("./img").tail:
|
||||
char_img = content.xpath("./center")[1].find("./a/img").get("src")
|
||||
lines = content.xpath("./p")[2].xpath("string(.)").split("\n")
|
||||
chars = [
|
||||
line
|
||||
for line in lines
|
||||
if "★" in line and "【" in line and "】" in line
|
||||
if "★" in line and "[" in line and "]" in line
|
||||
]
|
||||
for char in set(chars): # list去重
|
||||
star = char.count("★")
|
||||
name = re.split(r"[【】]", char)[-2].strip()
|
||||
name = re.split("[ ]",char)[-1]
|
||||
up_chars.append(
|
||||
UpChar(name=name, star=star, limited=False, zoom=70)
|
||||
)
|
||||
up_chars_name.append(name)
|
||||
elif "支援卡" in head.text:
|
||||
card_img = head.find_next("center").find("img")[
|
||||
"src"
|
||||
]
|
||||
lines = str(head.find_next("p").text).split("\n")
|
||||
elif "支援卡" in head.find("./img").tail:
|
||||
card_img = content.xpath("./center")[2].find("./a/img").get("src")
|
||||
lines = content.xpath("./p")[3].xpath("string(.)").split("\n")
|
||||
cards = [
|
||||
line
|
||||
for line in lines
|
||||
if "R" in line and "【" in line and "】" in line
|
||||
if "R" in line and "[" in line and "]" in line
|
||||
]
|
||||
for card in cards:
|
||||
for card in set(cards):
|
||||
star = 3 if "SSR" in card else 2 if "SR" in card else 1
|
||||
name = re.split(r"[【】]", card)[-2].strip()
|
||||
name = re.split("[ ]",card)[-1]
|
||||
up_cards.append(
|
||||
UpChar(name=name, star=star, limited=False, zoom=70)
|
||||
)
|
||||
@@ -404,7 +399,7 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_chars,
|
||||
up_name=up_chars_name,
|
||||
up_name=",".join(up_chars_name),
|
||||
)
|
||||
self.UP_CARD = UpEvent(
|
||||
title=title,
|
||||
@@ -412,7 +407,7 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_cards,
|
||||
up_name=up_cards_name,
|
||||
up_name=",".join(up_cards_name),
|
||||
)
|
||||
self.dump_up_char()
|
||||
logger.info(f"成功获取{self.game_name_cn}当前up信息...当前up池: {title}")
|
||||
@@ -424,10 +419,8 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
self.load_up_char()
|
||||
if self.UP_CHAR and self.UP_CARD:
|
||||
return Message(
|
||||
Message.template("重载成功!\n当前UP池子:{}{:image}\n当前支援卡池子:{}{:image}").format(
|
||||
Message.template("重载成功!\n当前UP池子:{}\n当前支援卡池子:{}").format(
|
||||
self.UP_CHAR.up_name,
|
||||
self.UP_CHAR.pool_img,
|
||||
self.UP_CARD.up_name,
|
||||
self.UP_CARD.pool_img,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -67,7 +67,7 @@ async def _():
|
||||
gl = [g["group_id"] for g in gl]
|
||||
msg_list, code = await get_epic_free(bot, "Group")
|
||||
for g in gl:
|
||||
if await group_manager.check_group_task_status(g, "epic_free_game"):
|
||||
if group_manager.check_group_task_status(g, "epic_free_game"):
|
||||
try:
|
||||
if msg_list and code == 200:
|
||||
await bot.send_group_forward_msg(group_id=g, messages=msg_list)
|
||||
|
||||
+15
-6
@@ -1,6 +1,4 @@
|
||||
from io import BytesIO
|
||||
import imagehash
|
||||
from PIL import Image
|
||||
from utils.image_utils import get_img_hash
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from configs.path_config import TEMP_PATH
|
||||
import random
|
||||
@@ -10,6 +8,7 @@ from utils.utils import get_message_img, get_message_text
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from configs.config import Config
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME
|
||||
|
||||
|
||||
@@ -91,7 +90,7 @@ async def _(event: GroupMessageEvent):
|
||||
if not img and not msg:
|
||||
return
|
||||
if img:
|
||||
img_hash = await get_fudu_img_hash(img[0])
|
||||
img_hash = await get_fudu_img_hash(img[0],event.group_id)
|
||||
else:
|
||||
img_hash = ""
|
||||
add_msg = msg + "|-|" + img_hash
|
||||
@@ -124,5 +123,15 @@ async def _(event: GroupMessageEvent):
|
||||
await fudu.finish("[[_task|fudu]]" + rst)
|
||||
|
||||
|
||||
async def get_fudu_img_hash(url):
|
||||
return str(imagehash.average_hash(Image.open(BytesIO((await AsyncHttpx.get(url)).content))))
|
||||
async def get_fudu_img_hash(url, group_id):
|
||||
try:
|
||||
if await AsyncHttpx.download_file(
|
||||
url, TEMP_PATH / f"compare_{group_id}_img.jpg"
|
||||
):
|
||||
img_hash = get_img_hash(TEMP_PATH / f"compare_{group_id}_img.jpg")
|
||||
return str(img_hash)
|
||||
else:
|
||||
logger.warning(f"复读下载图片失败...")
|
||||
except Exception as e:
|
||||
logger.warning(f"复读读取图片Hash出错 {type(e)}:{e}")
|
||||
return ""
|
||||
|
||||
@@ -71,5 +71,5 @@ async def _():
|
||||
if alc_img:
|
||||
mes = "[[_task|genshin_alc]]" + alc_img + "\n ※ 黄历数据来源于 genshin.pub"
|
||||
for gid in gl:
|
||||
if await group_manager.check_group_task_status(gid, "genshin_alc"):
|
||||
if group_manager.check_group_task_status(gid, "genshin_alc"):
|
||||
await bot.send_group_msg(group_id=int(gid), message="" + mes)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from configs.path_config import IMAGE_PATH, TEXT_PATH
|
||||
from configs.path_config import IMAGE_PATH, TEXT_PATH, TEMP_PATH
|
||||
from utils.image_utils import BuildImage
|
||||
from typing import Tuple, List
|
||||
from math import sqrt, pow
|
||||
@@ -118,7 +118,7 @@ class Map:
|
||||
self._generate_best_route()
|
||||
self.map.crop((min_width, min_height, max_width, max_height))
|
||||
rand = random.randint(1, 10000)
|
||||
self.map.save(f"{TEXT_PATH}/genshin_map_{rand}.png")
|
||||
self.map.save(f"{TEMP_PATH}/genshin_map_{rand}.png")
|
||||
return rand
|
||||
|
||||
# 资源数量
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from pathlib import Path
|
||||
from typing import Tuple, Optional, List
|
||||
from configs.path_config import IMAGE_PATH, TEXT_PATH
|
||||
from configs.path_config import IMAGE_PATH, TEXT_PATH, TEMP_PATH
|
||||
from utils.message_builder import image
|
||||
from services.log import logger
|
||||
from utils.image_utils import BuildImage
|
||||
@@ -57,7 +57,7 @@ async def query_resource(resource_name: str) -> str:
|
||||
None, map_.generate_resource_icon_in_map
|
||||
)
|
||||
return (
|
||||
f"{image(f'genshin_map_{rand}.png', 'temp')}"
|
||||
f"{image(TEMP_PATH / f'genshin_map_{rand}.png')}"
|
||||
f"\n\n※ {resource_name} 一共找到 {count} 个位置点\n※ 数据来源于米游社wiki"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from services.log import logger
|
||||
from .data_source import get_user_memo, get_memo
|
||||
from .._models import Genshin
|
||||
from nonebot.plugin import export
|
||||
|
||||
|
||||
__zx_plugin_name__ = "原神便笺查询"
|
||||
@@ -28,10 +27,6 @@ __plugin_settings__ = {
|
||||
__plugin_block_limit__ = {}
|
||||
|
||||
|
||||
export = export()
|
||||
|
||||
export.get_memo = get_memo
|
||||
|
||||
query_memo_matcher = on_command("原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True)
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ import pytz
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
get_memo = require("query_memo").get_memo
|
||||
require("query_memo")
|
||||
|
||||
from ..query_memo import get_memo
|
||||
|
||||
|
||||
global_map = {}
|
||||
|
||||
@@ -101,7 +101,7 @@ cases_matcher_group = MatcherGroup(priority=5, permission=GROUP, block=True)
|
||||
|
||||
k_open_case = cases_matcher_group.on_command("开箱")
|
||||
|
||||
reload_count = cases_matcher_group.on_command("重置开箱")
|
||||
reload_count = cases_matcher_group.on_command("重置开箱",permission=SUPERUSER)
|
||||
|
||||
|
||||
@reload_count.handle()
|
||||
|
||||
@@ -31,7 +31,7 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
|
||||
async with db.transaction():
|
||||
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
|
||||
# 一天次数上限
|
||||
if user.today_open_total > int(
|
||||
if user.today_open_total >= int(
|
||||
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
|
||||
+ int(impression)
|
||||
/ Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
|
||||
@@ -155,7 +155,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
|
||||
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
|
||||
+ int(impression) / Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
|
||||
)
|
||||
if user.today_open_total == max_count:
|
||||
if user.today_open_total >= max_count:
|
||||
return _handle_is_MAX_COUNT()
|
||||
if max_count - user.today_open_total < num:
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from nonebot import on_message
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, ActionFailed
|
||||
|
||||
from utils.manager import group_manager
|
||||
from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from utils.message_builder import image
|
||||
@@ -34,7 +36,10 @@ Config.add_plugin_config(
|
||||
)
|
||||
|
||||
|
||||
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
|
||||
async def plugin_on_checker(event: GroupMessageEvent) -> bool:
|
||||
return group_manager.get_plugin_status("parse_bilibili_json", event.group_id)
|
||||
|
||||
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False, rule=plugin_on_checker)
|
||||
|
||||
_tmp = {}
|
||||
|
||||
@@ -124,7 +129,7 @@ async def _(event: GroupMessageEvent):
|
||||
url,
|
||||
timeout=7,
|
||||
) as response:
|
||||
url = str(response.url).split("?")[0]
|
||||
url = (str(response.url).split("?")[0]).strip("/")
|
||||
bvid = url.split("/")[-1]
|
||||
vd_info = await video.get_video_base_info(bvid)
|
||||
if vd_info:
|
||||
|
||||
@@ -50,7 +50,7 @@ headers = {
|
||||
|
||||
@pid_search.got("pid", prompt="需要查询的图片PID是?")
|
||||
async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
|
||||
url = Config.get_config("hibiapi", "HIBIAPI") + "/api/pixiv/"
|
||||
url = Config.get_config("hibiapi", "HIBIAPI") + "/api/pixiv/illust"
|
||||
if pid in ["取消", "算了"]:
|
||||
await pid_search.finish("已取消操作...")
|
||||
if not is_number(pid):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from configs.config import Config
|
||||
from utils.manager import GDict
|
||||
from utils.utils import GDict
|
||||
import nonebot
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from .._model import Setu
|
||||
import asyncio
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
@@ -22,6 +23,7 @@ except ModuleNotFoundError:
|
||||
url = "https://api.lolicon.app/setu/v2"
|
||||
path = "_setu"
|
||||
r18_path = "_r18"
|
||||
host_pattern = re.compile(r"https?://([^/]+)")
|
||||
|
||||
|
||||
# 获取url
|
||||
@@ -89,7 +91,9 @@ async def search_online_setu(
|
||||
"""
|
||||
ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
|
||||
if ws_url:
|
||||
url_ = url_.replace("i.pximg.net", ws_url).replace("i.pixiv.cat", ws_url)
|
||||
host_match = re.match(host_pattern, url_)
|
||||
host = host_match.group(1)
|
||||
url_ = url_.replace(host, ws_url)
|
||||
index = random.randint(1, 100000) if id_ is None else id_
|
||||
path_ = IMAGE_PATH / path_ if path_ else TEMP_PATH
|
||||
file_name = f"{index}_temp_setu.jpg" if path_ == TEMP_PATH else f"{index}.jpg"
|
||||
|
||||
@@ -18,6 +18,7 @@ from configs.path_config import DATA_PATH
|
||||
from services.log import logger
|
||||
from .utils import clear_sign_data_pic
|
||||
from utils.utils import is_number
|
||||
from .goods_register import driver
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
from models.sign_group_user import SignGroupUser
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
from utils.decorator.shop import shop_register, NotMeetUseConditionsException
|
||||
import nonebot
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
"""
|
||||
导入内置的三个商品
|
||||
"""
|
||||
|
||||
@shop_register(
|
||||
name=("好感度双倍加持卡Ⅰ", "好感度双倍加持卡Ⅱ", "好感度双倍加持卡Ⅲ"),
|
||||
price=(30, 150, 250),
|
||||
des=(
|
||||
"下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
|
||||
"下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)",
|
||||
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
|
||||
),
|
||||
load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
|
||||
icon=("favorability_card_1.png", "favorability_card_2.png", "favorability_card_3.png"),
|
||||
** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
|
||||
)
|
||||
async def sign_card(user_id: int, group_id: int, prob: float):
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=prob).apply()
|
||||
|
||||
@shop_register(
|
||||
name="测试道具A",
|
||||
price=99,
|
||||
des="随便侧而出",
|
||||
load_status=False,
|
||||
icon="sword.png",
|
||||
)
|
||||
async def _(user_id: int, group_id: int):
|
||||
print(user_id, group_id, '使用测试道具')
|
||||
|
||||
@shop_register.before_handle(name="测试道具A", load_status=False)
|
||||
async def _(user_id: int, group_id: int):
|
||||
print(user_id, group_id, '第一个使用前函数(before handle)')
|
||||
|
||||
@shop_register.before_handle(name="测试道具A", load_status=False)
|
||||
async def _(user_id: int, group_id: int):
|
||||
print(user_id, group_id, '第二个使用前函数(before handle)222')
|
||||
raise NotMeetUseConditionsException("太笨了!") # 抛出异常,阻断使用,并返回信息
|
||||
|
||||
@shop_register.after_handle(name="测试道具A", load_status=False)
|
||||
async def _(user_id: int, group_id: int):
|
||||
print(user_id, group_id, '第一个使用后函数(after handle)')
|
||||
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ async def generate_statistics_img(
|
||||
data: dict, arg: str, name: str, plugin: str, day_index: int
|
||||
):
|
||||
try:
|
||||
plugin = plugins2settings_manager.get_plugin_data(plugin)['cmd'][0]
|
||||
plugin = plugins2settings_manager.get_plugin_data(plugin).cmd[0]
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
bar_graph = None
|
||||
|
||||
@@ -107,8 +107,8 @@ async def _(
|
||||
group_id = "total"
|
||||
user_id = str(event.user_id)
|
||||
plugin_name = plugins2settings_manager.get_plugin_data(module)
|
||||
if plugin_name and plugin_name.get('cmd'):
|
||||
plugin_name = plugin_name.get('cmd')[0]
|
||||
if plugin_name and plugin_name.cmd:
|
||||
plugin_name = plugin_name.cmd[0]
|
||||
check_exists_key(group_id, user_id, plugin_name)
|
||||
for data in [_prefix_count_dict, _prefix_user_count_dict]:
|
||||
data["total_statistics"]["total"][plugin_name] += 1
|
||||
|
||||
@@ -25,27 +25,22 @@ async def get_weather_of_city(city: str) -> str:
|
||||
elif code == 998:
|
||||
return f"{NICKNAME}没查到!!试试查火星的天气?"
|
||||
else:
|
||||
data_json = json.loads(
|
||||
(
|
||||
await AsyncHttpx.get(
|
||||
f"http://wthrcdn.etouch.cn/weather_mini?city={city}"
|
||||
)
|
||||
).text
|
||||
)
|
||||
if "desc" in data_json:
|
||||
if data_json["desc"] == "invilad-citykey":
|
||||
return f"{NICKNAME}没查到!!试试查火星的天气?" + image("shengqi", "zhenxun")
|
||||
elif data_json["desc"] == "OK":
|
||||
w_type = data_json["data"]["forecast"][0]["type"]
|
||||
w_max = data_json["data"]["forecast"][0]["high"][3:]
|
||||
w_min = data_json["data"]["forecast"][0]["low"][3:]
|
||||
fengli = data_json["data"]["forecast"][0]["fengli"][9:-3]
|
||||
ganmao = data_json["data"]["ganmao"]
|
||||
fengxiang = data_json["data"]["forecast"][0]["fengxiang"]
|
||||
repass = f"{city}的天气是 {w_type} 天\n最高温度: {w_max}\n最低温度: {w_min}\n风力: {fengli} {fengxiang}\n{ganmao}"
|
||||
return repass
|
||||
data_json = (
|
||||
await AsyncHttpx.get(
|
||||
f"https://v0.yiketianqi.com/api?unescape=1&version=v91&appid=43656176&appsecret=I42og6Lm&ext=&cityid=&city={city[:-1]}"
|
||||
)
|
||||
).json()
|
||||
if wh := data_json.get('data'):
|
||||
w_type = wh[0]["wea_day"]
|
||||
w_max = wh[0]["tem1"]
|
||||
w_min = wh[0]["tem2"]
|
||||
fengli = wh[0]["win_speed"]
|
||||
ganmao = wh[0]["narrative"]
|
||||
fengxiang = ','.join(wh[0].get('win', []))
|
||||
repass = f"{city}的天气是 {w_type} 天\n最高温度: {w_max}\n最低温度: {w_min}\n风力: {fengli} {fengxiang}\n{ganmao}"
|
||||
return repass
|
||||
else:
|
||||
return "好像出错了?再试试?"
|
||||
return data_json.get("errmsg") or "好像出错了?再试试?"
|
||||
|
||||
|
||||
def _check_exists_city(city: str) -> int:
|
||||
|
||||
@@ -23,11 +23,11 @@ gConfig.add_plugin_config("web-ui", "password", None, name="web-ui", help_="前
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
flag = False
|
||||
for module in plugins2settings_manager.keys():
|
||||
if isinstance(plugins2settings_manager.get_plugin_data(module).get("cmd"), str):
|
||||
if isinstance(plugins2settings_manager.get_plugin_data(module).cmd, str):
|
||||
plugins2settings_manager.set_module_data(
|
||||
module,
|
||||
"cmd",
|
||||
plugins2settings_manager.get_plugin_data(module).get("cmd").split(","),
|
||||
plugins2settings_manager.get_plugin_data(module).cmd.split(","),
|
||||
False
|
||||
)
|
||||
flag = True
|
||||
|
||||
@@ -61,8 +61,8 @@ def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
|
||||
)
|
||||
data["plugin_manager"] = PluginManager(**x)
|
||||
if x := plugins2settings_manager.get(model):
|
||||
if x.get("cmd") and isinstance(x.get("cmd"), list):
|
||||
x["cmd"] = ",".join(x["cmd"])
|
||||
if x.cmd and isinstance(x.cmd, list):
|
||||
x.cmd = ",".join(x.cmd)
|
||||
data["plugin_settings"] = PluginSettings(**x)
|
||||
if x := plugins2cd_manager.get(model):
|
||||
data["cd_limit"] = CdLimit(**x)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import imagehash
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
from httpx import TimeoutException
|
||||
from services.log import logger
|
||||
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||
@@ -20,8 +20,8 @@ async def check(event: MessageEvent, state: T_State) -> bool:
|
||||
try:
|
||||
r = await AsyncHttpx.get(img[0])
|
||||
problem = str(imagehash.average_hash(Image.open(BytesIO(r.content))))
|
||||
except TimeoutException:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.warning(f"word_bank rule 获取图片失败 {type(e)}:{e}")
|
||||
if at:
|
||||
temp = ''
|
||||
for seg in event.message:
|
||||
|
||||
@@ -57,6 +57,8 @@ async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
|
||||
dead = data_["total"]["dead"] # 累计死亡
|
||||
now_confirm = data_["total"]["nowConfirm"] # 目前确诊
|
||||
add_confirm = data_["today"]["confirm"] # 新增确诊
|
||||
add_wzz = data_["today"]["wzz_add"] #新增无症状
|
||||
wzz=data_["total"]["wzz"] #目前无症状
|
||||
grade = ""
|
||||
_grade_color = ""
|
||||
# if data_["total"].get("grade"):
|
||||
@@ -75,8 +77,10 @@ async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
|
||||
{x} 疫情数据 {f"(<f font_color={_grade_color}>{grade}</f>)" if grade else ""}:
|
||||
目前确诊:
|
||||
确诊人数:<f font_color=red>{now_confirm}(+{add_confirm})</f>
|
||||
新增无症状:<f font_color=red>{add_wzz}</f>
|
||||
-----------------
|
||||
累计数据:
|
||||
无症状人数:<f font_color=red>{wzz}</f>
|
||||
确诊人数:<f font_color=red>{confirm}</f>
|
||||
治愈人数:<f font_color=#39de4b>{heal}</f>
|
||||
死亡人数:<f font_color=#191d19>{dead}</f>
|
||||
|
||||
Generated
+1548
-891
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -12,18 +12,15 @@ url = "https://mirrors.aliyun.com/pypi/simple/"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
nonebot2 = "^2.0.0-beta.4"
|
||||
nonebot-adapter-onebot = "^2.0.0-beta.1"
|
||||
nonebot2 = "^2.0.0rc1"
|
||||
aiofiles = "^0.8.0"
|
||||
aiohttp = "3.7.4.post0"
|
||||
beautifulsoup4 = "4.9.3"
|
||||
feedparser = "^6.0.8"
|
||||
gino = "^1.0.1"
|
||||
httpx = "^0.23.0"
|
||||
ImageHash = "^4.2.1"
|
||||
jieba = "^0.42.1"
|
||||
lxml = "4.6.5"
|
||||
nonebot-plugin-apscheduler = "^0.1.2"
|
||||
opencv-python = "^4.5.5"
|
||||
Pillow = "^9.0.1"
|
||||
playwright = "^1.18.2"
|
||||
@@ -39,10 +36,13 @@ dateparser = "^1.1.0"
|
||||
cn2an = "^0.5.16"
|
||||
python-jose = "^3.3.0"
|
||||
python-multipart = "^0.0.5"
|
||||
bilireq = "^0.2.0"
|
||||
bilireq = "^0.2.3.post0"
|
||||
emoji = "^1.7.0"
|
||||
wordcloud = "^1.8.1"
|
||||
rich = "^12.4.3"
|
||||
gino = "^1.0.1"
|
||||
nonebot-adapter-onebot = "^2.1.5"
|
||||
nonebot-plugin-apscheduler = "^0.2.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
+97
-47
@@ -1,17 +1,52 @@
|
||||
from typing import Callable, Union, Tuple
|
||||
from typing import Callable, Union, Tuple, Optional
|
||||
from nonebot.adapters.onebot.v11 import MessageSegment, Message
|
||||
from nonebot.plugin import require
|
||||
|
||||
|
||||
use = require("use")
|
||||
shop = require("shop_handle")
|
||||
|
||||
|
||||
class ShopRegister(dict):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ShopRegister, self).__init__(*args, **kwargs)
|
||||
self._data = {}
|
||||
self._flag = True
|
||||
|
||||
def before_handle(self, name: Union[str, Tuple[str, ...]], load_status: bool = True):
|
||||
"""
|
||||
说明:
|
||||
使用前检查方法
|
||||
参数:
|
||||
:param name: 道具名称
|
||||
:param load_status: 加载状态
|
||||
"""
|
||||
def register_before_handle(name_list: Tuple[str, ...], func: Callable):
|
||||
if load_status:
|
||||
for name_ in name_list:
|
||||
if not self._data[name_]:
|
||||
self._data[name_] = {}
|
||||
if not self._data[name_].get('before_handle'):
|
||||
self._data[name_]['before_handle'] = []
|
||||
self._data[name]['before_handle'].append(func)
|
||||
_name = (name,) if isinstance(name, str) else name
|
||||
return lambda func: register_before_handle(_name, func)
|
||||
|
||||
def after_handle(self, name: Union[str, Tuple[str, ...]], load_status: bool = True):
|
||||
"""
|
||||
说明:
|
||||
使用后执行方法
|
||||
参数:
|
||||
:param name: 道具名称
|
||||
:param load_status: 加载状态
|
||||
"""
|
||||
def register_after_handle(name_list: Tuple[str, ...], func: Callable):
|
||||
if load_status:
|
||||
for name_ in name_list:
|
||||
if not self._data[name_]:
|
||||
self._data[name_] = {}
|
||||
if not self._data[name_].get('after_handle'):
|
||||
self._data[name_]['after_handle'] = []
|
||||
self._data[name_]['after_handle'].append(func)
|
||||
_name = (name,) if isinstance(name, str) else name
|
||||
return lambda func: register_after_handle(_name, func)
|
||||
|
||||
def register(
|
||||
self,
|
||||
name: Tuple[str, ...],
|
||||
@@ -21,13 +56,15 @@ class ShopRegister(dict):
|
||||
limit_time: Tuple[int, ...],
|
||||
load_status: Tuple[bool, ...],
|
||||
daily_limit: Tuple[int, ...],
|
||||
is_passive: Tuple[bool, ...],
|
||||
icon: Tuple[str, ...],
|
||||
**kwargs,
|
||||
):
|
||||
def add_register_item(func: Callable):
|
||||
if name in self._data.keys():
|
||||
raise ValueError("该商品已注册,请替换其他名称!")
|
||||
for n, p, d, dd, l, s, dl in zip(
|
||||
name, price, des, discount, limit_time, load_status, daily_limit
|
||||
for n, p, d, dd, l, s, dl, pa, i in zip(
|
||||
name, price, des, discount, limit_time, load_status, daily_limit, is_passive, icon
|
||||
):
|
||||
if s:
|
||||
_temp_kwargs = {}
|
||||
@@ -36,46 +73,60 @@ class ShopRegister(dict):
|
||||
_temp_kwargs[key.split("_", maxsplit=1)[-1]] = value
|
||||
else:
|
||||
_temp_kwargs[key] = value
|
||||
self._data[n] = {
|
||||
temp = self._data.get(n, {})
|
||||
temp.update({
|
||||
"price": p,
|
||||
"des": d,
|
||||
"discount": dd,
|
||||
"limit_time": l,
|
||||
"daily_limit": dl,
|
||||
"icon": i,
|
||||
"is_passive": pa,
|
||||
"func": func,
|
||||
"kwargs": _temp_kwargs,
|
||||
}
|
||||
})
|
||||
self._data[n] = temp
|
||||
return func
|
||||
|
||||
return lambda func: add_register_item(func)
|
||||
|
||||
async def load_register(self):
|
||||
require("use")
|
||||
require("shop_handle")
|
||||
from basic_plugins.shop.use.data_source import register_use, func_manager
|
||||
from basic_plugins.shop.shop_handle.data_source import register_goods
|
||||
# 统一进行注册
|
||||
if self._flag:
|
||||
# 只进行一次注册
|
||||
self._flag = False
|
||||
for name in self._data.keys():
|
||||
await shop.register_goods(
|
||||
await register_goods(
|
||||
name,
|
||||
self._data[name]["price"],
|
||||
self._data[name]["des"],
|
||||
self._data[name]["discount"],
|
||||
self._data[name]["limit_time"],
|
||||
self._data[name]["daily_limit"],
|
||||
self._data[name]["is_passive"],
|
||||
self._data[name]["icon"],
|
||||
)
|
||||
use.register_use(
|
||||
register_use(
|
||||
name, self._data[name]["func"], **self._data[name]["kwargs"]
|
||||
)
|
||||
func_manager.register_use_before_handle(name, self._data[name].get('before_handle', []))
|
||||
func_manager.register_use_after_handle(name, self._data[name].get('after_handle', []))
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
name: Union[str, Tuple[str, ...]],
|
||||
price: Union[float, Tuple[float, ...]],
|
||||
des: Union[str, Tuple[str, ...]],
|
||||
discount: Union[float, Tuple[float, ...]] = 1,
|
||||
limit_time: Union[int, Tuple[int, ...]] = 0,
|
||||
load_status: Union[bool, Tuple[bool, ...]] = True,
|
||||
daily_limit: Union[int, Tuple[int, ...]] = 0,
|
||||
name: Union[str, Tuple[str, ...]], # 名称
|
||||
price: Union[float, Tuple[float, ...]], # 价格
|
||||
des: Union[str, Tuple[str, ...]], # 简介
|
||||
discount: Union[float, Tuple[float, ...]] = 1, # 折扣
|
||||
limit_time: Union[int, Tuple[int, ...]] = 0, # 限时
|
||||
load_status: Union[bool, Tuple[bool, ...]] = True, # 加载状态
|
||||
daily_limit: Union[int, Tuple[int, ...]] = 0, # 每日限购
|
||||
is_passive: Union[bool, Tuple[bool, ...]] = False, # 被动道具(无法被'使用道具'命令消耗)
|
||||
icon: Union[str, Tuple[str, ...]] = False, # 图标
|
||||
**kwargs,
|
||||
):
|
||||
_tuple_list = []
|
||||
@@ -89,35 +140,15 @@ class ShopRegister(dict):
|
||||
f"注册商品 {name} 中 name,price,des,discount,limit_time,load_status,daily_limit 数量不符!"
|
||||
)
|
||||
_current_len = _current_len if _current_len > -1 else 1
|
||||
_name = name if isinstance(name, tuple) else (name,)
|
||||
_price = (
|
||||
price
|
||||
if isinstance(price, tuple)
|
||||
else tuple([price for _ in range(_current_len)])
|
||||
)
|
||||
_discount = (
|
||||
discount
|
||||
if isinstance(discount, tuple)
|
||||
else tuple([discount for _ in range(_current_len)])
|
||||
)
|
||||
_limit_time = (
|
||||
limit_time
|
||||
if isinstance(limit_time, tuple)
|
||||
else tuple([limit_time for _ in range(_current_len)])
|
||||
)
|
||||
_des = (
|
||||
des if isinstance(des, tuple) else tuple([des for _ in range(_current_len)])
|
||||
)
|
||||
_load_status = (
|
||||
load_status
|
||||
if isinstance(load_status, tuple)
|
||||
else tuple([load_status for _ in range(_current_len)])
|
||||
)
|
||||
_daily_limit = (
|
||||
daily_limit
|
||||
if isinstance(daily_limit, tuple)
|
||||
else tuple([daily_limit for _ in range(_current_len)])
|
||||
)
|
||||
_name = self.__get(name, _current_len)
|
||||
_price = self.__get(price, _current_len)
|
||||
_discount = self.__get(discount, _current_len)
|
||||
_limit_time = self.__get(limit_time, _current_len)
|
||||
_des = self.__get(des, _current_len)
|
||||
_load_status = self.__get(load_status, _current_len)
|
||||
_daily_limit = self.__get(daily_limit, _current_len)
|
||||
_is_passive = self.__get(is_passive, _current_len)
|
||||
_icon = self.__get(icon, _current_len)
|
||||
return self.register(
|
||||
_name,
|
||||
_price,
|
||||
@@ -126,9 +157,14 @@ class ShopRegister(dict):
|
||||
_limit_time,
|
||||
_load_status,
|
||||
_daily_limit,
|
||||
_is_passive,
|
||||
_icon,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def __get(self, value, _current_len):
|
||||
return value if isinstance(value, tuple) else tuple([value for _ in range(_current_len)])
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._data[key] = value
|
||||
|
||||
@@ -151,4 +187,18 @@ class ShopRegister(dict):
|
||||
return self._data.items()
|
||||
|
||||
|
||||
class NotMeetUseConditionsException(Exception):
|
||||
|
||||
"""
|
||||
不满足条件异常类
|
||||
"""
|
||||
|
||||
def __init__(self, info: Optional[Union[str, MessageSegment, Message]]):
|
||||
super().__init__(self)
|
||||
self._info = info
|
||||
|
||||
def get_info(self):
|
||||
return self._info
|
||||
|
||||
|
||||
shop_register = ShopRegister()
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
from typing import List, Callable, Optional, Union
|
||||
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
|
||||
from nonebot.internal.matcher import Matcher
|
||||
from nonebot.internal.params import Depends
|
||||
from models.user_shop_gold_log import UserShopGoldLog
|
||||
from models.bag_user import BagUser
|
||||
from utils.message_builder import at
|
||||
from utils.utils import get_message_at, get_message_face, get_message_img, get_message_text
|
||||
from configs.config import Config
|
||||
|
||||
|
||||
def CostGold(gold: int):
|
||||
"""
|
||||
说明:
|
||||
插件方法调用使用金币
|
||||
参数:
|
||||
:param gold: 金币数量
|
||||
"""
|
||||
async def dependency(matcher: Matcher, event: GroupMessageEvent):
|
||||
if (await BagUser.get_gold(event.user_id, event.group_id)) < gold:
|
||||
await matcher.finish(at(event.user_id) + f"金币不足..该功能需要{gold}金币..")
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, gold)
|
||||
await UserShopGoldLog.add_shop_log(event.user_id, event.group_id, 2, matcher.plugin_name, gold, 1)
|
||||
|
||||
return Depends(dependency)
|
||||
|
||||
|
||||
def GetConfig(module: Optional[str] = None, config: str = "", default_value: Optional[str] = None, prompt: Optional[str] = None):
|
||||
"""
|
||||
说明:
|
||||
获取配置项
|
||||
参数:
|
||||
:param module: 模块名,为空时默认使用当前插件模块名
|
||||
:param config: 配置项名称
|
||||
:param default_value: 默认值
|
||||
:param prompt: 为空时提示
|
||||
"""
|
||||
async def dependency(matcher: Matcher):
|
||||
module_ = module or matcher.plugin_name
|
||||
value = Config.get_config(module_, config, default_value)
|
||||
if value is None:
|
||||
await matcher.finish(prompt or f"配置项 {config} 未填写!")
|
||||
return value
|
||||
|
||||
return Depends(dependency)
|
||||
|
||||
|
||||
def CheckConfig(module: Optional[str] = None, config: Union[str, List[str]] = "", prompt: Optional[str] = None):
|
||||
"""
|
||||
说明:
|
||||
检测配置项在配置文件中是否填写
|
||||
参数:
|
||||
:param module: 模块名,为空时默认使用当前插件模块名
|
||||
:param config: 需要检查的配置项名称
|
||||
:param prompt: 为空时提示
|
||||
"""
|
||||
async def dependency(matcher: Matcher):
|
||||
module_ = module or matcher.plugin_name
|
||||
config_list = [config] if isinstance(config, str) else config
|
||||
for c in config_list:
|
||||
if Config.get_config(module_, c) is None:
|
||||
await matcher.finish(prompt or f"配置项 {c} 未填写!")
|
||||
|
||||
return Depends(dependency)
|
||||
|
||||
|
||||
async def _match(matcher: Matcher, event: MessageEvent, msg: Optional[str], func: Callable, contain_reply: bool):
|
||||
_list = func(event.message)
|
||||
if event.reply and contain_reply:
|
||||
_list = func(event.reply.message)
|
||||
if not _list and msg:
|
||||
await matcher.finish(msg)
|
||||
return _list
|
||||
|
||||
|
||||
def ImageList(msg: Optional[str] = None, contain_reply: bool = True) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
获取图片列表(包括回复时),含有msg时不能为空,为空时提示并结束事件
|
||||
参数:
|
||||
:param msg: 提示文本
|
||||
:param contain_reply: 包含回复内容
|
||||
"""
|
||||
async def dependency(matcher: Matcher, event: MessageEvent):
|
||||
return await _match(matcher, event, msg, get_message_img, contain_reply)
|
||||
|
||||
return Depends(dependency)
|
||||
|
||||
|
||||
def AtList(msg: Optional[str] = None, contain_reply: bool = True) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
获取at列表(包括回复时),含有msg时不能为空,为空时提示并结束事件
|
||||
参数:
|
||||
:param msg: 提示文本
|
||||
:param contain_reply: 包含回复内容
|
||||
"""
|
||||
async def dependency(matcher: Matcher, event: MessageEvent):
|
||||
return await _match(matcher, event, msg, get_message_at, contain_reply)
|
||||
|
||||
return Depends(dependency)
|
||||
|
||||
|
||||
def FaceList(msg: Optional[str] = None, contain_reply: bool = True) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
获取face列表(包括回复时),含有msg时不能为空,为空时提示并结束事件
|
||||
参数:
|
||||
:param msg: 提示文本
|
||||
:param contain_reply: 包含回复内容
|
||||
"""
|
||||
async def dependency(matcher: Matcher, event: MessageEvent):
|
||||
return await _match(matcher, event, msg, get_message_face, contain_reply)
|
||||
|
||||
return Depends(dependency)
|
||||
|
||||
|
||||
def PlaintText(msg: Optional[str] = None, contain_reply: bool = True) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取纯文本且(包括回复时),含有msg时不能为空,为空时提示并结束事件
|
||||
参数:
|
||||
:param msg: 提示文本
|
||||
:param contain_reply: 包含回复内容
|
||||
"""
|
||||
async def dependency(matcher: Matcher, event: MessageEvent):
|
||||
return await _match(matcher, event, msg, get_message_text, contain_reply)
|
||||
|
||||
return Depends(dependency)
|
||||
|
||||
@@ -44,6 +44,7 @@ class AsyncHttpx:
|
||||
:param params: params
|
||||
:param headers: 请求头
|
||||
:param cookies: cookies
|
||||
:param verify: verify
|
||||
:param use_proxy: 使用默认代理
|
||||
:param proxy: 指定代理
|
||||
:param timeout: 超时时间
|
||||
|
||||
@@ -2,11 +2,12 @@ import asyncio
|
||||
import base64
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
from io import BytesIO
|
||||
from math import ceil
|
||||
from pathlib import Path
|
||||
from typing import List, Literal, Optional, Tuple, Union
|
||||
|
||||
import uuid
|
||||
import cv2
|
||||
import imagehash
|
||||
from configs.path_config import FONT_PATH, IMAGE_PATH
|
||||
@@ -180,6 +181,7 @@ class BuildImage:
|
||||
self.paste_image_height = int(paste_image_height)
|
||||
self._current_w = 0
|
||||
self._current_h = 0
|
||||
self.uid = uuid.uuid1()
|
||||
self.font = ImageFont.truetype(str(FONT_PATH / font), int(font_size))
|
||||
if not plain_text and not color:
|
||||
color = (255, 255, 255)
|
||||
|
||||
@@ -14,10 +14,8 @@ from .requests_manager import RequestManager
|
||||
from configs.path_config import DATA_PATH
|
||||
|
||||
|
||||
# 全局字典
|
||||
GDict = {
|
||||
"run_sql": [] # 需要启动前运行的sql语句
|
||||
}
|
||||
# 管理员命令管理器
|
||||
admin_manager = AdminManager()
|
||||
|
||||
# 群功能开关 | 群被动技能 | 群权限 管理
|
||||
group_manager: Optional[GroupManager] = GroupManager(
|
||||
@@ -67,5 +65,3 @@ requests_manager: Optional[RequestManager] = RequestManager(
|
||||
DATA_PATH / "manager" / "requests_manager.json"
|
||||
)
|
||||
|
||||
# 管理员命令管理器
|
||||
admin_manager = AdminManager()
|
||||
|
||||
Executable → Regular
+38
-26
@@ -1,5 +1,6 @@
|
||||
from .data_class import StaticData
|
||||
from typing import List, Optional
|
||||
from .models import AdminSetting
|
||||
from utils.manager.data_class import StaticData
|
||||
from typing import List, Optional, Dict
|
||||
|
||||
|
||||
class AdminManager(StaticData):
|
||||
@@ -9,60 +10,71 @@ class AdminManager(StaticData):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
self._data: Dict[str, AdminSetting] = {}
|
||||
|
||||
def add_admin_plugin_settings(self, plugin: str, cmd: List[str], level: int):
|
||||
"""
|
||||
添加一个管理员命令
|
||||
:param plugin: 模块
|
||||
:param cmd: 别名
|
||||
:param level: 等级
|
||||
说明:
|
||||
添加一个管理员命令
|
||||
参数:
|
||||
:param plugin: 模块
|
||||
:param cmd: 别名
|
||||
:param level: 等级
|
||||
"""
|
||||
self._data[plugin] = {
|
||||
"level": level,
|
||||
"cmd": cmd,
|
||||
}
|
||||
self._data[plugin] = AdminSetting(level=level, cmd=cmd)
|
||||
|
||||
def set_admin_level(self, plugin: str, level: int):
|
||||
"""
|
||||
设置管理员命令等级
|
||||
:param plugin: 模块名
|
||||
:param level: 权限等级
|
||||
说明:
|
||||
设置管理员命令等级
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
:param level: 权限等级
|
||||
"""
|
||||
self._data[plugin]["level"] = level
|
||||
if plugin in self._data.keys():
|
||||
self._data[plugin].level = level
|
||||
|
||||
def remove_admin_plugin_settings(self, plugin: str):
|
||||
"""
|
||||
删除一个管理员命令
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
删除一个管理员命令
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if plugin in self._data.keys():
|
||||
del self._data[plugin]
|
||||
|
||||
def check(self, plugin: str, level: int) -> bool:
|
||||
"""
|
||||
检查是否满足权限
|
||||
:param plugin: 模块名
|
||||
:param level: 权限等级
|
||||
说明:
|
||||
检查是否满足权限
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
:param level: 权限等级
|
||||
"""
|
||||
if plugin in self._data.keys():
|
||||
return level >= self._data[plugin]["level"]
|
||||
return level >= self._data[plugin].level
|
||||
return True
|
||||
|
||||
def get_plugin_level(self, plugin: str) -> int:
|
||||
"""
|
||||
获取插件等级
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
获取插件等级
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if plugin in self._data.keys():
|
||||
return self._data[plugin]["level"]
|
||||
return self._data[plugin].level
|
||||
return 0
|
||||
|
||||
def get_plugin_module(self, cmd: str) -> Optional[str]:
|
||||
"""
|
||||
根据 cmd 获取功能 modules
|
||||
:param cmd: 命令
|
||||
说明:
|
||||
根据 cmd 获取功能 modules
|
||||
参数:
|
||||
:param cmd: 命令
|
||||
"""
|
||||
for key in self._data.keys():
|
||||
if self._data[key].get("cmd") and cmd in self._data[key]["cmd"]:
|
||||
if self._data[key].cmd and cmd in self._data[key].cmd:
|
||||
return key
|
||||
return None
|
||||
|
||||
Executable → Regular
+32
-18
@@ -1,24 +1,29 @@
|
||||
from typing import Union, Optional
|
||||
from typing import Union, Optional, TypeVar, Generic, Dict, NoReturn, Any
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from ruamel import yaml
|
||||
import ujson as json
|
||||
import copy
|
||||
|
||||
from .models import *
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
class StaticData:
|
||||
T = TypeVar("T", AdminSetting, BaseData, PluginBlock, PluginCd, PluginCount, PluginSetting, Plugin)
|
||||
|
||||
|
||||
class StaticData(Generic[T]):
|
||||
"""
|
||||
静态数据共享类
|
||||
"""
|
||||
|
||||
def __init__(self, file: Optional[Path]):
|
||||
def __init__(self, file: Optional[Path], load_file: bool = True):
|
||||
self._data: dict = {}
|
||||
if file:
|
||||
file.parent.mkdir(exist_ok=True, parents=True)
|
||||
self.file = file
|
||||
if file.exists():
|
||||
if file.exists() and load_file:
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
if file.name.endswith("json"):
|
||||
try:
|
||||
@@ -29,30 +34,39 @@ class StaticData:
|
||||
elif file.name.endswith("yaml"):
|
||||
self._data = _yaml.load(f)
|
||||
|
||||
def set(self, key, value):
|
||||
def set(self, key, value) -> NoReturn:
|
||||
self._data[key] = value
|
||||
self.save()
|
||||
|
||||
def set_module_data(self, module, key, value, auto_save: bool = True):
|
||||
def set_module_data(self, module, key, value, auto_save: bool = True) -> NoReturn:
|
||||
if module in self._data.keys():
|
||||
self._data[module][key] = value
|
||||
if auto_save:
|
||||
self.save()
|
||||
|
||||
def get(self, key):
|
||||
def get(self, key) -> T:
|
||||
return self._data.get(key)
|
||||
|
||||
def keys(self):
|
||||
def keys(self) -> List[str]:
|
||||
return self._data.keys()
|
||||
|
||||
def delete(self, key):
|
||||
def delete(self, key) -> NoReturn:
|
||||
if self._data.get(key) is not None:
|
||||
del self._data[key]
|
||||
|
||||
def get_data(self) -> dict:
|
||||
def get_data(self) -> Dict[str, T]:
|
||||
return copy.deepcopy(self._data)
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
def dict(self) -> Dict[str, Any]:
|
||||
temp = {}
|
||||
for k, v in self._data.items():
|
||||
try:
|
||||
temp[k] = v.dict()
|
||||
except AttributeError:
|
||||
temp[k] = copy.deepcopy(v)
|
||||
return temp
|
||||
|
||||
def save(self, path: Union[str, Path] = None) -> NoReturn:
|
||||
path = path or self.file
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
@@ -61,26 +75,26 @@ class StaticData:
|
||||
if path.name.endswith("yaml"):
|
||||
yaml.dump(self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
else:
|
||||
json.dump(self._data, f, ensure_ascii=False, indent=4)
|
||||
json.dump(self.dict(), f, ensure_ascii=False, indent=4)
|
||||
|
||||
def reload(self):
|
||||
def reload(self) -> NoReturn:
|
||||
if self.file.exists():
|
||||
if self.file.name.endswith("json"):
|
||||
self._data: dict = json.load(open(self.file, "r", encoding="utf8"))
|
||||
elif self.file.name.endswith("yaml"):
|
||||
self._data: dict = _yaml.load(open(self.file, "r", encoding="utf8"))
|
||||
|
||||
def is_exists(self):
|
||||
def is_exists(self) -> bool:
|
||||
return self.file.exists()
|
||||
|
||||
def is_empty(self):
|
||||
def is_empty(self) -> bool:
|
||||
return bool(len(self._data))
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return str(self._data)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
def __setitem__(self, key, value) -> NoReturn:
|
||||
self._data[key] = value
|
||||
|
||||
def __getitem__(self, key):
|
||||
def __getitem__(self, key) -> T:
|
||||
return self._data[key]
|
||||
|
||||
Executable → Regular
+352
-378
@@ -1,378 +1,352 @@
|
||||
from typing import Optional, List, Union, Dict
|
||||
from pathlib import Path
|
||||
from .data_class import StaticData
|
||||
from utils.utils import get_matchers, get_bot
|
||||
from configs.config import Config
|
||||
import nonebot
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
"group_manager", "DEFAULT_GROUP_LEVEL", 5, help_="默认群权限", default_value=5
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"group_manager", "DEFAULT_GROUP_BOT_STATUS", True, help_="默认进群总开关状态", default_value=True
|
||||
)
|
||||
|
||||
|
||||
class GroupManager(StaticData):
|
||||
"""
|
||||
群权限 | 功能 | 总开关 | 聊天时间 管理器
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
super().__init__(file)
|
||||
if not self._data:
|
||||
self._data = {
|
||||
"super": {"white_group_list": []},
|
||||
"group_manager": {},
|
||||
}
|
||||
self._task = {}
|
||||
|
||||
def block_plugin(self, module: str, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
锁定插件
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组,None时为超级用户禁用
|
||||
"""
|
||||
self._set_plugin_status(module, "block", group_id)
|
||||
|
||||
def unblock_plugin(self, module: str, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
解锁插件
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
"""
|
||||
self._set_plugin_status(module, "unblock", group_id)
|
||||
|
||||
def turn_on_group_bot_status(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
开启群bot开关
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
self._set_group_bot_status(group_id, True)
|
||||
|
||||
def shutdown_group_bot_status(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
关闭群bot开关
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
self._set_group_bot_status(group_id, False)
|
||||
|
||||
def check_group_bot_status(self, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检查群聊bot总开关状态
|
||||
参数:
|
||||
:param group_id: 说明
|
||||
"""
|
||||
group_id = str(group_id)
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
if self._data["group_manager"][group_id].get("status") is None:
|
||||
default_group_bot_status = Config.get_config("group_manager", "DEFAULT_GROUP_BOT_STATUS")
|
||||
if default_group_bot_status:
|
||||
default_group_bot_status = True
|
||||
self._data["group_manager"][group_id]["status"] = default_group_bot_status
|
||||
return self._data["group_manager"][group_id]["status"]
|
||||
|
||||
def set_group_level(self, group_id: int, level: int):
|
||||
"""
|
||||
说明:
|
||||
设置群权限
|
||||
参数:
|
||||
:param group_id: 群组
|
||||
:param level: 权限等级
|
||||
"""
|
||||
group_id = str(group_id)
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
self._data["group_manager"][group_id]["level"] = level
|
||||
self.save()
|
||||
|
||||
def get_plugin_status(self, module: str, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
获取插件状态
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
"""
|
||||
group_id = str(group_id) if group_id else group_id
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
return True
|
||||
if module in self._data["group_manager"][group_id]["close_plugins"]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_group_level(self, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
获取群等级
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
group_id = str(group_id)
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
return self._data["group_manager"][group_id]["level"]
|
||||
|
||||
def check_group_is_white(self, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测群聊是否在白名单
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
return group_id in self._data["super"]["white_group_list"]
|
||||
|
||||
def add_group_white_list(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
将群聊加入白名单
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id not in self._data["super"]["white_group_list"]:
|
||||
self._data["super"]["white_group_list"].append(group_id)
|
||||
|
||||
def delete_group_white_list(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
将群聊从白名单中删除
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id in self._data["super"]["white_group_list"]:
|
||||
self._data["super"]["white_group_list"].remove(group_id)
|
||||
|
||||
def get_group_white_list(self) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
获取所有群白名单
|
||||
"""
|
||||
return self._data["super"]["white_group_list"]
|
||||
|
||||
def delete_group(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
删除群配置
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id in self._data["group_manager"]:
|
||||
del self._data["group_manager"][str(group_id)]
|
||||
if group_id in self._data["super"]["white_group_list"]:
|
||||
self._data["super"]["white_group_list"].remove(group_id)
|
||||
self.save()
|
||||
|
||||
async def open_group_task(self, group_id: int, task: str):
|
||||
"""
|
||||
说明:
|
||||
开启群被动技能
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能名称
|
||||
"""
|
||||
await self._set_group_task_status(group_id, task, True)
|
||||
|
||||
async def close_group_task(self, group_id: int, task: str):
|
||||
"""
|
||||
说明:
|
||||
关闭群被动技能
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能名称
|
||||
"""
|
||||
await self._set_group_task_status(group_id, task, False)
|
||||
|
||||
async def check_group_task_status(self, group_id: int, task: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
查看群被动技能状态
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能名称
|
||||
"""
|
||||
group_id = str(group_id)
|
||||
if (
|
||||
not self._data["group_manager"][group_id].get("group_task_status")
|
||||
or self._data["group_manager"][group_id]["group_task_status"].get(task)
|
||||
is None
|
||||
):
|
||||
await self.init_group_task(group_id)
|
||||
return self._data["group_manager"][group_id]["group_task_status"][task]
|
||||
|
||||
def get_task_data(self) -> Dict[str, str]:
|
||||
"""
|
||||
说明:
|
||||
获取所有被动任务
|
||||
"""
|
||||
return self._task
|
||||
|
||||
async def group_task_status(self, group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
查看群被全部动技能状态
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
x = "[群被动技能]:\n"
|
||||
group_id = str(group_id)
|
||||
if not self._data["group_manager"][group_id].get("group_task_status"):
|
||||
await self.init_group_task(group_id)
|
||||
for key in self._data["group_manager"][group_id]["group_task_status"].keys():
|
||||
x += f'{self._task[key]}:{"√" if await self.check_group_task_status(int(group_id), key) else "×"}\n'
|
||||
return x[:-1]
|
||||
|
||||
async def _set_group_task_status(self, group_id: int, task: str, status: bool):
|
||||
"""
|
||||
说明:
|
||||
管理群被动技能状态
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能
|
||||
:param status: 状态
|
||||
"""
|
||||
group_id = str(group_id)
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
if (
|
||||
not self._data["group_manager"][group_id].get("group_task_status")
|
||||
or self._data["group_manager"][group_id]["group_task_status"].get(task)
|
||||
is None
|
||||
):
|
||||
await self.init_group_task(group_id)
|
||||
self._data["group_manager"][group_id]["group_task_status"][task] = status
|
||||
self.save()
|
||||
|
||||
async def init_group_task(self, group_id: Optional[Union[int, str]] = None):
|
||||
"""
|
||||
说明:
|
||||
初始化群聊 被动技能 状态
|
||||
"""
|
||||
if not self._task:
|
||||
_m = []
|
||||
for matcher in get_matchers():
|
||||
if matcher.plugin_name not in _m:
|
||||
_m.append(matcher.plugin_name)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_task = _module.__getattribute__("__plugin_task__")
|
||||
for key in plugin_task.keys():
|
||||
if key in self._task.keys():
|
||||
raise ValueError(f"plugin_task:{key} 已存在!")
|
||||
self._task[key] = plugin_task[key]
|
||||
except AttributeError:
|
||||
pass
|
||||
bot = get_bot()
|
||||
if bot or group_id:
|
||||
if group_id:
|
||||
_group_list = [group_id]
|
||||
else:
|
||||
_group_list = [x["group_id"] for x in await bot.get_group_list()]
|
||||
for group_id in _group_list:
|
||||
group_id = str(group_id)
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
if not self._data["group_manager"][group_id].get("group_task_status"):
|
||||
self._data["group_manager"][group_id]["group_task_status"] = {}
|
||||
for task in self._task:
|
||||
if (
|
||||
self._data["group_manager"][group_id]["group_task_status"].get(
|
||||
task
|
||||
)
|
||||
is None
|
||||
):
|
||||
self._data["group_manager"][group_id]["group_task_status"][
|
||||
task
|
||||
] = Config.get_config('_task', f'DEFAULT_{task}', default=True)
|
||||
for task in list(
|
||||
self._data["group_manager"][group_id]["group_task_status"]
|
||||
):
|
||||
if task not in self._task:
|
||||
del self._data["group_manager"][group_id]["group_task_status"][
|
||||
task
|
||||
]
|
||||
self.save()
|
||||
|
||||
def _set_plugin_status(
|
||||
self,
|
||||
module: str,
|
||||
status: str,
|
||||
group_id: int,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
设置功能开关状态
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param status: 功能状态
|
||||
:param group_id: 群组
|
||||
"""
|
||||
group_id = str(group_id) if group_id else group_id
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
if status == "block":
|
||||
if module not in self._data["group_manager"][group_id]["close_plugins"]:
|
||||
self._data["group_manager"][group_id]["close_plugins"].append(module)
|
||||
else:
|
||||
if module in self._data["group_manager"][group_id]["close_plugins"]:
|
||||
self._data["group_manager"][group_id]["close_plugins"].remove(module)
|
||||
self.save()
|
||||
|
||||
def _init_group(self, group_id: str):
|
||||
"""
|
||||
说明:
|
||||
初始化群数据
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
default_group_level = Config.get_config("group_manager", "DEFAULT_GROUP_LEVEL")
|
||||
if default_group_level is None:
|
||||
default_group_level = 5
|
||||
default_group_bot_status = Config.get_config("group_manager", "DEFAULT_GROUP_BOT_STATUS")
|
||||
if default_group_bot_status:
|
||||
default_group_bot_status = True
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._data["group_manager"][group_id] = {
|
||||
"level": default_group_level,
|
||||
"status": default_group_bot_status,
|
||||
"close_plugins": [],
|
||||
"group_task_status": {},
|
||||
}
|
||||
|
||||
def _set_group_bot_status(self, group_id: Union[int, str], status: bool):
|
||||
"""
|
||||
说明:
|
||||
设置群聊bot总开关
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param status: 开关状态
|
||||
"""
|
||||
group_id = str(group_id)
|
||||
if not self._data["group_manager"].get(group_id):
|
||||
self._init_group(group_id)
|
||||
self._data["group_manager"][group_id]["status"] = status
|
||||
self.save()
|
||||
|
||||
def get_super_old_data(self) -> Optional[dict]:
|
||||
"""
|
||||
说明:
|
||||
获取旧数据,平时使用请不要调用
|
||||
"""
|
||||
if self._data["super"].get("close_plugins"):
|
||||
_x = self._data["super"].get("close_plugins")
|
||||
del self._data["super"]["close_plugins"]
|
||||
return _x
|
||||
return None
|
||||
from typing import List, Union, Dict, Callable
|
||||
from pathlib import Path
|
||||
from .models import BaseData, BaseGroup
|
||||
from utils.manager.data_class import StaticData
|
||||
from utils.utils import get_matchers, is_number
|
||||
from configs.config import Config
|
||||
import nonebot
|
||||
import ujson as json
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
"group_manager", "DEFAULT_GROUP_LEVEL", 5, help_="默认群权限", default_value=5
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"group_manager", "DEFAULT_GROUP_BOT_STATUS", True, help_="默认进群总开关状态", default_value=True
|
||||
)
|
||||
|
||||
|
||||
def init_group(func: Callable):
|
||||
"""
|
||||
说明:
|
||||
初始化群数据
|
||||
参数:
|
||||
:param func: func
|
||||
"""
|
||||
def wrapper(*args, **kwargs):
|
||||
self = args[0]
|
||||
group_id = list(filter(lambda x: is_number(x), args[1:]))[0]
|
||||
if self and group_id and not self._data.group_manager.get(str(group_id)):
|
||||
self._data.group_manager[str(group_id)] = BaseGroup()
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def init_task(func: Callable):
|
||||
"""
|
||||
说明:
|
||||
初始化群被动
|
||||
参数:
|
||||
:param func: func
|
||||
"""
|
||||
def wrapper(*args, **kwargs):
|
||||
self = args[0]
|
||||
group_id = str(args[1])
|
||||
task = args[2] if len(args) > 1 else None
|
||||
if group_id and task and self._data.group_manager[group_id].group_task_status.get(task) is None:
|
||||
for task in self._data.task:
|
||||
if self._data.group_manager[group_id].group_task_status.get(task) is None:
|
||||
self._data.group_manager[group_id].group_task_status[task] = Config.get_config('_task', f'DEFAULT_{task}', default=True)
|
||||
for task in list(self._data.group_manager[group_id].group_task_status):
|
||||
if task not in self._data.task:
|
||||
del self._data.group_manager[group_id].group_task_status[task]
|
||||
self.save()
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
class GroupManager(StaticData):
|
||||
"""
|
||||
群权限 | 功能 | 总开关 | 聊天时间 管理器
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
super().__init__(file, False)
|
||||
self._data = BaseData.parse_file(file) if file.exists() else BaseData()
|
||||
|
||||
def block_plugin(self, module: str, group_id: int, is_save: bool = True):
|
||||
"""
|
||||
说明:
|
||||
锁定插件
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组,None时为超级用户禁用
|
||||
:param is_save: 是否保存文件
|
||||
"""
|
||||
self._set_plugin_status(module, "block", group_id, is_save)
|
||||
|
||||
def unblock_plugin(self, module: str, group_id: int, is_save: bool = True):
|
||||
"""
|
||||
说明:
|
||||
解锁插件
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
:param is_save: 是否保存文件
|
||||
"""
|
||||
self._set_plugin_status(module, "unblock", group_id, is_save)
|
||||
|
||||
def turn_on_group_bot_status(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
开启群bot开关
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
self._set_group_bot_status(group_id, True)
|
||||
|
||||
def shutdown_group_bot_status(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
关闭群bot开关
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
self._set_group_bot_status(group_id, False)
|
||||
|
||||
@init_group
|
||||
def check_group_bot_status(self, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检查群聊bot总开关状态
|
||||
参数:
|
||||
:param group_id: 说明
|
||||
"""
|
||||
return self._data.group_manager[str(group_id)].status
|
||||
|
||||
@init_group
|
||||
def set_group_level(self, group_id: int, level: int):
|
||||
"""
|
||||
说明:
|
||||
设置群权限
|
||||
参数:
|
||||
:param group_id: 群组
|
||||
:param level: 权限等级
|
||||
"""
|
||||
self._data.group_manager[str(group_id)].level = level
|
||||
self.save()
|
||||
|
||||
@init_group
|
||||
def get_plugin_status(self, module: str, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
获取插件状态
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
"""
|
||||
return module not in self._data.group_manager[str(group_id)].close_plugins
|
||||
|
||||
@init_group
|
||||
def get_group_level(self, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
获取群等级
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
return self._data.group_manager[str(group_id)].level
|
||||
|
||||
def check_group_is_white(self, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测群聊是否在白名单
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
return group_id in self._data.white_group
|
||||
|
||||
def add_group_white_list(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
将群聊加入白名单
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id not in self._data.white_group:
|
||||
self._data.white_group.append(group_id)
|
||||
|
||||
def delete_group_white_list(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
将群聊从白名单中删除
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id in self._data.white_group:
|
||||
self._data.white_group.remove(group_id)
|
||||
|
||||
def get_group_white_list(self) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
获取所有群白名单
|
||||
"""
|
||||
return self._data.white_group
|
||||
|
||||
def load_task(self):
|
||||
"""
|
||||
说明:
|
||||
加载被动技能
|
||||
"""
|
||||
for matcher in get_matchers(True):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_task = _module.__getattribute__("__plugin_task__")
|
||||
for key in plugin_task.keys():
|
||||
if key in self._data.task.keys():
|
||||
raise ValueError(f"plugin_task:{key} 已存在!")
|
||||
self._data.task[key] = plugin_task[key]
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@init_group
|
||||
def delete_group(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
删除群配置
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id in self._data.white_group:
|
||||
self._data.white_group.remove(group_id)
|
||||
self.save()
|
||||
|
||||
def open_group_task(self, group_id: int, task: str):
|
||||
"""
|
||||
说明:
|
||||
开启群被动技能
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能名称
|
||||
"""
|
||||
self._set_group_group_task_status(group_id, task, True)
|
||||
|
||||
def close_group_task(self, group_id: int, task: str):
|
||||
"""
|
||||
说明:
|
||||
关闭群被动技能
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能名称
|
||||
"""
|
||||
self._set_group_group_task_status(group_id, task, False)
|
||||
|
||||
@init_task
|
||||
def check_group_task_status(self, group_id: int, task: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
查看群被动技能状态
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能名称
|
||||
"""
|
||||
return self._data.group_manager[str(group_id)].group_task_status.get(task, False)
|
||||
|
||||
def get_task_data(self) -> Dict[str, str]:
|
||||
"""
|
||||
说明:
|
||||
获取所有被动任务
|
||||
"""
|
||||
return self._data.task
|
||||
|
||||
@init_task
|
||||
def group_group_task_status(self, group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
查看群被全部动技能状态
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
x = "[群被动技能]:\n"
|
||||
group_id = str(group_id)
|
||||
for key in self._data.group_manager[group_id].group_task_status.keys():
|
||||
x += f'{self._data.task[key]}:{"√" if self.check_group_task_status(int(group_id), key) else "×"}\n'
|
||||
return x[:-1]
|
||||
|
||||
@init_task
|
||||
@init_group
|
||||
def _set_group_group_task_status(self, group_id: int, task: str, status: bool):
|
||||
"""
|
||||
说明:
|
||||
管理群被动技能状态
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能
|
||||
:param status: 状态
|
||||
"""
|
||||
self._data.group_manager[str(group_id)].group_task_status[task] = status
|
||||
self.save()
|
||||
|
||||
@init_group
|
||||
def _set_plugin_status(
|
||||
self,
|
||||
module: str,
|
||||
status: str,
|
||||
group_id: int,
|
||||
is_save: bool
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
设置功能开关状态
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param status: 功能状态
|
||||
:param group_id: 群组
|
||||
:param is_save: 是否保存
|
||||
"""
|
||||
group_id = str(group_id) if group_id else group_id
|
||||
if status == "block":
|
||||
if module not in self._data.group_manager[group_id].close_plugins:
|
||||
self._data.group_manager[group_id].close_plugins.append(module)
|
||||
else:
|
||||
if module in self._data.group_manager[group_id].close_plugins:
|
||||
self._data.group_manager[group_id].close_plugins.remove(module)
|
||||
if is_save:
|
||||
self.save()
|
||||
|
||||
@init_group
|
||||
def _set_group_bot_status(self, group_id: Union[int, str], status: bool):
|
||||
"""
|
||||
说明:
|
||||
设置群聊bot总开关
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param status: 开关状态
|
||||
"""
|
||||
self._data.group_manager[str(group_id)].status = status
|
||||
self.save()
|
||||
|
||||
def reload(self):
|
||||
if self.file.exists():
|
||||
t = self._data.task
|
||||
self._data = BaseData.parse_file(self.file)
|
||||
self._data.task = t
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
"""
|
||||
说明:
|
||||
保存文件
|
||||
参数:
|
||||
:param path: 路径文件
|
||||
"""
|
||||
path = path or self.file
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
if path:
|
||||
dict_data = self._data.dict()
|
||||
del dict_data["task"]
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
json.dump(dict_data, f, ensure_ascii=False, indent=4)
|
||||
|
||||
# def get_super_old_data(self) -> Optional[dict]:
|
||||
# """
|
||||
# 说明:
|
||||
# 获取旧数据,平时使用请不要调用
|
||||
# """
|
||||
# if self._data["super"].get("close_plugins"):
|
||||
# _x = self._data["super"].get("close_plugins")
|
||||
# del self._data["super"]["close_plugins"]
|
||||
# return _x
|
||||
# return None
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
from typing import List, Optional, Dict, Literal, Tuple, Union
|
||||
from pydantic import BaseModel
|
||||
from configs.config import Config
|
||||
|
||||
|
||||
class AdminSetting(BaseModel):
|
||||
"""
|
||||
管理员设置
|
||||
"""
|
||||
|
||||
level: int
|
||||
cmd: Optional[List[str]]
|
||||
|
||||
|
||||
class BaseGroup(BaseModel):
|
||||
"""
|
||||
基础群聊信息
|
||||
"""
|
||||
|
||||
level: int = Config.get_config("group_manager", "DEFAULT_GROUP_LEVEL") # 群等级
|
||||
status: bool = Config.get_config(
|
||||
"group_manager", "DEFAULT_GROUP_BOT_STATUS"
|
||||
) # 总开关状态
|
||||
close_plugins: List[str] = [] # 已关闭插件
|
||||
group_task_status: Dict[str, bool] = {} # 被动状态
|
||||
|
||||
|
||||
class BaseData(BaseModel):
|
||||
"""
|
||||
群基本信息
|
||||
"""
|
||||
|
||||
white_group: List[int] = [] # 白名单
|
||||
group_manager: Dict[str, BaseGroup] = {} # 群组管理
|
||||
task: Dict[str, str] = {} # 被动任务 【英文:中文】
|
||||
|
||||
|
||||
class PluginBlock(BaseModel):
|
||||
"""
|
||||
插件阻断
|
||||
"""
|
||||
|
||||
status: bool # 限制状态
|
||||
check_type: Literal["private", "group", "all"] # 检查类型
|
||||
limit_type: Literal["user", "group"] # 监听对象
|
||||
rst: Optional[str] # 阻断时回复
|
||||
|
||||
|
||||
class PluginCd(BaseModel):
|
||||
"""
|
||||
插件阻断
|
||||
"""
|
||||
|
||||
cd: int # cd
|
||||
status: bool # 限制状态
|
||||
check_type: Literal["private", "group", "all"] # 检查类型
|
||||
limit_type: Literal["user", "group"] # 监听对象
|
||||
rst: Optional[str] # 阻断时回复
|
||||
|
||||
|
||||
class PluginCount(BaseModel):
|
||||
"""
|
||||
插件阻断
|
||||
"""
|
||||
|
||||
max_count: int # 次数
|
||||
status: bool # 限制状态
|
||||
limit_type: Literal["user", "group"] # 监听对象
|
||||
rst: Optional[str] # 阻断时回复
|
||||
|
||||
|
||||
class PluginSetting(BaseModel):
|
||||
"""
|
||||
插件设置
|
||||
"""
|
||||
|
||||
cmd: List[str] = [] # 命令 或 命令别名
|
||||
default_status: bool = True # 默认开关状态
|
||||
level: int = 5 # 功能权限等级
|
||||
limit_superuser: bool = False # 功能状态是否限制超级用户
|
||||
plugin_type: Tuple[Union[str, int], ...] = ("normal",) # 插件类型
|
||||
cost_gold: int = 0 # 需要消费的金币
|
||||
|
||||
|
||||
class Plugin(BaseModel):
|
||||
"""
|
||||
插件数据
|
||||
"""
|
||||
|
||||
plugin_name: str # 模块名
|
||||
status: Optional[bool] = True # 开关状态
|
||||
error: Optional[bool] = False # 是否加载报错
|
||||
block_type: Optional[str] = None # 关闭类型
|
||||
author: Optional[str] = None # 作者
|
||||
version: Optional[Union[int, str]] = None # 版本
|
||||
Executable → Regular
+47
-47
@@ -1,47 +1,47 @@
|
||||
from .data_class import StaticData
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class NonePluginCountManager(StaticData):
|
||||
"""
|
||||
插件加载容忍管理器,当连续 max_count 次插件加载,视为删除插件,清楚数据
|
||||
"""
|
||||
|
||||
def __init__(self, file: Optional[Path], max_count: int = 5):
|
||||
"""
|
||||
:param file: 存储路径
|
||||
:param max_count: 容忍最大次数
|
||||
"""
|
||||
super().__init__(file)
|
||||
if not self._data:
|
||||
self._data = {}
|
||||
self._max_count = max_count
|
||||
|
||||
def add_count(self, module: str, count: int = 1):
|
||||
"""
|
||||
添加次数
|
||||
:param module: 模块
|
||||
:param count: 次数,无特殊情况均为 1
|
||||
"""
|
||||
if module not in self._data.keys():
|
||||
self._data[module] = count
|
||||
else:
|
||||
self._data[module] += count
|
||||
|
||||
def reset(self, module: str):
|
||||
"""
|
||||
重置次数
|
||||
:param module: 模块
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
self._data[module] = 0
|
||||
|
||||
def check(self, module: str):
|
||||
"""
|
||||
检查容忍次数是否到达最大值
|
||||
:param module: 模块
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
return self._data[module] >= self._max_count
|
||||
return False
|
||||
from utils.manager.data_class import StaticData
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class NonePluginCountManager(StaticData):
|
||||
"""
|
||||
插件加载容忍管理器,当连续 max_count 次插件加载,视为删除插件,清楚数据
|
||||
"""
|
||||
|
||||
def __init__(self, file: Optional[Path], max_count: int = 5):
|
||||
"""
|
||||
:param file: 存储路径
|
||||
:param max_count: 容忍最大次数
|
||||
"""
|
||||
super().__init__(file)
|
||||
if not self._data:
|
||||
self._data = {}
|
||||
self._max_count = max_count
|
||||
|
||||
def add_count(self, module: str, count: int = 1):
|
||||
"""
|
||||
添加次数
|
||||
:param module: 模块
|
||||
:param count: 次数,无特殊情况均为 1
|
||||
"""
|
||||
if module not in self._data.keys():
|
||||
self._data[module] = count
|
||||
else:
|
||||
self._data[module] += count
|
||||
|
||||
def reset(self, module: str):
|
||||
"""
|
||||
重置次数
|
||||
:param module: 模块
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
self._data[module] = 0
|
||||
|
||||
def check(self, module: str):
|
||||
"""
|
||||
检查容忍次数是否到达最大值
|
||||
:param module: 模块
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
return self._data[module] >= self._max_count
|
||||
return False
|
||||
|
||||
Executable → Regular
+103
-50
@@ -1,11 +1,12 @@
|
||||
from typing import Optional, Dict
|
||||
from .data_class import StaticData
|
||||
from typing import Optional, Dict, Literal, Union
|
||||
from utils.manager.data_class import StaticData
|
||||
from services.log import logger
|
||||
from utils.utils import UserBlockLimiter
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from ruamel import yaml
|
||||
from .models import PluginBlock
|
||||
|
||||
yaml = YAML(typ="safe")
|
||||
_yaml = yaml.YAML(typ="safe")
|
||||
|
||||
|
||||
class Plugins2blockManager(StaticData):
|
||||
@@ -14,53 +15,45 @@ class Plugins2blockManager(StaticData):
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self.file = file
|
||||
super().__init__(None)
|
||||
super().__init__(file, False)
|
||||
self._block_limiter: Dict[str, UserBlockLimiter] = {}
|
||||
if file.exists():
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = yaml.load(f)
|
||||
if "PluginBlockLimit" in self._data.keys():
|
||||
self._data = self._data["PluginBlockLimit"] or {}
|
||||
self.__load_file()
|
||||
|
||||
def add_block_limit(
|
||||
self,
|
||||
plugin: str,
|
||||
*,
|
||||
status: Optional[bool] = True,
|
||||
check_type: Optional[str] = "all",
|
||||
limit_type: Optional[str] = "user",
|
||||
check_type: Literal["private", "group", "all"] = "all",
|
||||
limit_type: Literal["user", "group"] = "user",
|
||||
rst: Optional[str] = None,
|
||||
**kwargs # 用于接收额外实参
|
||||
):
|
||||
"""
|
||||
添加插件调用 block 限制
|
||||
:param plugin: 插件模块名称
|
||||
:param status: 默认开关状态
|
||||
:param check_type: 检查类型 'private'/'group'/'all',限制私聊/群聊/全部
|
||||
:param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
:param rst: 回复的话,为空则不回复
|
||||
说明:
|
||||
添加插件调用 block 限制
|
||||
参数:
|
||||
:param plugin: 插件模块名称
|
||||
:param status: 默认开关状态
|
||||
:param check_type: 检查类型 'private'/'group'/'all',限制私聊/群聊/全部
|
||||
:param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
:param rst: 回复的话,为空则不回复
|
||||
"""
|
||||
status = status or True
|
||||
check_type = check_type or "all"
|
||||
limit_type = limit_type or "user"
|
||||
if check_type not in ["all", "group", "private"]:
|
||||
raise ValueError(
|
||||
f"{plugin} 添加block限制错误,‘check_type‘ 必须为 'private'/'group'/'all'"
|
||||
)
|
||||
if limit_type not in ["user", "group"]:
|
||||
raise ValueError(f"{plugin} 添加block限制错误,‘limit_type‘ 必须为 'user'/'group'")
|
||||
self._data[plugin] = {
|
||||
"status": status,
|
||||
"check_type": check_type,
|
||||
"limit_type": limit_type,
|
||||
"rst": rst,
|
||||
}
|
||||
self._data[plugin] = PluginBlock(
|
||||
status=status, check_type=check_type, limit_type=limit_type, rst=rst
|
||||
)
|
||||
|
||||
def get_plugin_block_data(self, plugin: str) -> Optional[dict]:
|
||||
def get_plugin_block_data(self, plugin: str) -> Optional[PluginBlock]:
|
||||
"""
|
||||
获取插件block数据
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
获取插件block数据
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if self.check_plugin_block_status(plugin):
|
||||
return self._data[plugin]
|
||||
@@ -68,16 +61,20 @@ class Plugins2blockManager(StaticData):
|
||||
|
||||
def check_plugin_block_status(self, plugin: str) -> bool:
|
||||
"""
|
||||
检测插件是否有 block
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
检测插件是否有 block
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
return plugin in self._data.keys() and self._data[plugin]["status"]
|
||||
return plugin in self._data.keys() and self._data[plugin].status
|
||||
|
||||
def check(self, id_: int, plugin: str) -> bool:
|
||||
"""
|
||||
检查 block
|
||||
:param plugin: 模块名
|
||||
:param id_: 限制 id
|
||||
说明:
|
||||
检查 block
|
||||
参数:
|
||||
:param id_: 限制 id
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if self._block_limiter.get(plugin):
|
||||
return self._block_limiter[plugin].check(id_)
|
||||
@@ -85,26 +82,30 @@ class Plugins2blockManager(StaticData):
|
||||
|
||||
def set_true(self, id_: int, plugin: str):
|
||||
"""
|
||||
对插件 block
|
||||
:param plugin: 模块名
|
||||
:param id_: 限制 id
|
||||
说明:
|
||||
对插件 block
|
||||
参数:
|
||||
:param id_: 限制 id
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if self._block_limiter.get(plugin):
|
||||
self._block_limiter[plugin].set_true(id_)
|
||||
|
||||
def set_false(self, id_: int, plugin: str):
|
||||
"""
|
||||
对插件 unblock
|
||||
:param plugin: 模块名
|
||||
:param id_: 限制 id
|
||||
说明:
|
||||
对插件 unblock
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
:param id_: 限制 id
|
||||
"""
|
||||
if self._block_limiter.get(plugin):
|
||||
self._block_limiter[plugin].set_false(id_)
|
||||
|
||||
def reload_block_limit(self):
|
||||
"""
|
||||
加载 block 限制器
|
||||
:return:
|
||||
说明:
|
||||
加载 block 限制器
|
||||
"""
|
||||
for plugin in self._data:
|
||||
if self.check_plugin_block_status(plugin):
|
||||
@@ -113,10 +114,62 @@ class Plugins2blockManager(StaticData):
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
重载本地数据
|
||||
说明:
|
||||
重载本地数据
|
||||
"""
|
||||
self.__load_file()
|
||||
self.reload_block_limit()
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
"""
|
||||
说明:
|
||||
保存文件
|
||||
参数:
|
||||
:param path: 文件路径
|
||||
"""
|
||||
path = path or self.file
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
if path:
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
yaml.dump(
|
||||
{"PluginBlockLimit": self.dict()},
|
||||
f,
|
||||
indent=2,
|
||||
Dumper=yaml.RoundTripDumper,
|
||||
allow_unicode=True,
|
||||
)
|
||||
_data = yaml.round_trip_load(open(path, encoding="utf8"))
|
||||
_data["PluginBlockLimit"].yaml_set_start_comment(
|
||||
"""# 用户调用阻塞
|
||||
# 即 当用户调用此功能还未结束时
|
||||
# 用发送消息阻止用户重复调用此命令直到该命令结束
|
||||
# key:模块名称
|
||||
# status:此限制的开关状态
|
||||
# check_type:'private'/'group'/'all',限制私聊/群聊/全部
|
||||
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
# 示例:'user':阻塞用户,'group':阻塞群聊
|
||||
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
# rst 为 "" 或 None 时则不回复
|
||||
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
|
||||
indent=2,
|
||||
)
|
||||
with open(path, "w", encoding="utf8") as wf:
|
||||
yaml.round_trip_dump(
|
||||
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
|
||||
def __load_file(self):
|
||||
"""
|
||||
说明:
|
||||
读取配置文件
|
||||
"""
|
||||
self._data: Dict[str, PluginBlock] = {}
|
||||
if self.file.exists():
|
||||
with open(self.file, "r", encoding="utf8") as f:
|
||||
self._data: dict = yaml.load(f)
|
||||
self._data = self._data["PluginBlockLimit"]
|
||||
self.reload_block_limit()
|
||||
temp = yaml.round_trip_load(f)
|
||||
if "PluginBlockLimit" in temp.keys():
|
||||
for k, v in temp["PluginBlockLimit"].items():
|
||||
self._data[k] = PluginBlock.parse_obj(v)
|
||||
|
||||
Executable → Regular
+106
-61
@@ -1,11 +1,12 @@
|
||||
from typing import Optional, Dict
|
||||
from .data_class import StaticData
|
||||
from typing import Optional, Dict, Literal, Union
|
||||
from utils.manager.data_class import StaticData
|
||||
from utils.utils import FreqLimiter
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from ruamel import yaml
|
||||
from .models import PluginCd
|
||||
|
||||
yaml = YAML(typ="safe")
|
||||
_yaml = yaml.YAML(typ="safe")
|
||||
|
||||
|
||||
class Plugins2cdManager(StaticData):
|
||||
@@ -14,16 +15,9 @@ class Plugins2cdManager(StaticData):
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self.file = file
|
||||
super().__init__(None)
|
||||
super().__init__(file, False)
|
||||
self._freq_limiter: Dict[str, FreqLimiter] = {}
|
||||
if file.exists():
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = yaml.load(f)
|
||||
if "PluginCdLimit" in self._data.keys():
|
||||
self._data = (
|
||||
self._data["PluginCdLimit"] if self._data["PluginCdLimit"] else {}
|
||||
)
|
||||
self.__load_file()
|
||||
|
||||
def add_cd_limit(
|
||||
self,
|
||||
@@ -31,42 +25,35 @@ class Plugins2cdManager(StaticData):
|
||||
*,
|
||||
cd: Optional[int] = 5,
|
||||
status: Optional[bool] = True,
|
||||
check_type: Optional[str] = "all",
|
||||
limit_type: Optional[str] = "user",
|
||||
check_type: Literal["private", "group", "all"] = "all",
|
||||
limit_type: Literal["user", "group"] = "user",
|
||||
rst: Optional[str] = None,
|
||||
**kwargs # 用于接收额外实参
|
||||
):
|
||||
"""
|
||||
添加插件调用 cd 限制
|
||||
:param plugin: 插件模块名称
|
||||
:param cd: cd 时长
|
||||
:param status: 默认开关状态
|
||||
:param check_type: 检查类型 'private'/'group'/'all',限制私聊/群聊/全部
|
||||
:param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
:param rst: 回复的话,为空则不回复
|
||||
说明:
|
||||
添加插件调用 cd 限制
|
||||
参数:
|
||||
:param plugin: 插件模块名称
|
||||
:param cd: cd 时长
|
||||
:param status: 默认开关状态
|
||||
:param check_type: 检查类型 'private'/'group'/'all',限制私聊/群聊/全部
|
||||
:param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
:param rst: 回复的话,为空则不回复
|
||||
"""
|
||||
cd = cd or 5
|
||||
status = status or True
|
||||
check_type = check_type or "all"
|
||||
limit_type = limit_type or "user"
|
||||
if check_type not in ["all", "group", "private"]:
|
||||
raise ValueError(
|
||||
f"{plugin} 添加cd限制错误,‘check_type‘ 必须为 'private'/'group'/'all'"
|
||||
)
|
||||
if limit_type not in ["user", "group"]:
|
||||
raise ValueError(f"{plugin} 添加cd限制错误,‘limit_type‘ 必须为 'user'/'group'")
|
||||
self._data[plugin] = {
|
||||
"cd": cd,
|
||||
"status": status,
|
||||
"check_type": check_type,
|
||||
"limit_type": limit_type,
|
||||
"rst": rst,
|
||||
}
|
||||
self._data[plugin] = PluginCd(cd=cd, status=status, check_type=check_type, limit_type=limit_type, rst=rst)
|
||||
|
||||
def get_plugin_cd_data(self, plugin: str) -> Optional[dict]:
|
||||
def get_plugin_cd_data(self, plugin: str) -> Optional[PluginCd]:
|
||||
"""
|
||||
获取插件cd数据
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
获取插件cd数据
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if self.check_plugin_cd_status(plugin):
|
||||
return self._data[plugin]
|
||||
@@ -74,20 +61,24 @@ class Plugins2cdManager(StaticData):
|
||||
|
||||
def check_plugin_cd_status(self, plugin: str) -> bool:
|
||||
"""
|
||||
检测插件是否有 cd
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
检测插件是否有 cd
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
return (
|
||||
plugin in self._data.keys()
|
||||
and self._data[plugin]["cd"] > 0
|
||||
and self._data[plugin]["status"]
|
||||
and self._data[plugin].cd > 0
|
||||
and self._data[plugin].status
|
||||
)
|
||||
|
||||
def check(self, plugin: str, id_: int) -> bool:
|
||||
"""
|
||||
检查 cd
|
||||
:param plugin: 模块名
|
||||
:param id_: 限制 id
|
||||
说明:
|
||||
检查 cd
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
:param id_: 限制 id
|
||||
"""
|
||||
if self._freq_limiter.get(plugin):
|
||||
return self._freq_limiter[plugin].check(id_)
|
||||
@@ -95,42 +86,96 @@ class Plugins2cdManager(StaticData):
|
||||
|
||||
def start_cd(self, plugin: str, id_: int, cd: int = 0):
|
||||
"""
|
||||
开始cd
|
||||
:param plugin: 模块名
|
||||
:param id_: cd 限制类型
|
||||
:param cd: cd 时长
|
||||
:return:
|
||||
说明:
|
||||
开始cd
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
:param id_: cd 限制类型
|
||||
:param cd: cd 时长
|
||||
"""
|
||||
if self._freq_limiter.get(plugin):
|
||||
self._freq_limiter[plugin].start_cd(id_, cd)
|
||||
|
||||
def get_plugin_data(self, plugin: str) -> dict:
|
||||
def get_plugin_data(self, plugin: str) -> Optional[PluginCd]:
|
||||
"""
|
||||
获取单个模块限制数据
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
获取单个模块限制数据
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if self._data.get(plugin) is not None:
|
||||
if self._data.get(plugin):
|
||||
return self._data.get(plugin)
|
||||
return {}
|
||||
|
||||
def reload_cd_limit(self):
|
||||
"""
|
||||
加载 cd 限制器
|
||||
:return:
|
||||
说明:
|
||||
加载 cd 限制器
|
||||
"""
|
||||
for plugin in self._data:
|
||||
if self.check_plugin_cd_status(plugin):
|
||||
self._freq_limiter[plugin] = FreqLimiter(
|
||||
self.get_plugin_cd_data(plugin)["cd"]
|
||||
self.get_plugin_cd_data(plugin).cd
|
||||
)
|
||||
logger.info(f"已成功加载 {len(self._freq_limiter)} 个Cd限制.")
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
重载本地数据
|
||||
说明:
|
||||
重载本地数据
|
||||
"""
|
||||
self.__load_file()
|
||||
self.reload_cd_limit()
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
"""
|
||||
说明:
|
||||
保存文件
|
||||
参数:
|
||||
:param path: 文件路径
|
||||
"""
|
||||
path = path or self.file
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
if path:
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
yaml.dump(
|
||||
{"PluginCdLimit": self.dict()},
|
||||
f,
|
||||
indent=2,
|
||||
Dumper=yaml.RoundTripDumper,
|
||||
allow_unicode=True,
|
||||
)
|
||||
_data = yaml.round_trip_load(open(path, encoding="utf8"))
|
||||
_data["PluginCdLimit"].yaml_set_start_comment(
|
||||
"""# 需要cd的功能
|
||||
# 自定义的功能需要cd也可以在此配置
|
||||
# key:模块名称
|
||||
# cd:cd 时长(秒)
|
||||
# status:此限制的开关状态
|
||||
# check_type:'private'/'group'/'all',限制私聊/群聊/全部
|
||||
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次
|
||||
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
# rst 为 "" 或 None 时则不回复
|
||||
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
|
||||
indent=2,
|
||||
)
|
||||
with open(path, "w", encoding="utf8") as wf:
|
||||
yaml.round_trip_dump(
|
||||
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
|
||||
def __load_file(self):
|
||||
"""
|
||||
说明:
|
||||
读取配置文件
|
||||
"""
|
||||
self._data: Dict[str, PluginCd] = {}
|
||||
if self.file.exists():
|
||||
with open(self.file, "r", encoding="utf8") as f:
|
||||
self._data: dict = yaml.load(f)
|
||||
self._data = self._data["PluginCdLimit"]
|
||||
self.reload_cd_limit()
|
||||
temp = _yaml.load(f)
|
||||
if "PluginCdLimit" in temp.keys():
|
||||
for k, v in temp["PluginCdLimit"].items():
|
||||
self._data[k] = PluginCd.parse_obj(v)
|
||||
|
||||
Executable → Regular
+101
-55
@@ -1,11 +1,12 @@
|
||||
from typing import Optional, Dict
|
||||
from .data_class import StaticData
|
||||
from typing import Optional, Dict, Literal, Union
|
||||
from utils.manager.data_class import StaticData
|
||||
from utils.utils import DailyNumberLimiter
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from ruamel import yaml
|
||||
from .models import PluginCount
|
||||
|
||||
yaml = YAML(typ="safe")
|
||||
_yaml = yaml.YAML(typ="safe")
|
||||
|
||||
|
||||
class Plugins2countManager(StaticData):
|
||||
@@ -14,16 +15,9 @@ class Plugins2countManager(StaticData):
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self.file = file
|
||||
super().__init__(None)
|
||||
super().__init__(file, False)
|
||||
self._daily_limiter: Dict[str, DailyNumberLimiter] = {}
|
||||
if file.exists():
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = yaml.load(f)
|
||||
if "PluginCountLimit" in self._data.keys():
|
||||
self._data = (
|
||||
self._data["PluginCountLimit"] if self._data["PluginCountLimit"] else {}
|
||||
)
|
||||
self.__load_file()
|
||||
|
||||
def add_count_limit(
|
||||
self,
|
||||
@@ -31,64 +25,64 @@ class Plugins2countManager(StaticData):
|
||||
*,
|
||||
max_count: int = 5,
|
||||
status: Optional[bool] = True,
|
||||
limit_type: Optional[str] = "user",
|
||||
limit_type: Literal["user", "group"] = "user",
|
||||
rst: Optional[str] = None,
|
||||
**kwargs # 用于接收额外实参
|
||||
):
|
||||
"""
|
||||
添加插件调用 次数 限制
|
||||
:param plugin: 插件模块名称
|
||||
:param max_count: 最大次数限制
|
||||
:param status: 默认开关状态
|
||||
:param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
:param rst: 回复的话,为空则不回复
|
||||
说明:
|
||||
添加插件调用 次数 限制
|
||||
参数:
|
||||
:param plugin: 插件模块名称
|
||||
:param max_count: 最大次数限制
|
||||
:param status: 默认开关状态
|
||||
:param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
:param rst: 回复的话,为空则不回复
|
||||
"""
|
||||
max_count = max_count or 5
|
||||
status = status or True
|
||||
limit_type = limit_type or "user"
|
||||
if limit_type not in ["user", "group"]:
|
||||
raise ValueError(f"{plugin} 添加count限制错误,‘limit_type‘ 必须为 'user'/'group'")
|
||||
self._data[plugin] = {
|
||||
"max_count": max_count,
|
||||
"status": status,
|
||||
"limit_type": limit_type,
|
||||
"rst": rst,
|
||||
}
|
||||
self._data[plugin] = PluginCount(max_count=max_count, status=status, limit_type=limit_type, rst=rst)
|
||||
|
||||
def get_plugin_count_data(self, plugin: str) -> Optional[dict]:
|
||||
def get_plugin_count_data(self, plugin: str) -> Optional[PluginCount]:
|
||||
"""
|
||||
获取插件次数数据
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
获取插件次数数据
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if self.check_plugin_count_status(plugin):
|
||||
return self._data[plugin]
|
||||
return None
|
||||
|
||||
def get_plugin_data(self, plugin: str) -> Optional[dict]:
|
||||
def get_plugin_data(self, plugin: str) -> Optional[PluginCount]:
|
||||
"""
|
||||
获取单个模块限制数据
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
获取单个模块限制数据
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
if self._data.get(plugin) is not None:
|
||||
return self._data.get(plugin)
|
||||
return None
|
||||
|
||||
def check_plugin_count_status(self, plugin: str) -> bool:
|
||||
"""
|
||||
检测插件是否有 次数 限制
|
||||
:param plugin: 模块名
|
||||
说明:
|
||||
检测插件是否有 次数 限制
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
"""
|
||||
return (
|
||||
plugin in self._data.keys()
|
||||
and self._data[plugin]["status"]
|
||||
and self._data[plugin]["max_count"] > 0
|
||||
and self._data[plugin].status
|
||||
and self._data[plugin].max_count > 0
|
||||
)
|
||||
|
||||
def check(self, plugin: str, id_: int) -> bool:
|
||||
"""
|
||||
检查 count
|
||||
:param plugin: 模块名
|
||||
:param id_: 限制 id
|
||||
说明:
|
||||
检查 count
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
:param id_: 限制 id
|
||||
"""
|
||||
if self._daily_limiter.get(plugin):
|
||||
return self._daily_limiter[plugin].check(id_)
|
||||
@@ -96,24 +90,25 @@ class Plugins2countManager(StaticData):
|
||||
|
||||
def increase(self, plugin: str, id_: int, num: int = 1):
|
||||
"""
|
||||
增加次数
|
||||
:param plugin: 模块名
|
||||
:param id_: cd 限制类型
|
||||
:param num: 增加次数
|
||||
:return:
|
||||
说明:
|
||||
增加次数
|
||||
参数:
|
||||
:param plugin: 模块名
|
||||
:param id_: cd 限制类型
|
||||
:param num: 增加次数
|
||||
"""
|
||||
if self._daily_limiter.get(plugin):
|
||||
self._daily_limiter[plugin].increase(id_, num)
|
||||
|
||||
def reload_count_limit(self):
|
||||
"""
|
||||
加载 cd 限制器
|
||||
:return:
|
||||
说明:
|
||||
加载 cd 限制器
|
||||
"""
|
||||
for plugin in self._data:
|
||||
if self.check_plugin_count_status(plugin):
|
||||
self._daily_limiter[plugin] = DailyNumberLimiter(
|
||||
self.get_plugin_count_data(plugin)["max_count"]
|
||||
self.get_plugin_count_data(plugin).max_count
|
||||
)
|
||||
logger.info(f"已成功加载 {len(self._daily_limiter)} 个Count限制.")
|
||||
|
||||
@@ -121,8 +116,59 @@ class Plugins2countManager(StaticData):
|
||||
"""
|
||||
重载本地数据
|
||||
"""
|
||||
self.__load_file()
|
||||
self.reload_count_limit()
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
"""
|
||||
说明:
|
||||
保存文件
|
||||
参数:
|
||||
:param path: 文件路径
|
||||
"""
|
||||
path = path or self.file
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
if path:
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
yaml.dump(
|
||||
{"PluginCountLimit": self.dict()},
|
||||
f,
|
||||
indent=2,
|
||||
Dumper=yaml.RoundTripDumper,
|
||||
allow_unicode=True,
|
||||
)
|
||||
_data = yaml.round_trip_load(open(path, encoding="utf8"))
|
||||
_data["PluginCountLimit"].yaml_set_start_comment(
|
||||
"""# 命令每日次数限制
|
||||
# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
|
||||
# 每日调用直到 00:00 刷新
|
||||
# key:模块名称
|
||||
# max_count: 每日调用上限
|
||||
# status:此限制的开关状态
|
||||
# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
|
||||
# 示例:'user':用户上限,'group':群聊上限
|
||||
# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
# rst 为 "" 或 None 时则不回复
|
||||
# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
|
||||
indent=2,
|
||||
)
|
||||
with open(path, "w", encoding="utf8") as wf:
|
||||
yaml.round_trip_dump(
|
||||
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
|
||||
def __load_file(self):
|
||||
"""
|
||||
说明:
|
||||
读取配置文件
|
||||
"""
|
||||
self._data: Dict[str, PluginCount] = {}
|
||||
if self.file.exists():
|
||||
with open(self.file, "r", encoding="utf8") as f:
|
||||
self._data: dict = yaml.load(f)
|
||||
self._data = self._data["PluginCountLimit"]
|
||||
self.reload_count_limit()
|
||||
temp = _yaml.load(f)
|
||||
if "PluginCountLimit" in temp.keys():
|
||||
for k, v in temp["PluginCountLimit"].items():
|
||||
self._data[k] = PluginCount.parse_obj(v)
|
||||
|
||||
Executable → Regular
+83
-60
@@ -1,11 +1,11 @@
|
||||
from typing import List, Optional, Union, Tuple
|
||||
from .data_class import StaticData
|
||||
from typing import List, Optional, Union, Tuple, Dict
|
||||
from utils.manager.data_class import StaticData
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from ruamel import yaml
|
||||
from .models import PluginSetting
|
||||
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
_yaml = yaml.YAML(typ="safe")
|
||||
|
||||
|
||||
class Plugins2settingsManager(StaticData):
|
||||
@@ -14,97 +14,120 @@ class Plugins2settingsManager(StaticData):
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self.file = file
|
||||
super().__init__(None)
|
||||
if file.exists():
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = _yaml.load(f)
|
||||
if self._data:
|
||||
if "PluginSettings" in self._data.keys():
|
||||
self._data = (
|
||||
self._data["PluginSettings"] if self._data["PluginSettings"] else {}
|
||||
)
|
||||
for x in self._data.keys():
|
||||
if self._data[x].get("cost_gold") is None:
|
||||
self._data[x]["cost_gold"] = 0
|
||||
super().__init__(file, False)
|
||||
self.__load_file()
|
||||
|
||||
def add_plugin_settings(
|
||||
self,
|
||||
plugin: str,
|
||||
cmd: Optional[List[str]] = None,
|
||||
default_status: Optional[bool] = True,
|
||||
level: Optional[int] = 5,
|
||||
limit_superuser: Optional[bool] = False,
|
||||
default_status: bool = True,
|
||||
level: int = 5,
|
||||
limit_superuser: bool = False,
|
||||
plugin_type: Tuple[Union[str, int]] = ("normal",),
|
||||
cost_gold: int = 0,
|
||||
):
|
||||
"""
|
||||
添加一个插件设置
|
||||
:param plugin: 插件模块名称
|
||||
:param cmd: 命令 或 命令别名
|
||||
:param default_status: 默认开关状态
|
||||
:param level: 功能权限等级
|
||||
:param limit_superuser: 功能状态是否限制超级用户
|
||||
:param plugin_type: 插件类型
|
||||
:param cost_gold: 需要消费的金币
|
||||
说明:
|
||||
添加一个插件设置
|
||||
参数:
|
||||
:param plugin: 插件模块名称
|
||||
:param cmd: 命令 或 命令别名
|
||||
:param default_status: 默认开关状态
|
||||
:param level: 功能权限等级
|
||||
:param limit_superuser: 功能状态是否限制超级用户
|
||||
:param plugin_type: 插件类型
|
||||
:param cost_gold: 需要消费的金币
|
||||
"""
|
||||
level = level or 5
|
||||
cmd = cmd or []
|
||||
cost_gold = cost_gold or 0
|
||||
self._data[plugin] = {
|
||||
"level": level if level is not None else 5,
|
||||
"default_status": default_status if default_status is not None else True,
|
||||
"limit_superuser": (
|
||||
limit_superuser
|
||||
if limit_superuser is not None
|
||||
else False
|
||||
),
|
||||
"cmd": cmd,
|
||||
"plugin_type": list(
|
||||
plugin_type if plugin_type is not None else ("normal",)
|
||||
),
|
||||
"cost_gold": cost_gold,
|
||||
}
|
||||
self._data[plugin] = PluginSetting(
|
||||
cmd=cmd,
|
||||
level=level,
|
||||
default_status=default_status,
|
||||
limit_superuser=limit_superuser,
|
||||
plugin_type=plugin_type,
|
||||
cost_gold=cost_gold,
|
||||
)
|
||||
|
||||
def get_plugin_data(self, module: str) -> dict:
|
||||
def get_plugin_data(self, module: str) -> Optional[PluginSetting]:
|
||||
"""
|
||||
通过模块名获取数据
|
||||
:param module: 模块名称
|
||||
说明:
|
||||
通过模块名获取数据
|
||||
参数:
|
||||
:param module: 模块名称
|
||||
"""
|
||||
if self._data.get(module) is not None:
|
||||
return self._data.get(module)
|
||||
return {}
|
||||
return self._data.get(module)
|
||||
|
||||
def get_plugin_module(
|
||||
self, cmd: str, is_all: bool = False
|
||||
) -> Union[str, List[str]]:
|
||||
"""
|
||||
根据 cmd 获取功能 modules
|
||||
:param cmd: 命令
|
||||
:param is_all: 获取全部包含cmd的模块
|
||||
说明:
|
||||
根据 cmd 获取功能 modules
|
||||
参数:
|
||||
:param cmd: 命令
|
||||
:param is_all: 获取全部包含cmd的模块
|
||||
"""
|
||||
keys = []
|
||||
for key in self._data.keys():
|
||||
if cmd in self._data[key]["cmd"]:
|
||||
if cmd in self._data[key].cmd:
|
||||
if is_all:
|
||||
keys.append(key)
|
||||
else:
|
||||
return key
|
||||
return keys
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
说明:
|
||||
重载本地数据
|
||||
"""
|
||||
self.__load_file()
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
"""
|
||||
说明:
|
||||
保存文件
|
||||
参数:
|
||||
:param path: 文件路径
|
||||
"""
|
||||
path = path or self.file
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
if path:
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
yaml.dump({"PluginSettings": self._data}, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
yaml.dump(
|
||||
{"PluginSettings": self.dict()},
|
||||
f,
|
||||
indent=2,
|
||||
Dumper=yaml.RoundTripDumper,
|
||||
allow_unicode=True,
|
||||
)
|
||||
_data = yaml.round_trip_load(open(path, encoding="utf8"))
|
||||
_data["PluginSettings"].yaml_set_start_comment(
|
||||
"""# 模块与对应命令和对应群权限
|
||||
# 用于生成帮助图片 和 开关功能
|
||||
# key:模块名称
|
||||
# level:需要的群等级
|
||||
# default_status:加入群时功能的默认开关状态
|
||||
# limit_superuser: 功能状态是否限制超级用户
|
||||
# cmd: 关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称
|
||||
# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1),1代表帮助命令列向排列,否则为横向排列""",
|
||||
indent=2,
|
||||
)
|
||||
with open(path, "w", encoding="utf8") as wf:
|
||||
yaml.round_trip_dump(
|
||||
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
|
||||
def reload(self):
|
||||
def __load_file(self):
|
||||
"""
|
||||
重载本地数据
|
||||
说明:
|
||||
读取配置文件
|
||||
"""
|
||||
self._data: Dict[str, PluginSetting] = {}
|
||||
if self.file.exists():
|
||||
with open(self.file, "r", encoding="utf8") as f:
|
||||
self._data: dict = _yaml.load(f)
|
||||
self._data = self._data["PluginSettings"]
|
||||
temp = _yaml.load(f)
|
||||
if "PluginSettings" in temp.keys():
|
||||
for k, v in temp["PluginSettings"].items():
|
||||
self._data[k] = PluginSetting.parse_obj(v)
|
||||
|
||||
Executable → Regular
+66
-57
@@ -1,7 +1,33 @@
|
||||
from typing import Optional
|
||||
from typing import Optional, Dict, Callable, Union
|
||||
from pathlib import Path
|
||||
from .data_class import StaticData
|
||||
from . import group_manager
|
||||
from utils.manager.data_class import StaticData
|
||||
from utils.manager import group_manager
|
||||
from .models import Plugin
|
||||
|
||||
|
||||
def init_plugin(func: Callable):
|
||||
"""
|
||||
说明:
|
||||
初始化群数据
|
||||
参数:
|
||||
:param func: func
|
||||
"""
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
self = args[0]
|
||||
module = args[1]
|
||||
if module not in self._data.keys():
|
||||
self._data[module] = Plugin(
|
||||
plugin_name=module,
|
||||
status=True,
|
||||
error=False,
|
||||
block_type=None,
|
||||
author=None,
|
||||
version=None,
|
||||
)
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class PluginsManager(StaticData):
|
||||
@@ -10,9 +36,10 @@ class PluginsManager(StaticData):
|
||||
"""
|
||||
|
||||
def __init__(self, file: Path):
|
||||
self._data: Dict[str, Plugin]
|
||||
super().__init__(file)
|
||||
if not self._data:
|
||||
self._data = {}
|
||||
for k, v in self._data.items():
|
||||
self._data[k] = Plugin.parse_obj(v)
|
||||
|
||||
def add_plugin_data(
|
||||
self,
|
||||
@@ -26,23 +53,25 @@ class PluginsManager(StaticData):
|
||||
version: Optional[int] = None,
|
||||
):
|
||||
"""
|
||||
添加插件数据
|
||||
:param module: 模块名称
|
||||
:param plugin_name: 插件名称
|
||||
:param status: 插件开关状态
|
||||
:param error: 加载状态
|
||||
:param block_type: 限制类型
|
||||
:param author: 作者
|
||||
:param version: 版本
|
||||
说明:
|
||||
添加插件数据
|
||||
参数:
|
||||
:param module: 模块名称
|
||||
:param plugin_name: 插件名称
|
||||
:param status: 插件开关状态
|
||||
:param error: 加载状态
|
||||
:param block_type: 限制类型
|
||||
:param author: 作者
|
||||
:param version: 版本
|
||||
"""
|
||||
self._data[module] = {
|
||||
"plugin_name": plugin_name,
|
||||
"status": status,
|
||||
"error": error,
|
||||
"block_type": block_type,
|
||||
"author": author,
|
||||
"version": version,
|
||||
}
|
||||
self._data[module] = Plugin(
|
||||
plugin_name=plugin_name,
|
||||
status=status,
|
||||
error=error,
|
||||
block_type=block_type,
|
||||
author=author,
|
||||
version=version,
|
||||
)
|
||||
|
||||
def block_plugin(
|
||||
self, module: str, group_id: Optional[int] = None, block_type: str = "all"
|
||||
@@ -67,9 +96,7 @@ class PluginsManager(StaticData):
|
||||
"""
|
||||
self._set_plugin_status(module, "unblock", group_id)
|
||||
|
||||
def get_plugin_status(
|
||||
self, module: str, block_type: str = "all"
|
||||
) -> bool:
|
||||
def get_plugin_status(self, module: str, block_type: str = "all") -> bool:
|
||||
"""
|
||||
说明:
|
||||
获取插件状态
|
||||
@@ -78,13 +105,12 @@ class PluginsManager(StaticData):
|
||||
:param block_type: 限制类型
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
if self._data[module]["block_type"] == "all" and block_type == "all":
|
||||
if self._data[module].block_type == "all" and block_type == "all":
|
||||
return False
|
||||
else:
|
||||
return not self._data[module]["block_type"] == block_type
|
||||
return not self._data[module].block_type == block_type
|
||||
return True
|
||||
|
||||
def get_plugin_block_type(self, module: str) -> str:
|
||||
def get_plugin_block_type(self, module: str) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
获取功能限制类型
|
||||
@@ -92,18 +118,19 @@ class PluginsManager(StaticData):
|
||||
:param module: 模块名称
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
return self._data[module]["block_type"]
|
||||
return ""
|
||||
return self._data[module].block_type
|
||||
|
||||
@init_plugin
|
||||
def get_plugin_error_status(self, module: str) -> bool:
|
||||
"""
|
||||
插件是否成功加载
|
||||
:param module: 模块名称
|
||||
说明:
|
||||
插件是否成功加载
|
||||
参数:
|
||||
:param module: 模块名称
|
||||
"""
|
||||
if module not in self._data.keys():
|
||||
self.init_plugin(module)
|
||||
return self._data[module]["error"]
|
||||
return self._data[module].error
|
||||
|
||||
@init_plugin
|
||||
def _set_plugin_status(
|
||||
self,
|
||||
module: str,
|
||||
@@ -120,7 +147,6 @@ class PluginsManager(StaticData):
|
||||
:param group_id: 群组
|
||||
:param block_type: 限制类型
|
||||
"""
|
||||
group_id = str(group_id) if group_id else group_id
|
||||
if module:
|
||||
if group_id:
|
||||
if status == "block":
|
||||
@@ -128,28 +154,11 @@ class PluginsManager(StaticData):
|
||||
else:
|
||||
group_manager.unblock_plugin(f"{module}:super", int(group_id))
|
||||
else:
|
||||
if module not in self._data.keys():
|
||||
self.init_plugin(module)
|
||||
if status == "block":
|
||||
self._data[module]["status"] = False
|
||||
self._data[module]["block_type"] = block_type
|
||||
self._data[module].status = False
|
||||
self._data[module].block_type = block_type
|
||||
else:
|
||||
if module in self._data.keys():
|
||||
self._data[module]["status"] = True
|
||||
self._data[module]["block_type"] = None
|
||||
self._data[module].status = True
|
||||
self._data[module].block_type = None
|
||||
self.save()
|
||||
|
||||
def init_plugin(self, module: str):
|
||||
"""
|
||||
初始化插件数据
|
||||
:param module: 模块名称
|
||||
"""
|
||||
if module not in self._data.keys():
|
||||
self._data[module] = {
|
||||
"plugin_name": module,
|
||||
"status": True,
|
||||
"error": False,
|
||||
"block_type": None,
|
||||
"author": None,
|
||||
"version": None,
|
||||
}
|
||||
|
||||
Executable → Regular
+271
-271
@@ -1,271 +1,271 @@
|
||||
from utils.manager.data_class import StaticData
|
||||
from nonebot.adapters.onebot.v11 import Bot, ActionFailed
|
||||
from services.log import logger
|
||||
from typing import Optional, Literal
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.utils import get_user_avatar
|
||||
from pathlib import Path
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
class RequestManager(StaticData):
|
||||
|
||||
"""
|
||||
好友请求/邀请请求 管理
|
||||
"""
|
||||
|
||||
def __init__(self, file: Optional[Path]):
|
||||
super().__init__(file)
|
||||
if not self._data:
|
||||
self._data = {"private": {}, "group": {}}
|
||||
|
||||
def add_request(
|
||||
self,
|
||||
id_: int,
|
||||
type_: str,
|
||||
flag: str,
|
||||
*,
|
||||
nickname: Optional[str] = None,
|
||||
level: Optional[int] = None,
|
||||
sex: Optional[str] = None,
|
||||
age: Optional[str] = None,
|
||||
from_: Optional[str] = "",
|
||||
comment: Optional[str] = None,
|
||||
invite_group: Optional[int] = None,
|
||||
group_name: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
添加一个请求
|
||||
:param id_: id,用户id或群id
|
||||
:param type_: 类型,private 或 group
|
||||
:param flag: event.flag
|
||||
:param nickname: 用户昵称
|
||||
:param level: 等级
|
||||
:param sex: 性别
|
||||
:param age: 年龄
|
||||
:param from_: 请求来自
|
||||
:param comment: 附加消息
|
||||
:param invite_group: 邀请群聊
|
||||
:param group_name: 群聊名称
|
||||
"""
|
||||
self._data[type_][str(len(self._data[type_].keys()))] = {
|
||||
"id": id_,
|
||||
"flag": flag,
|
||||
"nickname": nickname,
|
||||
"level": level,
|
||||
"sex": sex,
|
||||
"age": age,
|
||||
"from": from_,
|
||||
"comment": comment,
|
||||
"invite_group": invite_group,
|
||||
"group_name": group_name,
|
||||
}
|
||||
self.save()
|
||||
|
||||
def remove_request(self, type_: str, id_: int):
|
||||
"""
|
||||
删除一个请求数据
|
||||
:param type_: 类型
|
||||
:param id_: id,user_id 或 group_id
|
||||
"""
|
||||
for x in self._data[type_].keys():
|
||||
if self._data[type_][x].get("id") == id_:
|
||||
del self._data[type_][x]
|
||||
break
|
||||
self.save()
|
||||
|
||||
def get_group_id(self, id_: int) -> Optional[int]:
|
||||
"""
|
||||
通过id获取群号
|
||||
:param id_: id
|
||||
"""
|
||||
data = self._data["group"].get(str(id_))
|
||||
if data:
|
||||
return data["invite_group"]
|
||||
return None
|
||||
|
||||
async def approve(self, bot: Bot, id_: int, type_: str) -> int:
|
||||
"""
|
||||
同意请求
|
||||
:param bot: Bot
|
||||
:param id_: id
|
||||
:param type_: 类型,private 或 group
|
||||
"""
|
||||
return await self._set_add_request(bot, id_, type_, True)
|
||||
|
||||
async def refused(self, bot: Bot, id_: int, type_: str) -> Optional[int]:
|
||||
"""
|
||||
拒绝请求
|
||||
:param bot: Bot
|
||||
:param id_: id
|
||||
:param type_: 类型,private 或 group
|
||||
"""
|
||||
return await self._set_add_request(bot, id_, type_, False)
|
||||
|
||||
def clear(self, type_: Optional[str] = None): # type_: Optional[Literal["group", "private"]] = None
|
||||
"""
|
||||
清空所有请求信息,无视请求
|
||||
:param type_: 类型
|
||||
"""
|
||||
if type_:
|
||||
self._data[type_] = {}
|
||||
else:
|
||||
self._data = {"private": {}, "group": {}}
|
||||
self.save()
|
||||
|
||||
def delete_request(self, id_: int, type_: str): # type_: Literal["group", "private"]
|
||||
"""
|
||||
删除请求
|
||||
:param id_: id
|
||||
:param type_: 类型
|
||||
"""
|
||||
id_ = str(id_)
|
||||
if self._data[type_].get(id_):
|
||||
del self._data[type_][id_]
|
||||
self.save()
|
||||
|
||||
def set_group_name(self, group_name: str, group_id: int):
|
||||
"""
|
||||
设置群聊名称
|
||||
:param group_name: 名称
|
||||
:param group_id: id
|
||||
"""
|
||||
for id_ in self._data["group"].keys():
|
||||
if self._data["group"][id_]["invite_group"] == group_id:
|
||||
self._data["group"][id_]["group_name"] = group_name
|
||||
break
|
||||
self.save()
|
||||
|
||||
async def show(self, type_: str) -> Optional[str]:
|
||||
"""
|
||||
请求可视化
|
||||
"""
|
||||
data = self._data[type_]
|
||||
if not data:
|
||||
return None
|
||||
img_list = []
|
||||
id_list = list(data.keys())
|
||||
id_list.reverse()
|
||||
for id_ in id_list:
|
||||
age = data[id_]["age"]
|
||||
nickname = data[id_]["nickname"]
|
||||
comment = data[id_]["comment"] if type_ == "private" else ""
|
||||
from_ = data[id_]["from"]
|
||||
sex = data[id_]["sex"]
|
||||
ava = BuildImage(
|
||||
80, 80, background=BytesIO(await get_user_avatar(data[id_]["id"]))
|
||||
)
|
||||
ava.circle()
|
||||
age_bk = BuildImage(
|
||||
len(str(age)) * 6 + 6,
|
||||
15,
|
||||
color="#04CAF7" if sex == "male" else "#F983C1",
|
||||
)
|
||||
age_bk.text((3, 1), f"{age}", fill=(255, 255, 255))
|
||||
x = BuildImage(
|
||||
90, 32, font_size=15, color="#EEEFF4", font="HYWenHei-85W.ttf"
|
||||
)
|
||||
x.text((0, 0), "同意/拒绝", center_type="center")
|
||||
x.circle_corner(10)
|
||||
A = BuildImage(500, 100, font_size=24, font="msyh.ttf")
|
||||
A.paste(ava, (15, 0), alpha=True, center_type="by_height")
|
||||
A.text((120, 15), nickname)
|
||||
A.paste(age_bk, (120, 50), True)
|
||||
A.paste(
|
||||
BuildImage(
|
||||
200,
|
||||
0,
|
||||
font_size=12,
|
||||
plain_text=f"对方留言:{comment}",
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(120 + age_bk.w + 10, 49),
|
||||
True,
|
||||
)
|
||||
if type_ == "private":
|
||||
A.paste(
|
||||
BuildImage(
|
||||
200,
|
||||
0,
|
||||
font_size=12,
|
||||
plain_text=f"来源:{from_}",
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(120, 70),
|
||||
True,
|
||||
)
|
||||
else:
|
||||
A.paste(
|
||||
BuildImage(
|
||||
200,
|
||||
0,
|
||||
font_size=12,
|
||||
plain_text=f"邀请你加入:{data[id_]['group_name']}({data[id_]['invite_group']})",
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(120, 70),
|
||||
True,
|
||||
)
|
||||
A.paste(x, (380, 35), True)
|
||||
A.paste(
|
||||
BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"id:{id_}",
|
||||
font_size=13,
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(400, 10),
|
||||
True,
|
||||
)
|
||||
img_list.append(A)
|
||||
A = BuildImage(500, len(img_list) * 100, 500, 100)
|
||||
for img in img_list:
|
||||
A.paste(img)
|
||||
bk = BuildImage(A.w, A.h + 50, color="#F8F9FB", font_size=20)
|
||||
bk.paste(A, (0, 50))
|
||||
bk.text(
|
||||
(15, 13), "好友请求" if type_ == "private" else "群聊请求", fill=(140, 140, 143)
|
||||
)
|
||||
return bk.pic2bs4()
|
||||
|
||||
async def _set_add_request(
|
||||
self, bot: Bot, id_: int, type_: str, approve: bool
|
||||
) -> int:
|
||||
"""
|
||||
处理请求
|
||||
:param bot: Bot
|
||||
:param id_: id
|
||||
:param type_: 类型,private 或 group
|
||||
:param approve: 是否同意
|
||||
"""
|
||||
id_ = str(id_)
|
||||
if id_ in self._data[type_].keys():
|
||||
try:
|
||||
if type_ == "private":
|
||||
await bot.set_friend_add_request(
|
||||
flag=self._data[type_][id_]["flag"], approve=approve
|
||||
)
|
||||
rid = self._data[type_][id_]["id"]
|
||||
else:
|
||||
await bot.set_group_add_request(
|
||||
flag=self._data[type_][id_]["flag"],
|
||||
sub_type="invite",
|
||||
approve=approve,
|
||||
)
|
||||
rid = self._data[type_][id_]["invite_group"]
|
||||
except ActionFailed:
|
||||
logger.info(
|
||||
f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
|
||||
f"的{'好友' if type_ == 'private' else '入群'}请求失败了..."
|
||||
)
|
||||
return 1 # flag失效
|
||||
else:
|
||||
logger.info(
|
||||
f"{'同意' if approve else '拒绝'}{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
|
||||
f"的{'好友' if type_ == 'private' else '入群'}请求..."
|
||||
)
|
||||
del self._data[type_][id_]
|
||||
self.save()
|
||||
return rid
|
||||
return 2 # 未找到id
|
||||
from utils.manager.data_class import StaticData
|
||||
from nonebot.adapters.onebot.v11 import Bot, ActionFailed
|
||||
from services.log import logger
|
||||
from typing import Optional
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.utils import get_user_avatar
|
||||
from pathlib import Path
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
class RequestManager(StaticData):
|
||||
|
||||
"""
|
||||
好友请求/邀请请求 管理
|
||||
"""
|
||||
|
||||
def __init__(self, file: Optional[Path]):
|
||||
super().__init__(file)
|
||||
if not self._data:
|
||||
self._data = {"private": {}, "group": {}}
|
||||
|
||||
def add_request(
|
||||
self,
|
||||
id_: int,
|
||||
type_: str,
|
||||
flag: str,
|
||||
*,
|
||||
nickname: Optional[str] = None,
|
||||
level: Optional[int] = None,
|
||||
sex: Optional[str] = None,
|
||||
age: Optional[str] = None,
|
||||
from_: Optional[str] = "",
|
||||
comment: Optional[str] = None,
|
||||
invite_group: Optional[int] = None,
|
||||
group_name: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
添加一个请求
|
||||
:param id_: id,用户id或群id
|
||||
:param type_: 类型,private 或 group
|
||||
:param flag: event.flag
|
||||
:param nickname: 用户昵称
|
||||
:param level: 等级
|
||||
:param sex: 性别
|
||||
:param age: 年龄
|
||||
:param from_: 请求来自
|
||||
:param comment: 附加消息
|
||||
:param invite_group: 邀请群聊
|
||||
:param group_name: 群聊名称
|
||||
"""
|
||||
self._data[type_][str(len(self._data[type_].keys()))] = {
|
||||
"id": id_,
|
||||
"flag": flag,
|
||||
"nickname": nickname,
|
||||
"level": level,
|
||||
"sex": sex,
|
||||
"age": age,
|
||||
"from": from_,
|
||||
"comment": comment,
|
||||
"invite_group": invite_group,
|
||||
"group_name": group_name,
|
||||
}
|
||||
self.save()
|
||||
|
||||
def remove_request(self, type_: str, id_: int):
|
||||
"""
|
||||
删除一个请求数据
|
||||
:param type_: 类型
|
||||
:param id_: id,user_id 或 group_id
|
||||
"""
|
||||
for x in self._data[type_].keys():
|
||||
if self._data[type_][x].get("id") == id_:
|
||||
del self._data[type_][x]
|
||||
break
|
||||
self.save()
|
||||
|
||||
def get_group_id(self, id_: int) -> Optional[int]:
|
||||
"""
|
||||
通过id获取群号
|
||||
:param id_: id
|
||||
"""
|
||||
data = self._data["group"].get(str(id_))
|
||||
if data:
|
||||
return data["invite_group"]
|
||||
return None
|
||||
|
||||
async def approve(self, bot: Bot, id_: int, type_: str) -> int:
|
||||
"""
|
||||
同意请求
|
||||
:param bot: Bot
|
||||
:param id_: id
|
||||
:param type_: 类型,private 或 group
|
||||
"""
|
||||
return await self._set_add_request(bot, id_, type_, True)
|
||||
|
||||
async def refused(self, bot: Bot, id_: int, type_: str) -> Optional[int]:
|
||||
"""
|
||||
拒绝请求
|
||||
:param bot: Bot
|
||||
:param id_: id
|
||||
:param type_: 类型,private 或 group
|
||||
"""
|
||||
return await self._set_add_request(bot, id_, type_, False)
|
||||
|
||||
def clear(self, type_: Optional[str] = None): # type_: Optional[Literal["group", "private"]] = None
|
||||
"""
|
||||
清空所有请求信息,无视请求
|
||||
:param type_: 类型
|
||||
"""
|
||||
if type_:
|
||||
self._data[type_] = {}
|
||||
else:
|
||||
self._data = {"private": {}, "group": {}}
|
||||
self.save()
|
||||
|
||||
def delete_request(self, id_: int, type_: str): # type_: Literal["group", "private"]
|
||||
"""
|
||||
删除请求
|
||||
:param id_: id
|
||||
:param type_: 类型
|
||||
"""
|
||||
id_ = str(id_)
|
||||
if self._data[type_].get(id_):
|
||||
del self._data[type_][id_]
|
||||
self.save()
|
||||
|
||||
def set_group_name(self, group_name: str, group_id: int):
|
||||
"""
|
||||
设置群聊名称
|
||||
:param group_name: 名称
|
||||
:param group_id: id
|
||||
"""
|
||||
for id_ in self._data["group"].keys():
|
||||
if self._data["group"][id_]["invite_group"] == group_id:
|
||||
self._data["group"][id_]["group_name"] = group_name
|
||||
break
|
||||
self.save()
|
||||
|
||||
async def show(self, type_: str) -> Optional[str]:
|
||||
"""
|
||||
请求可视化
|
||||
"""
|
||||
data = self._data[type_]
|
||||
if not data:
|
||||
return None
|
||||
img_list = []
|
||||
id_list = list(data.keys())
|
||||
id_list.reverse()
|
||||
for id_ in id_list:
|
||||
age = data[id_]["age"]
|
||||
nickname = data[id_]["nickname"]
|
||||
comment = data[id_]["comment"] if type_ == "private" else ""
|
||||
from_ = data[id_]["from"]
|
||||
sex = data[id_]["sex"]
|
||||
ava = BuildImage(
|
||||
80, 80, background=BytesIO(await get_user_avatar(data[id_]["id"]))
|
||||
)
|
||||
ava.circle()
|
||||
age_bk = BuildImage(
|
||||
len(str(age)) * 6 + 6,
|
||||
15,
|
||||
color="#04CAF7" if sex == "male" else "#F983C1",
|
||||
)
|
||||
age_bk.text((3, 1), f"{age}", fill=(255, 255, 255))
|
||||
x = BuildImage(
|
||||
90, 32, font_size=15, color="#EEEFF4", font="HYWenHei-85W.ttf"
|
||||
)
|
||||
x.text((0, 0), "同意/拒绝", center_type="center")
|
||||
x.circle_corner(10)
|
||||
A = BuildImage(500, 100, font_size=24, font="msyh.ttf")
|
||||
A.paste(ava, (15, 0), alpha=True, center_type="by_height")
|
||||
A.text((120, 15), nickname)
|
||||
A.paste(age_bk, (120, 50), True)
|
||||
A.paste(
|
||||
BuildImage(
|
||||
200,
|
||||
0,
|
||||
font_size=12,
|
||||
plain_text=f"对方留言:{comment}",
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(120 + age_bk.w + 10, 49),
|
||||
True,
|
||||
)
|
||||
if type_ == "private":
|
||||
A.paste(
|
||||
BuildImage(
|
||||
200,
|
||||
0,
|
||||
font_size=12,
|
||||
plain_text=f"来源:{from_}",
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(120, 70),
|
||||
True,
|
||||
)
|
||||
else:
|
||||
A.paste(
|
||||
BuildImage(
|
||||
200,
|
||||
0,
|
||||
font_size=12,
|
||||
plain_text=f"邀请你加入:{data[id_]['group_name']}({data[id_]['invite_group']})",
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(120, 70),
|
||||
True,
|
||||
)
|
||||
A.paste(x, (380, 35), True)
|
||||
A.paste(
|
||||
BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"id:{id_}",
|
||||
font_size=13,
|
||||
font_color=(140, 140, 143),
|
||||
),
|
||||
(400, 10),
|
||||
True,
|
||||
)
|
||||
img_list.append(A)
|
||||
A = BuildImage(500, len(img_list) * 100, 500, 100)
|
||||
for img in img_list:
|
||||
A.paste(img)
|
||||
bk = BuildImage(A.w, A.h + 50, color="#F8F9FB", font_size=20)
|
||||
bk.paste(A, (0, 50))
|
||||
bk.text(
|
||||
(15, 13), "好友请求" if type_ == "private" else "群聊请求", fill=(140, 140, 143)
|
||||
)
|
||||
return bk.pic2bs4()
|
||||
|
||||
async def _set_add_request(
|
||||
self, bot: Bot, id_: int, type_: str, approve: bool
|
||||
) -> int:
|
||||
"""
|
||||
处理请求
|
||||
:param bot: Bot
|
||||
:param id_: id
|
||||
:param type_: 类型,private 或 group
|
||||
:param approve: 是否同意
|
||||
"""
|
||||
id_ = str(id_)
|
||||
if id_ in self._data[type_].keys():
|
||||
try:
|
||||
if type_ == "private":
|
||||
await bot.set_friend_add_request(
|
||||
flag=self._data[type_][id_]["flag"], approve=approve
|
||||
)
|
||||
rid = self._data[type_][id_]["id"]
|
||||
else:
|
||||
await bot.set_group_add_request(
|
||||
flag=self._data[type_][id_]["flag"],
|
||||
sub_type="invite",
|
||||
approve=approve,
|
||||
)
|
||||
rid = self._data[type_][id_]["invite_group"]
|
||||
except ActionFailed:
|
||||
logger.info(
|
||||
f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
|
||||
f"的{'好友' if type_ == 'private' else '入群'}请求失败了..."
|
||||
)
|
||||
return 1 # flag失效
|
||||
else:
|
||||
logger.info(
|
||||
f"{'同意' if approve else '拒绝'}{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
|
||||
f"的{'好友' if type_ == 'private' else '入群'}请求..."
|
||||
)
|
||||
del self._data[type_][id_]
|
||||
self.save()
|
||||
return rid
|
||||
return 2 # 未找到id
|
||||
|
||||
Executable → Regular
+1
-1
@@ -1,7 +1,7 @@
|
||||
from typing import Union, List, Optional
|
||||
|
||||
from configs.path_config import IMAGE_PATH, DATA_PATH, RECORD_PATH, TEXT_PATH, FONT_PATH, LOG_PATH
|
||||
from .data_class import StaticData
|
||||
from utils.manager.data_class import StaticData
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from services.log import logger
|
||||
|
||||
Executable → Regular
@@ -1,3 +1,4 @@
|
||||
import io
|
||||
from pathlib import Path
|
||||
from typing import List, Union
|
||||
|
||||
@@ -26,7 +27,7 @@ def image(
|
||||
return MessageSegment.image(file)
|
||||
logger.warning(f"图片 {file.absolute()}缺失...")
|
||||
return ""
|
||||
elif isinstance(file, bytes):
|
||||
elif isinstance(file, (bytes, io.BytesIO)):
|
||||
return MessageSegment.image(file)
|
||||
elif b64:
|
||||
return MessageSegment.image(b64 if "base64://" in b64 else "base64://" + b64)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
|
||||
from pydantic import BaseModel, create_model
|
||||
from nonebot.adapters.onebot.v11 import Message, MessageEvent
|
||||
from pydantic import BaseModel
|
||||
from typing import Any
|
||||
|
||||
|
||||
@@ -10,5 +10,7 @@ class ShopParam(BaseModel):
|
||||
bot: Any
|
||||
event: MessageEvent
|
||||
num: int # 道具单次使用数量
|
||||
message: Message
|
||||
text: str
|
||||
send_success_msg: bool = True # 是否发送使用成功信息
|
||||
max_num_limit: int = 1 # 单次使用最大次数
|
||||
|
||||
+16
-7
@@ -18,8 +18,17 @@ try:
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
require("nonebot_plugin_apscheduler")
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
|
||||
scheduler = require("nonebot_plugin_apscheduler").scheduler
|
||||
scheduler = scheduler
|
||||
|
||||
# 全局字典
|
||||
GDict = {
|
||||
"run_sql": [], # 需要启动前运行的sql语句
|
||||
"_shop_before_handle": {}, # 商品使用前函数
|
||||
"_shop_after_handle": {}, # 商品使用后函数
|
||||
}
|
||||
|
||||
|
||||
class CountLimiter:
|
||||
@@ -110,8 +119,8 @@ class BanCheckLimiter:
|
||||
self.mint[key] = 0
|
||||
return False
|
||||
if (
|
||||
self.mint[key] >= self.default_count
|
||||
and time.time() - self.mtime[key] < self.default_check_time
|
||||
self.mint[key] >= self.default_count
|
||||
and time.time() - self.mtime[key] < self.default_check_time
|
||||
):
|
||||
self.mtime[key] = time.time()
|
||||
self.mint[key] = 0
|
||||
@@ -402,7 +411,7 @@ def cn2py(word: str) -> str:
|
||||
|
||||
|
||||
def change_pixiv_image_links(
|
||||
url: str, size: Optional[str] = None, nginx_url: Optional[str] = None
|
||||
url: str, size: Optional[str] = None, nginx_url: Optional[str] = None
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
@@ -422,8 +431,8 @@ def change_pixiv_image_links(
|
||||
if nginx_url:
|
||||
url = (
|
||||
url.replace("i.pximg.net", nginx_url)
|
||||
.replace("i.pixiv.cat", nginx_url)
|
||||
.replace("_webp", "")
|
||||
.replace("i.pixiv.cat", nginx_url)
|
||||
.replace("_webp", "")
|
||||
)
|
||||
return url
|
||||
|
||||
@@ -441,4 +450,4 @@ def change_img_md5(path_file: Union[str, Path]) -> bool:
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"改变图片MD5发生错误 {type(e)}:{e} Path:{path_file}")
|
||||
return False
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user