mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-09-30 01:00:02 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2a54a8164 | ||
|
|
4dbab21853 | ||
|
|
3063c5bc02 | ||
|
|
30b56583bd | ||
|
|
5e5168f804 | ||
|
|
4a8122829e | ||
|
|
52ba2cf89a | ||
|
|
58957cdf44 | ||
|
|
71f860a500 | ||
|
|
9b4cde819e | ||
|
|
99637de1de | ||
|
|
19dbd3f2b0 | ||
|
|
7567794f74 | ||
|
|
df0d15c1b3 | ||
|
|
9a84c02bb5 | ||
|
|
e623c4f30f | ||
|
|
3fd7acffb2 | ||
|
|
71f8c16c26 | ||
|
|
b64699c4ab | ||
|
|
786d62bb2f | ||
|
|
ac48d3d542 | ||
|
|
c4d9523ec2 | ||
|
|
cb6549c297 | ||
|
|
29816ada2a | ||
|
|
dd12bdc028 | ||
|
|
2a52c0711b | ||
|
|
2653f67193 | ||
|
|
b892617824 | ||
|
|
a6fb05c91d |
+3
-1
@@ -142,4 +142,6 @@ test.py
|
||||
server.py
|
||||
member_activity_handle.py
|
||||
Yu-Gi-Oh/
|
||||
|
||||
search_image/
|
||||
black_word/
|
||||
csgo/
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
## 未完成的文档
|
||||
|
||||
[传送门](https://hibikier.github.io/zhenxun_bot/)
|
||||
# [传送门](https://hibikier.github.io/zhenxun_bot/)
|
||||
|
||||
## 真寻的帮助
|
||||
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
|
||||
@@ -29,6 +29,18 @@
|
||||
|
||||
[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
|
||||
|
||||
## 来点优点?
|
||||
一.作为bot:
|
||||
* 实现了许多功能,且提供了大量功能管理命令
|
||||
* __..... 更多详细请通过`传送门`查看文档!__
|
||||
|
||||
二.作为框架?:
|
||||
* 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改
|
||||
* 方便增删插件,原生nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
|
||||
* 提供了cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`__plugin_cd_limit__`
|
||||
* 基本完善的权限管理
|
||||
* __..... 更多详细请通过`传送门`查看文档!__
|
||||
|
||||
|
||||
## 功能列表
|
||||
<details>
|
||||
@@ -51,9 +63,11 @@
|
||||
- [x] 商店/我的金币/购买道具/使用道具
|
||||
- [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
|
||||
- [x] 我有一个朋友想问问..(借鉴pcrbot插件)
|
||||
- [x] 原神黄历 (使用[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
|
||||
- [x] 原神黄历
|
||||
- [x] 原神今日素材
|
||||
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
|
||||
- [x] 原神便笺查询
|
||||
- [x] 原神玩家查询
|
||||
- [x] 金币红包
|
||||
- [x] 微博热搜
|
||||
- [x] B站主播/UP/番剧订阅
|
||||
@@ -89,6 +103,8 @@
|
||||
- [x] 通过PID获取图片
|
||||
- [x] 功能统计可视化
|
||||
|
||||
- [x] 关于
|
||||
|
||||
### 已实现的管理员功能
|
||||
- [x] 更新群组成员信息
|
||||
- [x] 95%的群功能开关
|
||||
@@ -101,6 +117,7 @@
|
||||
- [x] 删除图片 (同上)
|
||||
- [x] 群内B站订阅
|
||||
- [x] 群词条
|
||||
- [x] 休息吧/醒来
|
||||
|
||||
### 已实现的超级用户功能
|
||||
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
|
||||
@@ -126,6 +143,11 @@
|
||||
- [x] 功能开关(更多设置)
|
||||
- [x] 功能状态
|
||||
- [x] b了
|
||||
- [x] 执行sql
|
||||
- [x] 重载配置
|
||||
- [x] 清理临时数据
|
||||
- [x] 增删群认证
|
||||
- [x] 同意/拒绝好友/群聊请求
|
||||
|
||||
#### 超级用户的被动技能
|
||||
- [x] 邀请入群提醒(别人邀请真寻入群)
|
||||
@@ -152,127 +174,6 @@
|
||||
- [x] 定时更新权限
|
||||
</details>
|
||||
|
||||
## 功能具体指令
|
||||
<details>
|
||||
<summary>功能具体指令说明</summary>
|
||||
|
||||
### 常用功能
|
||||
|
||||
** [*]:表示该参数可有多个 [?]:表示参数可选 **
|
||||
|
||||
| 功能 | 指令 | 说明
|
||||
| ----------------------| :--------------------------------------:| :------------------------:
|
||||
| 签到 | 签到/我的签到/好感度排行/好感度总榜/好感度总榜\[显示我/屏蔽我] | 普通的签到插件,可以获得好感度和金币<br>好感度影响开箱次数和涩图触发概率,金币用于购买道具,俄罗斯轮盘赌注以及金币红包<br>好感度总榜,显示所有群的群员好感度排行,可通过命令好感度总榜\[显示我/屏蔽我] 来设置是否隐藏
|
||||
| 发送图片 | 美图/壁纸/萝莉 \[id]?(默认随机)/\[num]张图\[keyword] | 发送指定文件夹下的图片<br>示例:萝莉->发送img文件夹下luoli文件夹下的图片<br>在线搜索一些不色的图,示例:3张图米浴
|
||||
| 色图 | 色图/色图xx/n张色图/n张xx的色图/查色图(查询本地色图信息)/色图r【n<10】 | 色图r返回10张r18色图(仅私聊),并限制每日次数(默认5次)<br>其他示例:色图 真寻 <br>5张真寻的色图
|
||||
| 黑白草图 | 黑白草图/黑白图 \[文字] \[图片] | 整活生成器,示例:黑白图 我喜欢真寻 \[图片]
|
||||
| coser | coser/cos/括丝 | coser图片,说实话挺失望的,太色了
|
||||
| 骂我 | 骂我 | 就是发送钉宫的语音罢了
|
||||
| 戳一戳 | 戳一戳 | 随机发送钉宫语音 or 美图 or 萝莉图 or 文本
|
||||
| 模拟开箱 | 开箱 \[武器箱名称](默认随机)/N连开箱 \[武器箱名称](默认随机)/我的开箱/群开箱统计/我的金色 | 当不指定武器箱时默认随机,此功能需要先在/open_cases/config.py中编写指定武器箱数据,然后提前爬取价格,使用超级用户命令更新cookie后,再使用命令更新xx武器箱【注:未设置爬取频率,可能会被禁用api(请谨慎!!用小号!!)】
|
||||
| 鲁迅说过 | 鲁迅说过 \[文本] | 示例:鲁迅说过 真寻世界第一可爱
|
||||
| 假消息 | 假消息 \[网址] \[标题] \[内容]? \[图片]? | 构造虚假的分享消息
|
||||
| 商店系统 | 商店/我的金币/购买道具 \[名称或序号] \[数量](默认1)/使用道具 \[名称或序号] | 示例:<br>购买道具 1 3<br>购买道具 好感度双倍加持卡Ⅰ 3<br>使用道具 1<br>使用道具 好感度双倍加持卡Ⅰ
|
||||
| 抽卡系统 | 原神/明日方舟/赛马娘/坎公骑冠剑/碧蓝航线/阴阳师/公主连结(pcr)/FGO N抽/一井 | 详细帮助请查看: [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw) <br>示例:原神90抽
|
||||
| 我有一个朋友 | 我有一个朋友他说/想问问/\[文本] | 会将文本中的(他,她,它)替换成 '我'<br>示例:我有一个朋友想问问他喜不喜欢真寻
|
||||
| 昵称系统 | 以后叫我\[昵称]/以后请叫我\[昵称]/我是谁/我叫什么 | 此昵称会替换与真寻聊天中 '你' 的名称(群名片),群与群与私聊的昵称相互独立
|
||||
| 原神黄历 | 原神黄历 | 查看今日原神黄历,含有每日10:25的定时任务
|
||||
| 原神材料 | 今日素材 | 发送可莉特调的截图
|
||||
| 丘丘语翻译 | 丘丘翻译/丘丘一下/丘丘语翻译 | 示例:丘丘一下 mimi
|
||||
| 原神资源查询 | 原神资源查询 \[资源名称] \[路线]?/\[资源名称]在哪/哪里有\[资源名称]/原神资源列表 | 如果资源名称末尾添加‘路线’的话将生成残缺缺缺版的优先路径<br>示例:嘟嘟莲在哪<br>原神资源查询嘟嘟莲路线
|
||||
| 俄罗斯轮盘 | 装弹\[子弹数] \[金额](默认200)/开枪/结算/我的战绩/胜场排行/败场排行/欧洲人排行/慈善家排行 | 紧张刺激的群内小游戏,使用每日签到的金币作为赌注,具体玩法请发送 真寻帮助 俄罗斯轮盘
|
||||
| 红包系统 | 塞红包\[金额] \[数量](默认5)/抢/开/戳一戳/退回 | 仿微信明日方舟红包的样式(pil拼图大师!),每个红包金额随机生成,最多会是红包总金额的1/3,退回用于退回一分钟后还未开完的红包
|
||||
| 金币排行 | 金币排行 | 字面意思
|
||||
|网易云热评 | 到点了/12点了/网易云热评/网易云评论 | 防下塔
|
||||
| 古诗 | 念诗/念首诗/来首诗 | 突然文艺起来了
|
||||
|微博热搜 | 微博热搜/微博热搜[序号]? | 快捷热搜查询方式
|
||||
| pil对图片的操作 | 修改尺寸/等比压缩/旋转图片/水平翻转/铅笔滤镜/模糊效果/锐化效果/高斯模糊/边缘检测/底色替换 | 选项较多,请直接发送 真寻图片帮助
|
||||
| BUFF皮肤底价查询 | 查询皮肤 \[武器名称] \[皮肤名称] | 网络不友好的话会经常超时<br>示例:查询皮肤 沙漠之鹰 印花集
|
||||
| 天气查询 | \[城市]天气 | 非常常见的插件,第一个入门插件
|
||||
| 疫情查询 | 疫情/查询疫情 \[城市名或省份名] | 示例:疫情杭州
|
||||
| bt磁力搜索 | bt \[关键词] \[页数]?(默认第1页) | 该功能仅仅提供给私聊,因为可以搜到一些色色的东西,示例:bt钢铁侠 5
|
||||
| 上车 | 略 | 直接查看真寻帮助 上车,每日限制次数(默认5)
|
||||
| 以图识番 | 识番 \[图片] | 以图搜翻,图片越清晰越完整正确率越高
|
||||
| 以图搜图 | 识图 (asc)? \[图片] | 参数asc更换搜索引擎为ascii2d,默认为saucenao
|
||||
| 点歌 | 点歌 \[歌名] | 网易云点歌小助手
|
||||
| 搜番 | 搜番 \[关键字] | 群聊只返回5个结果,私聊返回20个结果
|
||||
| epic白嫖游戏通知 | epic | 通知你又到了白嫖游戏的时候,可以不玩,不能没有
|
||||
| P站排行榜 | p站排行 \[排行类型参数]? \[数量]? \[日期]?| 9种不同排行榜,r18类型仅可私聊,通过参数选择,查看真寻帮助p站排行<br>示例:p站排行榜 1 9 2018-4-25
|
||||
| 搜图 | 搜图 \[关键词] \[数量]? \[排序方式]? \[r18]?| r18仅可私聊,查看真寻帮助搜图
|
||||
| 通过PID搜索图片 | p搜 [pid] | 在群内使用此功能会在30秒内撤回
|
||||
| 翻译 | 英翻/日翻/韩翻/翻韩/翻日/翻英 \[文本] | 三种语言互相翻译
|
||||
| 获取b站视频封面 | b封面 [链接/av/bv/cv/直播id] | 快捷的封面获取方式
|
||||
| 群欢迎消息 | 群欢迎消息/查看群欢迎消息/查看当前群欢迎消息 | 查看给真寻设置的群欢迎消息
|
||||
| 自我介绍 | 自我介绍 | 没错,一份正经的真寻自我介绍
|
||||
| 我的权限 | 我的权限 | 真寻内部定义的一套权限系统
|
||||
| 我的信息 | 我的信息 | 唯一的作用就是看看什么时候加入群
|
||||
| 撤回 | 撤回 \[消息位置]?(默认为最新一条消息) | 按顺序撤回发送的消息,示例:撤回 1
|
||||
| 滴滴滴- | 滴滴滴- \[文本] | 用于用户联系真寻的超级用户
|
||||
|功能调用统计可视化 | 功能调用统计(自记录以来的功能调用统计)<br>周功能调用统计 [plugin_name]<br>月功能调用统计 [plugin_name]| 当plugin_name为空时为7天或30内的所有功能统计
|
||||
| pix | pix/PIX [tags/uid/pid:pid] [num] | 无参数时随机查看pix图库的图片(无r18),num数量默认=1,tags:查看相关tags图片,uid:查找相关画师图片,pid:pid:指定查看pid图片<br>示例:pix原神 3<br>pix23493844<br>pixpid:29429933
|
||||
| 添加pix关键词/uid/pid | 添加pix关键词/uid/pid *[关键词/uid/pid]| 添加关键词或uid或pid用于下次搜索,关键词搜索相关tag,uid会收录作者下收藏符合标准的作品,pid收录单张作品<br>示例:添加pix关键词 原神<br> 添加pixuid 123441<br>添加pixpid 2748937|
|
||||
| 查看pix图库 | 查看pix图库 [tags] | 查看已收录的tag相关图片数量<br>示例:查看pix图库 原神 莫娜
|
||||
|显示pix关键词 | 显示pix关键词 | 查看已收录的所有关键词/UID/PID
|
||||
| b了 | b了 [at] | 使真寻完全忽略一个用户的所有信息
|
||||
| B站订阅 | 添加订阅 [主播/UP/番剧] [id/链接/番名] / 删除订阅 [id] / 查看订阅 | 可以通过直接间链接或主播间id添加订阅主播开播提醒,动态和投稿,可以通过番名,番剧的id,或者番剧链接添加番剧订阅(是番剧id,md开头,不是集数id,ep开头的)更新, 可以通过UP个人id或UP主页链接订阅UP动态和投稿
|
||||
|
||||
### 管理员功能
|
||||
|
||||
**群主与群管理员默认5级权限**
|
||||
|
||||
| 功能 | 权限等级 | 指令 | 说明
|
||||
| -------------| --------------| :--------------------------------------:| :------------------------:
|
||||
| 更新群组成员信息 | 1 | 更新群组成员信息/更新群组成员列表 | 存储群员的基本信息,虽然有自动更新,但备个命令以防万一
|
||||
| 群功能开关 | 2 | 开启/关闭\[指令名]功能 | 群帮助中左边带有√的功能都可以通过此命令开启或关闭,示例:开启色图
|
||||
| 查看群被动技能 | 2 | 群通知状态 | 详细请查看被动技能列表
|
||||
| 被动技能开关 | 2 | 开启/关闭被动技能 | 有时候花里胡哨通知也会很烦人
|
||||
| 自定义群欢迎消息 | 2 | 自定义群欢迎消息 \[文本] \[图片] | 文本和图片至少需要一个,在文本内添加"\[at]"字符串可以用来设置艾特进群的新群员
|
||||
| 黑名单 | 5 | .ban/.unban \[at] \[小时]? \[分钟]?| 不提供具体时间的话则ban掉永久,且权限低的用户无法unban高权限用户的ban,同级权限也无法进行ban/unban <br>示例:.ban@笨蛋 1 50
|
||||
| 刷屏检测相关 | 5 | 刷屏检测设置/设置检测时间 \[文本]/设置检测次数 \[文本]/设置禁言时长 \[分钟]| 非常讨厌刷屏的人,打算给他们一点教训
|
||||
| 上传图片 | 6 | 上传图片 \[图库] \[图片]... | 上传图片至指定图库,虽然并不打算开放给群员,但还是写了,支持批量图片<br>示例:上传图片 美图 \[图片]..
|
||||
| 删除图片 | 6 | 删除图片 [图库] \[图片id] | 通过指定本地图片id来删除指定图库的图片<br>示例:删除图片 美图 1
|
||||
| 移动图片 | 6 | 移动图片 \[移出的图库] \[移入的图库] \[图片id] | 移动指定图库中的图片到指定的新图库中,移入的图片id更改为移入图库的最后一位,移除的图库中原本图片的id又最后一位图片替代<br>示例:移动图片 美图 萝莉 22
|
||||
|B站订阅 | 5 | 功能同上,就是在群中有权限限制 | 略
|
||||
|
||||
### 超级用户功能
|
||||
|
||||
| 功能 | 指令 | 说明
|
||||
| ----------------------| :--------------------------------------:| :------------------------:
|
||||
| 权限增删 | 添加/删除权限 \[at] \[level]<br>添加/删除权限 [qq] [group] [level] | 用于添加或修改权限等级,且该权限不会被自动更新取消
|
||||
| 所有群组/好友 | 所有群组/好友 | 查看真寻添加的群组与好友
|
||||
| 广播 | 广播- [文本] | 广播所有群组
|
||||
| 更新色图 | 更新色图 | 更新群友搜索色图时保存的url
|
||||
| 回复 | /t | 命令较多,请查看/t帮助,省略群号则私聊用户(必须要有用户的好友)
|
||||
| 更新cookie | 更新cookie \[cookie] | 用于更新开箱数据和查询buff皮肤
|
||||
| 开启广播通知 | 开启/关闭广播通知 \[群号] | 用于开启/关闭是否对某些群进行广播(上边的广播方法)
|
||||
| 退群 | 退群 \[群号] | 用于退出某一些群
|
||||
| 检查系统状态 | 自检 | 略
|
||||
| 更新好友/群组信息| 更新好友/群组信息 | 包含自动更新,被t出群等等有更好的可视信息
|
||||
| 重载卡池 | 略 | 重载抽卡的游戏卡池,请查看 \[nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw)
|
||||
| 添加商品 | 添加商品 \[名称]-\[价格]-\[描述]-\[折扣](小数)?-\[限时时间](分钟)? | 为真寻的商店添加一点点道具<br>示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60
|
||||
| 删除商品 | 删除商品 \[名称或序号] | 在真寻的商店中删除一点东西
|
||||
| 修改商品 | 修改商品 -name \[名称或序号] -price \[价格] -des \[描述] -discount \[折扣] -time \[限时]| 注意空格,不需要的参数可以不加<br>示例:修改商品 -name 1 -price 900 【修改序号为1的商品的价格为900】
|
||||
| 节日红包 | 节日红包 \[金额] \[数量] \[祝福语]? \[群号]?... | 群号支持批量,使用空格隔开,不使用群号则对所有群发送节日红包,节日红包有效时间为24小时,祝福语默认为“恭喜发财 大吉大利”<br>示例:节日红包 10000 15 真寻真可爱 123324423 23423423
|
||||
| 修改群权限 | 修改群权限 \[group] \[level] | 所以说这功能是对内鬼的无奈,默认群权限为5,默认无法使用 色图/coser/p站排行/搜图(这些功能都要9级权限)
|
||||
|更新原神今日素材| 更新原神今日素材 | 自动更新原神每日素材失败时可以手动触发
|
||||
|更新原神资源信息| 更新原神资源信息 | 除了每日自动更新的资源外,额外更新大地图
|
||||
| 清理数据 | 清理数据 | 清理 temp,rar,r18_rar 文件夹的文件数据
|
||||
|添加pix关键词/uid/pid | 添加pix关键词/uid/pid [keyword/pid:pid/uid:uid] [-f]? | 与普通功能相同,额外可以通过参数 -f 强制通过检测
|
||||
|删除pix关键词 | 删除pix关键词 *[keyword/uid/pid:pid] | 删除已收录的keyword/uid/pid
|
||||
|更新pix关键词 | 更新pix关键词 [keyword/pid:pid/uid:uid] [num]?| 更新keyword,uid,pid或指定uid,pid,未指定时,则更新全部,当num未指定时为keyword/uid/pid更新全部<br>示例:更新pix关键词<br>更新pix关键词uid 8<br>更新pix关键词pid:83457477<br>num:倒叙更新数量
|
||||
|删除pix图片 | 删除pix图片 [*pid] [-b]? | [-b]参数为删除的同时加入黑名单(不再更新),虽然是pid,但是_p也可以<br>示例:删除pix图片3458344 8235234_p1 -b
|
||||
|显示pix关键词 | 显示pix关键词 | 与普通功能相同,额外显示待收录和黑名单
|
||||
|pix检测更新 | pix检测更新 [update]? | 检测从未更新过的pid或uid,-update参数将在检测后直接更新未更新过的pid或uid<br>示例:pix检测更新 update
|
||||
| 检查更新真寻 | 检查更新真寻 | 不再需要麻烦的clone第一步
|
||||
| 关闭功能 | 关闭[功能] [group/private]/*[群号]? | 关闭色图:维护功能(关闭总开关)<br>关闭色图 g:在群内限制功能<br>关闭色图 p:在私聊限制功能<br>关闭色图 1234678:禁用12345678的色图功能
|
||||
| 群白名单 | 添加/删除群白名单 *[群号] / 查看群白名单 | 白名单内的群不会受到 维护 限制
|
||||
| 功能状态 | 功能状态 | 查看功能开关状态
|
||||
| pix | pix [-s/-r] [keyword] | 可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
|
||||
| 重载插件配置 |重载插件配置 |用于生效手动修改配文件
|
||||
|帮助 -super | 帮助[功能] -super | 显示该插件的超级用户帮助
|
||||
|
||||
</details>
|
||||
|
||||
## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
|
||||
|
||||
|
||||
@@ -321,365 +222,76 @@ python bot.py
|
||||
|
||||
## 更新
|
||||
|
||||
### 2021/12/1 \[v0.0.6.5]
|
||||
|
||||
* 群权限-1时超级用户命令依旧生效
|
||||
* 修复以真寻为开头的词条不会被回复
|
||||
* 修复购买道具可以为负数
|
||||
* P站排行/搜图提供配置项,将略过大于指定张数的作品
|
||||
* 昵称提供关键词屏蔽配置项,会将指定关键词替换为“*”
|
||||
* 取消了自动更新,改为自动检测版本
|
||||
|
||||
### 2021/11/29 \[v0.0.6.4]
|
||||
|
||||
* 新增cos图撤回配置项
|
||||
* 新增默认群权限配置项
|
||||
* 修复权限等级类配置无法正常应用
|
||||
|
||||
### 2021/11/24 \[v0.0.6.3]
|
||||
|
||||
* 修复在线搜索色图出错
|
||||
* 修复pix无法正确获取HIBIAPI
|
||||
|
||||
### 2021/11/23 \[v0.0.6.2]
|
||||
|
||||
* 替换cos API
|
||||
* 提供私聊b了,即跨群b了用户
|
||||
* 修复游戏抽卡导入角色失败(原神)
|
||||
* 修复无Pixiv代理时报错
|
||||
* 将项目中大部分aiohttp替换为httpx
|
||||
* 删除了丘丘人翻译插件
|
||||
* 新增群词条
|
||||
* 修复游戏抽卡碧蓝航线bwiki格式更改导致获取报错
|
||||
* 首次启动会生成配置文件后停止程序,配置后再次启动即可
|
||||
|
||||
### 2021/11/18
|
||||
|
||||
* 修复超级用户无法正确拉真寻入群
|
||||
|
||||
### 2021/11/14
|
||||
|
||||
* 修复功能总开关无法正确开启
|
||||
|
||||
### 2021/11/12
|
||||
|
||||
* 修复PIX无法url无法正确获取
|
||||
|
||||
### 2021/11/10
|
||||
|
||||
* 修复PIX表重复创建导致首次无法运行
|
||||
* 检测Omage图库改为命令方式:检测omega图库
|
||||
|
||||
### 2021/11/9
|
||||
|
||||
* 修复管理员帮助无法正常响应
|
||||
* 修复被ban时会一直回复被ban提醒
|
||||
|
||||
### 2021/11/5
|
||||
|
||||
* 修复ai没有图灵key时报错
|
||||
* 提供图片路径resource/img/background/check
|
||||
|
||||
### 2021/11/4
|
||||
|
||||
* 通用排行榜改用图片消息,且可以自定义排行榜人数
|
||||
* 优化CreateMat排行榜数据显示
|
||||
* 修复了pix更新多余参数导致失败的问题
|
||||
* 修复滴滴滴-注入风险
|
||||
* 修复无法正常关闭滴滴滴,戳一戳
|
||||
* 添加了发送图片撤回配置项WITHDRAW_IMAGE_TIME
|
||||
* 修复了天气regex文本过长时会正则匹配过久导致nb卡顿
|
||||
* message_build新增custom_forward_msg用于快捷生成转发消息
|
||||
* 插件配置改为yaml存储,新增Config,用于获取和新增插件配置
|
||||
* 新增 当插件加载失败时,会发送消息提醒超级用户,且在功能状态中对应失败插件写上[ERROR]
|
||||
* 修复当查看-spuer插件帮助时无法正确回复
|
||||
* 群内帮助图片会随群内功能开关和插件总开关变化
|
||||
* 自检改为图像形式
|
||||
* 更新色图删除了rar_setu,r18_rar和rar文件夹,压缩将统一在temp文件夹
|
||||
* 更新色图只有在有更新数量或报错时才会提醒超级用户
|
||||
* 群欢迎消息加入cd
|
||||
* 加入资源管理resources_manager
|
||||
* 新增 好友请求/群聊邀请 控制命令
|
||||
|
||||
### 2021/10/15
|
||||
|
||||
* 适配了原神资源查询米游社地图返回的新格式
|
||||
|
||||
### 2021/10/8
|
||||
|
||||
* 修复疫情省份查询失效
|
||||
* 修复功能调用统计全局下统计可能发生错误
|
||||
|
||||
### 2021/10/4
|
||||
|
||||
* 修复了功能调用统计失效问题
|
||||
* 当色图库中没有色图时,会在线搜索色图而不是‘没找到符合条件的色图...’
|
||||
* 快速更新权限再给超级用户发送错误日志
|
||||
* 修复疫情未加载省份城市无法正常使用
|
||||
|
||||
### 2021/10/3
|
||||
|
||||
* 对插件进行分离
|
||||
* 重写了插件与限制管理器以及帮助获取
|
||||
* 修改一些插件目录和数据存储目录
|
||||
* 插件通用配置与限制数据将以ymal文件存储 \[路径:data/configs]
|
||||
* 所有商店相关操作调用统计合并为商店(包括之前已经保存的数据,会先进行备份)
|
||||
* 简化了点歌的代码相关
|
||||
* 修复了碧蓝航线抽卡新框导致报错无法正常初始化
|
||||
* 修复了P站排行/搜图在PC端无法正常显示
|
||||
* 添加了插件对超级用户是否限制的配置 ‘limit_superuser’
|
||||
* 添加命令 ‘重载插件配置’,用于生效手动修改配文件
|
||||
* 超级用户帮助可以添加 -super 来显示该插件的超级用户帮助,示例:帮助.ban -super
|
||||
* 原神黄历改为网页截图
|
||||
* 修改了鲁迅说逻辑结构
|
||||
* 修改了统计图表样式,改为自定义CreateMat
|
||||
* 节日红包不再被24小时限制,群内多个节日红包将会覆盖
|
||||
* 当群权限为-1时,不会对群发送修改权限通知,并屏蔽此群一切命令(包括提醒)
|
||||
* 修复了红包数量可以过大或为负数,红包数量大于群员数量时会修改为群员数量
|
||||
* 修复了负数开箱
|
||||
* 签到最低好感度设置为0.01 [@pull/53](https://github.com/HibiKier/zhenxun_bot/pull/53)
|
||||
* pip安装新依赖 ruamel.yaml
|
||||
* 修复功能 EPIC [@pull/58](https://github.com/HibiKier/zhenxun_bot/pull/58)
|
||||
|
||||
### 2021/9/10
|
||||
|
||||
* 修复撤回消息有时无法正确获取消息id
|
||||
|
||||
### 2021/9/9
|
||||
|
||||
* 替换coser API
|
||||
* 修复签到uid可能不默认为0
|
||||
* 修复签到可能重复的问题
|
||||
* 修复无订阅时递归出错
|
||||
* 启用了plugins2info_dict, plugins2cd_dict, plugins2exists_dict配置文件,通过USE_CONFIG_FILE=True开启
|
||||
* 修复涩图local_id会被固定为50
|
||||
* 优化图库数量查询
|
||||
* 修复原神大地图过大无法打开报错
|
||||
* 修复无法显示正确的涩图上限
|
||||
|
||||
### 2021/9/7
|
||||
|
||||
* 修改 update_info.json
|
||||
* 修改 更新信息 图片大小
|
||||
* 修复 查看订阅 命令 UP和番剧无法正常显示
|
||||
* 修复订阅推送无法正确推送
|
||||
* 修复搜图返回列表为空时无法正确回复 [@pull/40](https://github.com/HibiKier/zhenxun_bot/pull/40)
|
||||
|
||||
### 2021/9/5
|
||||
* 添加配置PIX_IMAGE_SIZE,调整PIX下载图片大小,当设置的图片404时,改为原图
|
||||
* 新增配置DEFAULT_GROUP_LEVEL,默认群等级
|
||||
* 新增超级用户功能 super ban,将屏蔽被ban用户的所有消息,指令:b了
|
||||
* b站转发解析支持纯BV号解析,且五分钟内不会解析相同url
|
||||
* 俄罗斯轮盘新增 连胜/最高连胜/连败/最高连败 纪录,新增 最高连胜排行榜/最高连败排行榜
|
||||
* 增加扩展图库 OmegaPixivIllusts,不想自己找图的人福音([Ailitonia](https://github.com/Ailitonia) 佬的高质量精品手筛图库)([传送门](https://github.com/Ailitonia/omega-miya/blob/master/archive_data/db_pixiv.7z) ),可以手动导入图库,也可以将解压文件放在bot.py同级目录重启bot
|
||||
* 增加配置PIX_OMEGA_PIXIV_RATIO,PIX功能发送PIX图库和扩展图库OmegaPixivIllusts图片的比例,如果没有使用扩展图库OmegaPixivIllusts,请设置为(10, 0)
|
||||
* 增加配置WITHDRAW_PIX_TIME,用于配置在开关PIX图片在群私聊的自动撤回
|
||||
* 上传图库cases, 开箱 也可以连抽(未更新过没有价格)
|
||||
* 新增命令 查看群白名单
|
||||
* plugins2info_dict新增键"default_status",设置加入新群时功能的默认开关状态
|
||||
* 增加配置plugins2exists_dict,可自定义是否阻塞某命令同时触发多次
|
||||
* 增加配置plugins2cd_dict,可自定义为命令添加cd
|
||||
* 新增B站订阅(直播/番剧/UP)[测试],提供命令:添加订阅 [主播/UP/番剧] [id/链接/番名],删除订阅 [id],查看订阅
|
||||
* 优化pix和色图的数据库查询
|
||||
* 触发已关闭的功能的正则时不再触发ai
|
||||
* 更换coser API
|
||||
* PIX搜索pid功能在群聊无法搜索PIX图库的r18和OmegaPixivIllusts的r15以及r18,超级用户除外
|
||||
* PIX单次搜索的图片张数超级用户限制为至多30张,普通用户10张
|
||||
* PIX超级用户新增-s,-r,可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
|
||||
* 优化P站排行和搜图,现在需要艾特,改为使用HIBIAPI,在群内时将使用合并消息(群聊搜图会屏蔽R-18)
|
||||
* win10下playwright相关功能无法使用,但是不再需要删除文件
|
||||
* 签到大改,优化签到方式与逻辑,改为图片形式发送,有概率额外获得随机道具(好感度有加成)
|
||||
* 修改撤回功能,改为回复撤回,回复发送撤回
|
||||
* 更改logging为loguru
|
||||
* 删除了 发送图片 中的 [N]张图[keyword] 功能
|
||||
* 修复私聊 关闭[功能] 默认不为 全部 而要添加参数 ‘a’
|
||||
* 修复0权限用户可以修改禁言检测相关设置
|
||||
|
||||
### 2021/8/17
|
||||
|
||||
* 新增配置CHECK_NOTICE_INFO_CD,修改群权限,个人权限检测各种检测的提示消息cd
|
||||
* 新增功能‘连续上传图片’功能,直到输入‘stop’停止
|
||||
* 新增功能维护时白名单以及对应命令(白名单中的群聊不受维护限制)
|
||||
* 新增ALAPI功能,微博热搜,可以通过序号来查看部分热搜内容
|
||||
* 新增配置NICKNAME,偶尔也想换换名字的说(自我介绍仅当NICKNAME=真寻时生效)
|
||||
* 提供 更新信息 命令,可以使群员查看更新内容(可开关,与其他功能无异,但不会被统计,该命令图片由自动更新生成)
|
||||
* 超级用户可以通过私聊来对指定qq进行ban/unban
|
||||
* 超级用户帮助改为图片形式
|
||||
* 公开图库删除‘色图’
|
||||
* 群权限检测,个人权限检测,功能开关检测合并,权限检测顺序:个人权限 > 群权限 > 插件开关 >超级用户禁用某群插件 > 超级用户限制群里插件 > 插件维护检测
|
||||
* 重写群功能管理,超级用户可对群/私聊分别禁用,也可禁用指定群指定功能,新增命令‘功能状态’,超级用户关闭功能提供参数(默认ALL):group/g(群聊),private/p(私聊)
|
||||
* 超级用户不会被任何权限等检测阻挡
|
||||
* 不会重复复读,复读消息只会发送一次
|
||||
* b站转发解析支持b23.tv,www.bilibili.com链接,cv专栏(playwright截图,压缩倍率0.5,较慢且文字可能不清晰,后优化)
|
||||
* 我有一个朋友功能,当艾特一个对象时,‘朋友’改为艾特对象的群名片或昵称
|
||||
* 修复‘上传/删除/移动图片’目录不正确
|
||||
* 修复天气功能,当城市名在‘天气’后时报错
|
||||
* 修复配置INITIAL_SETU_PROBABILITY不生效
|
||||
|
||||
### 2021/8/10
|
||||
|
||||
* 重复的好友请求和邀群提示在5分钟内不会重复提示
|
||||
* 疫情会优先检查城市,城市省份市区重名时请添加‘市’
|
||||
* 添加命令‘原神资源查找’,‘设置cookie’
|
||||
* 添加配置AUTO_UPDATE_ZHENXUN,是否自动更新真寻,默认True
|
||||
* 添加配置MAX_RUSSIAN_BET_GOLD,俄罗斯轮盘赌注最大金额,默认1000
|
||||
* 检查更新真寻定时任务时间改为12 : 00
|
||||
* 添加功能能不能好好说话(nbnhhsh)
|
||||
* 添加功能随机roll,无参为数字,有参为随机参数
|
||||
* 添加linux重启脚本以及重启命令‘重启’(建议首次生成restart.sh先查看命令是否正确)
|
||||
* 修复管理员功能的权限检测
|
||||
* 修复丢人爬开关
|
||||
|
||||
### 2021/8/6
|
||||
|
||||
* 天气查询会优先遍历城市
|
||||
* 添加自动更新真寻命令
|
||||
|
||||
##### 如果你的版本为 2021/8/4,可以直接复制plugins/check_zhenxun_update后,通过指令来更新真寻
|
||||
|
||||
### 2021/8/4
|
||||
|
||||
* 修改天气与疫情城市数据,改为api获取,丰富疫情的回复消息
|
||||
* 原神资源查询,大地图将被压缩至9M,且启动时当大地图存在时不再自动更新地图
|
||||
* 下载数据库内色图时将直接存储至_setu,不再存储至临时文件
|
||||
* 重复的好友请求或邀请请求在一定时间不会重复发送提醒
|
||||
* 添加每日自动清理临时图片定时任务
|
||||
* 修复金币排行显示
|
||||
* 修复无法正常关闭戳一戳功能
|
||||
|
||||
### 2021/7/30
|
||||
|
||||
* 重构代码,进行优化,添加注释,删除冗余代码,降低代码耦合
|
||||
* 添加功能:PIX(一套快捷的pixiv存图命令,自建图库存储url等信息?意在获取自己或群友xp的图)
|
||||
* 添加功能:清理临时图片文件(temp/rar/r18_rar文件夹)
|
||||
* 添加额外定时任务(5分钟检测一次),解决加入新群时无法及时为管理员提供权限
|
||||
* 添加配置ALAPI_AI_CHECK,开关AI回复文本检测
|
||||
* 添加配置IMPORT_DEFAULT_SHOP_GOODS,控制是否导入内置的三个商品(好感度加持卡ⅠⅡⅢ)
|
||||
* 添加配置ONLY_USE_LOCAL_SETU,仅仅使用本地色图(有的话),提升速度,但无法在线搜索色图和保存链接
|
||||
* 添加配置WITHDRAW_SETU_TIME,是否需要延迟撤回色图,可配置仅群里,私聊或全部
|
||||
* 好友请求,入群请求,滴滴滴-,/t,被踢出群提醒,的提示消息更加丰富
|
||||
* 彻底重写原神资源查找,添加规划路线(路线残缺缺缺缺版,有空补)添加命令‘更新原神资源信息’,强制更新地图等资源
|
||||
* 优化色图和P站排行/搜图检测用户是否正在触发命令代码
|
||||
* 当群最后发言大于36小时,也会关闭广播通知
|
||||
* 功能维护时超级用户依然可以调用(苦了谁都不能苦了自己)
|
||||
* 修复获取赛马娘UP公告
|
||||
* 重写 色图/更新色图
|
||||
* 色图数据存储改为数据库,启动时会更新之前的色图数据(有的话),更新完毕后会删除原数据文件,如果需要保留请提前备份,
|
||||
* lolicon api改为v2
|
||||
* 取消r18次数限制
|
||||
* 单次搜索至多保存100条链接
|
||||
* 添加定时撤回
|
||||
* 暂时取消上传/删除色图
|
||||
*
|
||||
* 更新建议(不要替换你的data和resources文件夹!)
|
||||
* 删除configs,plugins,services,utils,models文件夹重新clone
|
||||
* 删除多余文件夹,resources/img/genshin/seek_god_eye
|
||||
* 清空resources/img/genshin/genshin_icon文件夹,仅保留box.png和box_alpha.png
|
||||
* 替换bot.py
|
||||
|
||||
### 2021/7/27
|
||||
|
||||
* 原神今日素材改为单张截图+拼图,更新文件utils/img_utils.py及plugins/genshin/material_remind/__init__.py
|
||||
|
||||
### 2021/7/26
|
||||
|
||||
* 修复原神今日素材稻妻城开放后截图不完整的问题
|
||||
|
||||
### 2021/7/14
|
||||
|
||||
* 原神今日素材自动更新时间由 00:01 -> 04:01 [#issues7](https://github.com/HibiKier/zhenxun_bot/issues/7)
|
||||
* 小问题的修复和优化
|
||||
|
||||
### 2021/7/12
|
||||
|
||||
* 修复开箱功能单抽出金时存储格式错误导致 ‘我的金色’ 无法正常发送图片
|
||||
* 小问题的修复和优化
|
||||
|
||||
### 2021/7/6
|
||||
|
||||
* 识番功能 trace.moe 替换为新API(旧API已失效)
|
||||
* 小问题的修复和优化
|
||||
|
||||
### 2021/6/30
|
||||
|
||||
* 将plugin2name和plugin2level合并为plugin2info
|
||||
* util改为utils(。。!)
|
||||
* 修复当用户发送速度极快时开箱会突破每日限制
|
||||
* 新增功能:通过PID获取图片
|
||||
* 发送图片新增功能:搜索图片
|
||||
* 功能统计可视化
|
||||
* 新增命令:好感度总排行
|
||||
* 原神每日素材改为从"可莉特调"截图,提供命令‘更新原神每日素材’和定时任务
|
||||
* 修复月功能统计错误的问题
|
||||
|
||||
### 2021/6/24
|
||||
|
||||
* 添加了一些ALAPI:网易云热评,获取b站视频封面,古诗(需要填写ALAPI_TOKEN)
|
||||
* 如果填写了ALAPI_TOKEN,将会检测备用接口回复的文本是否合规
|
||||
* 优化了色图,当搜索色图下载失败时,会从本地色图库中发送相关tag色图
|
||||
* 当网易云点歌繁忙时会尝试多次点歌
|
||||
|
||||
### 2021/6/23
|
||||
|
||||
* 添加功能:群权限(所以说内鬼都快爬,可以在configs/config.py中修改各个功能的权限等级)
|
||||
* 优化了数据统计,将以7天,30天为周期,为将来更方便实现数据可视化
|
||||
* 更新坎公骑冠剑UP卡池
|
||||
* 修复赛马娘UP卡池
|
||||
* 修复一些小问题
|
||||
|
||||
### 2021/6/18
|
||||
|
||||
* 修复p站排行,搜图因网络问题爆炸时没有具体回复
|
||||
* 更换色图显示方式为 id,title,author,pid
|
||||
* 修复修改商品后商品顺序改变
|
||||
* 滴滴滴- 和 /t支持图片回复
|
||||
* 将/t回复更加简单(可以通过序号),且可以直接发送群
|
||||
* 修复bt功能无法交互
|
||||
|
||||
### 2021/6/17
|
||||
|
||||
* 修复p站排行,搜图因网络问题爆炸时没有具体回复
|
||||
* 更换色图显示方式为 id,title,author,pid
|
||||
|
||||
### 2021/6/15
|
||||
* 修改了‘帮助’功能,具体为‘帮助 指令名’,未指定指令名时则为查看全部功能列表
|
||||
* 修改了色图的存储数据格式
|
||||
* 色图功能搜索的色图改为随机从urls中随机抽取
|
||||
* 将商品数据存储入数据库,提供 '增加/删除/修改商品' 指令
|
||||
* 商店列表图片不再使用固定背景图,改为直接拼图
|
||||
* 增加功能:俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
|
||||
* 增加功能:金币红包(节日红包与群红包相互独立)
|
||||
* 金币排行
|
||||
* 重写一个朋友插件
|
||||
* 其他微小调整
|
||||
|
||||
### 2021/6/4
|
||||
* 重写BT功能
|
||||
* 进行一些BUG修复和微小调整
|
||||
* 添加撤回功能[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
|
||||
* 为色图功能添加额外的 上传色图 和 删除色图方法(影响hash)
|
||||
|
||||
### 2021/5/26
|
||||
* 将语录源更换为一言api
|
||||
### 2021/1/5 \[v0.0.8.0]
|
||||
|
||||
* 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币
|
||||
* 商店插件将作为内置插件移动至basic_plugins
|
||||
* 商店插件通过export提供了方法,不需要修改商店插件代码添加商品数据和生效方法
|
||||
* 修改了hook插件顺序,主要以auth_hook为主
|
||||
* 修改商店图片样式
|
||||
* 取消每次启动更新城市列表(首次除外),采用定时更新,加快bot启动速度
|
||||
* 取消每次启动时截取今日素材,采用调用时截取保存,加快bot启动速度
|
||||
* 更新色图时当图片404时会删除并替换
|
||||
* 疫情消息回复改为图片
|
||||
* 修复商店折扣和限时时间无法生效
|
||||
* 修复原神玩家查询尘歌壶缺少图片
|
||||
|
||||
### 2021/12/26
|
||||
|
||||
* 修复群词条问题 空格 会被录入导致不断回复
|
||||
* 修复米游社app替换api导致无法正常查询
|
||||
|
||||
### 2021/12/24
|
||||
|
||||
* 支持国际疫情数据查询 [@pull/99](https://github.com/HibiKier/zhenxun_bot/pull/99)
|
||||
|
||||
### 2021/12/20
|
||||
|
||||
* 只有发布小于存储时间的新动态/视频的时候才获取并推送 [@pull/96](https://github.com/HibiKier/zhenxun_bot/pull/96)
|
||||
|
||||
### 2021/12/16 \[v0.0.7.0]
|
||||
|
||||
* 提供了真寻群聊功能总开关和对应默认配置项,命令:休息吧 醒来
|
||||
* 新增原神玩家查询,原神便笺查询
|
||||
* 群功能管理提供全部开启/关闭命令:开启/关闭全部功能
|
||||
* 提供主要数据自动备份,且提供自定义配置项
|
||||
* 提供命令:关于,用于介绍Bot之类的
|
||||
* 新增命令exec,用于执行sql语句
|
||||
* 签到提供参数 "all",用于签到所有群聊
|
||||
* Ban提醒提供cd
|
||||
* 本地图库提供配置项SHOW_ID,用于设置发送图片时是否显示id
|
||||
* 色图和PIX提供配置项SHOW_INFO,用于设置发送图片时是否显示图片信息
|
||||
* 所有被动技能提供了进群默认状态配置项
|
||||
* 修复添加权限第二种添加形式无法正确添加正确的权限
|
||||
* 修复签到获取好感度卡时金币不会增加
|
||||
* 修复当红包数量不合法时依旧扣除金币
|
||||
* 修复金币红包再次使用塞红包时无法正确退回上次未开完的金币
|
||||
* 修复 滴滴滴- 只包含图片时不会发送至管理员
|
||||
* 修复添加权限等级错误
|
||||
* 修复群词条以bot名称为开头时无法正确触发
|
||||
* 修改了权限插件加载顺序防止小概率优先加载权限插件引起报错
|
||||
* 本地图库新图库会统一建立在resource/img/image_management文件夹下,如果该文件夹内未找到图库,会从上级目录查找(即:resource/img/)
|
||||
|
||||
<br>
|
||||
|
||||
__..... 更多更新信息请查看文档__
|
||||
|
||||
|
||||
## Todo
|
||||
- [ ] 提供更多对插件的控制
|
||||
- [ ] 明日方舟卡片式的签到..(大概)
|
||||
- [ ] 更多的群管理功能
|
||||
- [ ] 数据清理控制
|
||||
- [ ] docker容器
|
||||
- [ ] web管理
|
||||
|
||||
## 感谢
|
||||
[Onebot](https://github.com/howmanybots/onebot)
|
||||
[go-cqhttp](https://github.com/Mrs4s/go-cqhttp)
|
||||
[nonebot2](https://github.com/nonebot/nonebot2)
|
||||
[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)
|
||||
[cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins#%E7%94%9F%E6%88%90%E5%99%A8%E6%8F%92%E4%BB%B6)
|
||||
[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
|
||||
[nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)
|
||||
[nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager)
|
||||
[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)
|
||||
[nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says)
|
||||
[AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus)
|
||||
[omega-miya](https://github.com/Ailitonia/omega-miya)
|
||||
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
|
||||
[Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台.
|
||||
[nonebot / nonebot2](https://github.com/nonebot/nonebot2) :跨平台Python异步机器人框架
|
||||
[Angel-Hair / XUN_Bot](https://github.com/Angel-Hair/XUN_Bot) :一个基于NoneBot和酷Q的功能性QQ机器人
|
||||
[pcrbot / cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins) :hoshino插件合集
|
||||
[MeetWq /nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw) :A simple withdraw plugin for Nonebot2
|
||||
[maxesisn / nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) :适用于nonebot2的点歌插件
|
||||
[nonepkg / nonebot-plugin-manager](https://github.com/nonepkg/nonebot-plugin-manager) :Nonebot Plugin Manager base on import hook
|
||||
[H-K-Y / Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot) :原神bot,这是一个基于nonebot和HoshinoBot的原神娱乐及信息查询插件
|
||||
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
|
||||
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
|
||||
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
|
||||
[KimigaiiWuyi / GenshinUID]("https://github.com/KimigaiiWuyi/GenshinUID") :一个基于HoshinoBot/NoneBot2的原神UID查询插件
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__: v0.0.6.5
|
||||
__version__: v0.0.8.0
|
||||
|
||||
@@ -11,7 +11,7 @@ from services.db_context import db
|
||||
from models.level_user import LevelUser
|
||||
from configs.config import Config
|
||||
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import asyncio
|
||||
import time
|
||||
@@ -72,7 +72,9 @@ async def custom_group_welcome(
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}")
|
||||
result += msg
|
||||
if img:
|
||||
await AsyncHttpx.download_file(img, DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
|
||||
await AsyncHttpx.download_file(
|
||||
img, DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"
|
||||
)
|
||||
img_result = image(abspath=DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片")
|
||||
except Exception as e:
|
||||
@@ -107,7 +109,16 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
else:
|
||||
if await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.close_group_task(group_id, task)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
return f"已 {status} 全部被动技能!"
|
||||
if cmd == "全部功能":
|
||||
for f in plugins2settings_manager.get_data():
|
||||
if status == "开启":
|
||||
group_manager.unblock_plugin(f, group_id)
|
||||
else:
|
||||
group_manager.block_plugin(f, group_id)
|
||||
return f"已 {status} 全部功能!"
|
||||
if cmd in [task_data[x] for x in task_data.keys()]:
|
||||
type_ = "task"
|
||||
modules = [x for x in task_data.keys() if task_data[x] == cmd]
|
||||
@@ -132,14 +143,14 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
if not group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
|
||||
group_manager.block_plugin(module, group_id)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
if is_super:
|
||||
for file in os.listdir(Path(DATA_PATH) / 'group_help'):
|
||||
file = Path(DATA_PATH) / 'group_help' / file
|
||||
for file in os.listdir(Path(DATA_PATH) / "group_help"):
|
||||
file = Path(DATA_PATH) / "group_help" / file
|
||||
file.unlink()
|
||||
else:
|
||||
_help_image = Path(DATA_PATH) / 'group_help' / f"{group_id}.png"
|
||||
_help_image = Path(DATA_PATH) / "group_help" / f"{group_id}.png"
|
||||
if _help_image.exists():
|
||||
_help_image.unlink()
|
||||
return f"{status} {cmd} 功能!"
|
||||
@@ -158,8 +169,8 @@ def set_plugin_status(cmd: str, block_type: str = "all"):
|
||||
plugins_manager.unblock_plugin(module)
|
||||
else:
|
||||
plugins_manager.block_plugin(module, block_type=block_type)
|
||||
for file in os.listdir(Path(DATA_PATH) / 'group_help'):
|
||||
file = Path(DATA_PATH) / 'group_help' / file
|
||||
for file in os.listdir(Path(DATA_PATH) / "group_help"):
|
||||
file = Path(DATA_PATH) / "group_help" / file
|
||||
file.unlink()
|
||||
|
||||
|
||||
@@ -195,11 +206,11 @@ def _get_plugin_status() -> MessageSegment:
|
||||
rst += "\n"
|
||||
flag_str += f"{flag}\n"
|
||||
height = len(rst.split("\n")) * 24
|
||||
a = CreateImg(250, height, font_size=20)
|
||||
a = BuildImage(250, height, font_size=20)
|
||||
a.text((10, 10), rst)
|
||||
b = CreateImg(200, height, font_size=20)
|
||||
b = BuildImage(200, height, font_size=20)
|
||||
b.text((10, 10), flag_str)
|
||||
A = CreateImg(500, height)
|
||||
A = BuildImage(500, height)
|
||||
A.paste(a)
|
||||
A.paste(b, (270, 0))
|
||||
return image(b64=A.pic2bs4())
|
||||
@@ -288,3 +299,21 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
|
||||
user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def set_group_bot_status(group_id: int, status: bool) -> str:
|
||||
"""
|
||||
设置群聊bot开关状态
|
||||
:param group_id: 群号
|
||||
:param status: 状态
|
||||
"""
|
||||
if status:
|
||||
if group_manager.check_group_bot_status(group_id):
|
||||
return "我还醒着呢!"
|
||||
group_manager.turn_on_group_bot_status(group_id)
|
||||
return "呜..醒来了..."
|
||||
else:
|
||||
group_manager.shutdown_group_bot_status(group_id)
|
||||
# for x in group_manager.get_task_data():
|
||||
# group_manager.close_group_task(group_id, x)
|
||||
return "那我先睡觉了..."
|
||||
|
||||
@@ -14,10 +14,10 @@ def switch_rule(bot: Bot, event: Event, state: T_State) -> bool:
|
||||
:param event: pass
|
||||
:param state: pass
|
||||
"""
|
||||
global cmd
|
||||
try:
|
||||
if not cmd:
|
||||
cmd.append('关闭全部被动')
|
||||
cmd.append('开启全部被动')
|
||||
cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"]
|
||||
_data = group_manager.get_task_data()
|
||||
for key in _data:
|
||||
cmd.append(f"开启{_data[key]}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from nonebot import on_command, on_message
|
||||
from nonebot import on_command, on_message, on_regex
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP
|
||||
from .data_source import (
|
||||
@@ -6,12 +6,14 @@ from .data_source import (
|
||||
set_plugin_status,
|
||||
get_plugin_status,
|
||||
group_current_status,
|
||||
set_group_bot_status
|
||||
)
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME, Config
|
||||
from utils.utils import get_message_text, is_number
|
||||
from nonebot.permission import SUPERUSER
|
||||
from .rule import switch_rule
|
||||
import re
|
||||
|
||||
|
||||
__zx_plugin_name__ = "群功能开关 [Admin]"
|
||||
@@ -24,6 +26,7 @@ usage:
|
||||
群被动状态
|
||||
开启全部被动
|
||||
关闭全部被动
|
||||
醒来/休息吧
|
||||
示例:开启/关闭色图
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
@@ -40,6 +43,7 @@ __plugin_cmd__ = [
|
||||
"群被动状态",
|
||||
"开启全部被动",
|
||||
"关闭全部被动",
|
||||
"醒来/休息吧",
|
||||
"功能状态 [_superuser]",
|
||||
"开启/关闭[功能] [group] [_superuser]",
|
||||
"开启/关闭[功能] ['private'/'group'] [_superuser]",
|
||||
@@ -57,6 +61,8 @@ plugins_status = on_command("功能状态", permission=SUPERUSER, priority=5, bl
|
||||
|
||||
group_task_status = on_command("群被动状态", permission=GROUP, priority=5, block=True)
|
||||
|
||||
group_status = on_regex("^(休息吧|醒来)$", permission=GROUP, priority=5, block=True)
|
||||
|
||||
|
||||
@switch_rule_matcher.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
@@ -105,3 +111,15 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
@group_task_status.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await group_task_status.send(await group_current_status(event.group_id))
|
||||
|
||||
|
||||
@group_status.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
r = re.search("^(休息吧|醒来)$", get_message_text(event.json()))
|
||||
if r:
|
||||
if r.group(1) == "休息吧":
|
||||
msg = set_group_bot_status(event.group_id, False)
|
||||
else:
|
||||
msg = set_group_bot_status(event.group_id, True)
|
||||
await group_status.send(msg)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用总开关命令:{r.group(1)}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
@@ -84,8 +84,8 @@ def _create_help_image():
|
||||
for i, x in enumerate(task_data.keys()):
|
||||
help_str += f'{i+1}.开启/关闭{task_data[x]}\n\n'
|
||||
height = len(help_str.split("\n")) * 33
|
||||
A = CreateImg(width, height, font_size=24)
|
||||
_background = CreateImg(width, height, background=background)
|
||||
A = BuildImage(width, height, font_size=24)
|
||||
_background = BuildImage(width, height, background=background)
|
||||
A.text((150, 110), help_str)
|
||||
A.paste(_background, alpha=True)
|
||||
A.save(admin_help_image)
|
||||
|
||||
@@ -5,8 +5,10 @@ from services.log import logger
|
||||
from models.group_info import GroupInfo
|
||||
from models.friend_user import FriendUser
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from configs.config import NICKNAME
|
||||
from configs.config import NICKNAME, Config
|
||||
from utils.manager import group_manager
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
__zx_plugin_name__ = "定时任务相关 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
@@ -14,7 +16,33 @@ __plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {'zwa': '早晚安'}
|
||||
|
||||
|
||||
x = on_message(priority=9, block=False)
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_ZWA",
|
||||
True,
|
||||
help_="被动 早晚安 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_backup",
|
||||
"BACKUP_FLAG",
|
||||
True,
|
||||
help_="是否开启文件备份",
|
||||
default_value=True
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_backup",
|
||||
"BACKUP_DIR_OR_FILE",
|
||||
['data/black_word', 'data/configs', 'data/statistics', 'data/word_bank', 'data/manager', 'configs'],
|
||||
name="文件备份",
|
||||
help_="备份的文件夹或文件",
|
||||
default_value=[]
|
||||
)
|
||||
|
||||
|
||||
cx = on_message(priority=9, block=False)
|
||||
|
||||
|
||||
# 早上好
|
||||
@@ -106,6 +134,34 @@ async def _():
|
||||
logger.error(f"自动更新群组信息错误 e:{e}")
|
||||
|
||||
|
||||
# 自动备份
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=3,
|
||||
minute=25,
|
||||
)
|
||||
async def _():
|
||||
if Config.get_config("_backup", "BACKUP_FLAG"):
|
||||
_backup_path = Path() / 'backup'
|
||||
_backup_path.mkdir(exist_ok=True, parents=True)
|
||||
for x in Config.get_config("_backup", "BACKUP_DIR_OR_FILE"):
|
||||
try:
|
||||
path = Path(x)
|
||||
_p = _backup_path / x
|
||||
if path.exists():
|
||||
if path.is_dir():
|
||||
if _p.exists():
|
||||
shutil.rmtree(_p, ignore_errors=True)
|
||||
shutil.copytree(x, _p)
|
||||
else:
|
||||
if _p.exists():
|
||||
_p.unlink()
|
||||
shutil.copy(x, _p)
|
||||
logger.info(f'已完成自动备份:{x}')
|
||||
except Exception as e:
|
||||
logger.error(f"自动备份文件 {x} 发生错误 {type(e)}:{e}")
|
||||
|
||||
|
||||
# 一次性任务
|
||||
# 固定时间触发,仅触发一次:
|
||||
#
|
||||
|
||||
@@ -7,6 +7,7 @@ from utils.utils import get_message_text, get_message_imgs
|
||||
from services.log import logger
|
||||
from utils.message_builder import image
|
||||
from utils.manager import group_manager
|
||||
from configs.config import Config
|
||||
|
||||
__zx_plugin_name__ = "广播 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
@@ -20,6 +21,13 @@ __plugin_cmd__ = ["广播-"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {"broadcast": "广播"}
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_BROADCAST",
|
||||
True,
|
||||
help_="被动 广播 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@@ -38,6 +38,22 @@ Config.add_plugin_config(
|
||||
Config.add_plugin_config(
|
||||
"invite_manager", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_GROUP_WELCOME",
|
||||
True,
|
||||
help_="被动 进群欢迎 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_REFUND_GROUP_REMIND",
|
||||
True,
|
||||
help_="被动 退群提醒 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
|
||||
_flmt = FreqLimiter(Config.get_config("invite_manager", "welcome_msg_cd"))
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.manager import (
|
||||
plugins2settings_manager,
|
||||
@@ -50,7 +50,7 @@ def _create_help_img(
|
||||
_des_tmp = {}
|
||||
_plugin_name_tmp = []
|
||||
_tmp = []
|
||||
tmp_img = CreateImg(0, 0, plain_text="1", font_size=24)
|
||||
tmp_img = BuildImage(0, 0, plain_text="1", font_size=24)
|
||||
font_height = tmp_img.h
|
||||
# 插件分类
|
||||
for matcher in _matchers:
|
||||
@@ -181,7 +181,7 @@ def _create_help_img(
|
||||
)
|
||||
height = len(help_str.split("\n")) * (font_height + 5)
|
||||
simple_height = len(simple_help_str.split("\n")) * (font_height + 5)
|
||||
A = CreateImg(
|
||||
A = BuildImage(
|
||||
width + 150, height, font_size=24, color="white" if not ix % 2 else "black"
|
||||
)
|
||||
A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
|
||||
@@ -192,8 +192,8 @@ def _create_help_img(
|
||||
for x in simple_help_str.split("\n")
|
||||
]:
|
||||
simple_width = simple_width if simple_width > x else x
|
||||
bk = CreateImg(simple_width + 20, simple_height, font_size=24, color="#6495ED")
|
||||
B = CreateImg(
|
||||
bk = BuildImage(simple_width + 20, simple_height, font_size=24, color="#6495ED")
|
||||
B = BuildImage(
|
||||
simple_width + 20,
|
||||
simple_height,
|
||||
font_size=24,
|
||||
@@ -236,7 +236,7 @@ def _create_help_img(
|
||||
for img in help_img_list:
|
||||
height += img.h
|
||||
if not group_id:
|
||||
A = CreateImg(width + 150, height + 50, font_size=24)
|
||||
A = BuildImage(width + 150, height + 50, font_size=24)
|
||||
A.text(
|
||||
(10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n'
|
||||
)
|
||||
@@ -253,14 +253,14 @@ def _create_help_img(
|
||||
if img.h > height:
|
||||
height = img.h
|
||||
width += img.w + 10
|
||||
B = CreateImg(width + 100, height + 250, font_size=24)
|
||||
B = BuildImage(width + 100, height + 250, font_size=24)
|
||||
width, _ = get_max_width_or_paste(simple_help_img_list, B)
|
||||
bk = None
|
||||
random_bk = os.listdir(random_bk_path)
|
||||
if random_bk:
|
||||
bk = random.choice(random_bk)
|
||||
x = max(width + 50, height + 250)
|
||||
B = CreateImg(
|
||||
B = BuildImage(
|
||||
x,
|
||||
x,
|
||||
font_size=24,
|
||||
@@ -272,7 +272,7 @@ def _create_help_img(
|
||||
w = 10
|
||||
h = 10
|
||||
for msg in ["目前支持的功能列表:", "可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法", "或者使用 ‘详细帮助’ 来获取所有功能方法"]:
|
||||
text = CreateImg(
|
||||
text = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=msg,
|
||||
@@ -284,7 +284,7 @@ def _create_help_img(
|
||||
if msg == "目前支持的功能列表:":
|
||||
w += 50
|
||||
B.paste(
|
||||
CreateImg(
|
||||
BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护",
|
||||
@@ -299,8 +299,8 @@ def _create_help_img(
|
||||
|
||||
|
||||
def get_max_width_or_paste(
|
||||
simple_help_img_list: list, B: CreateImg = None, is_paste: bool = False
|
||||
) -> "int, CreateImg":
|
||||
simple_help_img_list: list, B: BuildImage = None, is_paste: bool = False
|
||||
) -> "int, BuildImage":
|
||||
"""
|
||||
获取最大宽度,或直接贴图
|
||||
:param simple_help_img_list: 简单帮助图片列表
|
||||
@@ -353,8 +353,8 @@ def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
|
||||
_width = len(x) * 24
|
||||
width = width if width > _width else _width
|
||||
height = len(result.split("\n")) * 45
|
||||
A = CreateImg(width, height, font_size=24)
|
||||
bk = CreateImg(
|
||||
A = BuildImage(width, height, font_size=24)
|
||||
bk = BuildImage(
|
||||
width,
|
||||
height,
|
||||
background=Path(IMAGE_PATH) / "background" / "1.png",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from configs.config import Config
|
||||
import nonebot
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
@@ -35,4 +34,3 @@ Config.add_plugin_config(
|
||||
default_value=6
|
||||
)
|
||||
|
||||
nonebot.load_plugins("basic_plugins/hooks")
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from 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
|
||||
from nonebot.typing import T_State
|
||||
from typing import Optional
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
PokeNotifyEvent,
|
||||
PrivateMessageEvent,
|
||||
Message,
|
||||
Event
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
@@ -22,13 +32,11 @@ from utils.message_builder import at
|
||||
from models.level_user import LevelUser
|
||||
import nonebot
|
||||
|
||||
|
||||
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
|
||||
|
||||
ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
|
||||
|
||||
@@ -37,42 +45,66 @@ ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
module = matcher.module
|
||||
plugins2info_dict = plugins2settings_manager.get_data()
|
||||
if (
|
||||
(not isinstance(event, MessageEvent) and module != "poke")
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
) or (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
return
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
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 != "poke")
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
) or (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
# 超级用户命令
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(module)
|
||||
_module = _plugin.module
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if (
|
||||
"[superuser]" in plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
"[superuser]" in plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
# 群黑名单检测
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if group_manager.get_group_level(event.group_id) < 0:
|
||||
raise IgnoredException("群黑名单")
|
||||
# 群黑名单检测 群总开关检测
|
||||
if isinstance(event, GroupMessageEvent) or matcher.module == "poke":
|
||||
try:
|
||||
if group_manager.get_group_level(event.group_id) < 0:
|
||||
raise IgnoredException("群黑名单")
|
||||
if not group_manager.check_group_bot_status(event.group_id):
|
||||
try:
|
||||
if str(event.get_message()) != "醒来":
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except ValueError:
|
||||
raise IgnoredException("功能总开关关闭状态")
|
||||
except AttributeError:
|
||||
pass
|
||||
if module in admin_manager.keys() and matcher.priority not in [1, 9]:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
# 个人权限
|
||||
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
|
||||
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):
|
||||
@@ -80,7 +112,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
|
||||
f"{admin_manager.get_plugin_level(module)}",
|
||||
f"{admin_manager.get_plugin_level(module)}",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
@@ -90,7 +122,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
raise IgnoredException("权限不足")
|
||||
else:
|
||||
if not await LevelUser.check_level(
|
||||
event.user_id, 0, admin_manager.get_plugin_level(module)
|
||||
event.user_id, 0, admin_manager.get_plugin_level(module)
|
||||
):
|
||||
try:
|
||||
await bot.send_private_msg(
|
||||
@@ -106,12 +138,12 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
|
||||
# 戳一戳单独判断
|
||||
if isinstance(event, GroupMessageEvent) or (
|
||||
isinstance(event, PokeNotifyEvent) and event.group_id
|
||||
isinstance(event, PokeNotifyEvent) and event.group_id
|
||||
):
|
||||
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
|
||||
event.group_id
|
||||
):
|
||||
try:
|
||||
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
|
||||
@@ -129,7 +161,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
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
|
||||
event.group_id
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@@ -145,8 +177,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
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.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@@ -162,8 +194,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
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.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@@ -193,14 +225,14 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
# 维护
|
||||
if not plugins_manager.get_plugin_status(module, block_type="all"):
|
||||
if isinstance(
|
||||
event, GroupMessageEvent
|
||||
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.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@@ -221,3 +253,154 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
status_message_manager.add(id_)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("此功能正在维护...")
|
||||
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
|
||||
# Cd
|
||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||
check_type = plugin_cd_data["check_type"]
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(module, cd_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(module, cd_type_)
|
||||
module = matcher.module
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
and status_message_manager.get(event.group_id) is None
|
||||
):
|
||||
status_message_manager.delete(event.group_id)
|
||||
# Cd
|
||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||
check_type = plugin_cd_data["check_type"]
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(module, cd_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(module, cd_type_)
|
||||
# Block
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
rst = plugin_block_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or check_type == "all"
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
if plugins2block_manager.check(block_type_, module):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{event.user_id}正在调用{module}....")
|
||||
else:
|
||||
plugins2block_manager.set_true(block_type_, module)
|
||||
# Count
|
||||
if (
|
||||
plugins2count_manager.check_plugin_count_status(module)
|
||||
and event.user_id not in bot.config.superusers
|
||||
):
|
||||
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
|
||||
limit_type = plugin_count_data["limit_type"]
|
||||
rst = plugin_count_data["rst"]
|
||||
count_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
count_type_ = event.group_id
|
||||
if not plugins2count_manager.check(module, count_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} count次数限制...")
|
||||
else:
|
||||
plugins2count_manager.increase(module, count_type_)
|
||||
# 功能花费的金币 #######################################
|
||||
# 功能花费的金币 #######################################
|
||||
if cost_gold:
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
|
||||
|
||||
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
发送信息
|
||||
:param rst: pass
|
||||
:param bot: pass
|
||||
:param event: pass
|
||||
"""
|
||||
rst = await init_rst(rst, event)
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
status_message_manager.add(event.group_id)
|
||||
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
|
||||
else:
|
||||
status_message_manager.add(event.user_id)
|
||||
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
|
||||
except ActionFailed:
|
||||
pass
|
||||
|
||||
|
||||
# 解除命令block阻塞
|
||||
@run_postprocessor
|
||||
async def _(
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception],
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
):
|
||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
||||
return
|
||||
module = matcher.module
|
||||
set_block_limit_false(event, module)
|
||||
|
||||
|
||||
async def init_rst(rst: str, event: MessageEvent):
|
||||
if "[uname]" in rst:
|
||||
uname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
rst = rst.replace("[uname]", uname)
|
||||
if "[nickname]" in rst:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
else:
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
rst = rst.replace("[nickname]", nickname)
|
||||
if "[at]" in rst and isinstance(event, GroupMessageEvent):
|
||||
rst = rst.replace("[at]", str(at(event.user_id)))
|
||||
return rst
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from nonebot.adapters.cqhttp import (
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
from utils.utils import is_number, static_flmt
|
||||
from utils.utils import is_number, static_flmt, FreqLimiter
|
||||
from utils.message_builder import at
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ Config.add_plugin_config(
|
||||
help_="对被ban用户发送的消息",
|
||||
)
|
||||
|
||||
_flmt = FreqLimiter(300)
|
||||
|
||||
|
||||
# 检查是否被ban
|
||||
@run_preprocessor
|
||||
@@ -55,7 +57,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if matcher.priority != 9:
|
||||
try:
|
||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||
if ban_result:
|
||||
if ban_result and _flmt.check(event.user_id):
|
||||
_flmt.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=at(event.user_id)
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from utils.message_builder import at
|
||||
from .utils import status_message_manager, set_block_limit_false
|
||||
from utils.manager import (
|
||||
plugins2cd_manager,
|
||||
plugins2block_manager,
|
||||
plugins2count_manager,
|
||||
)
|
||||
from typing import Optional
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
Event,
|
||||
MessageEvent,
|
||||
PrivateMessageEvent,
|
||||
GroupMessageEvent,
|
||||
Message,
|
||||
)
|
||||
|
||||
|
||||
# 命令cd | 命令阻塞 | 命令次数
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
||||
return
|
||||
module = matcher.module
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
and status_message_manager.get(event.group_id) is None
|
||||
):
|
||||
status_message_manager.delete(event.group_id)
|
||||
# Count
|
||||
if (
|
||||
plugins2count_manager.check_plugin_count_status(module)
|
||||
and event.user_id not in bot.config.superusers
|
||||
):
|
||||
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
|
||||
limit_type = plugin_count_data["limit_type"]
|
||||
rst = plugin_count_data["rst"]
|
||||
count_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
count_type_ = event.group_id
|
||||
if not plugins2count_manager.check(module, count_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} count次数限制...")
|
||||
else:
|
||||
plugins2count_manager.increase(module, count_type_)
|
||||
# Cd
|
||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||
check_type = plugin_cd_data["check_type"]
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(module, cd_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(module, cd_type_)
|
||||
# Block
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
rst = plugin_block_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or check_type == "all"
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
if plugins2block_manager.check(block_type_, module):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{event.user_id}正在调用{module}....")
|
||||
else:
|
||||
plugins2block_manager.set_true(block_type_, module)
|
||||
|
||||
|
||||
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
发送信息
|
||||
:param rst: pass
|
||||
:param bot: pass
|
||||
:param event: pass
|
||||
"""
|
||||
rst = await init_rst(rst, event)
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
status_message_manager.add(event.group_id)
|
||||
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
|
||||
else:
|
||||
status_message_manager.add(event.user_id)
|
||||
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
|
||||
except ActionFailed:
|
||||
pass
|
||||
|
||||
|
||||
# 解除命令block阻塞
|
||||
@run_postprocessor
|
||||
async def _(
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception],
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
):
|
||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
||||
return
|
||||
module = matcher.module
|
||||
set_block_limit_false(event, module)
|
||||
|
||||
|
||||
async def init_rst(rst: str, event: MessageEvent):
|
||||
if "[uname]" in rst:
|
||||
uname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
rst = rst.replace("[uname]", uname)
|
||||
if "[nickname]" in rst:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
else:
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
rst = rst.replace("[nickname]", nickname)
|
||||
if "[at]" in rst and isinstance(event, GroupMessageEvent):
|
||||
rst = rst.replace("[at]", str(at(event.user_id)))
|
||||
return rst
|
||||
@@ -71,6 +71,8 @@ def init_plugins_settings(data_path: str):
|
||||
plugin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
if plugin_settings.get('cost_gold') is None:
|
||||
plugin_settings['cost_gold'] = 0
|
||||
if (
|
||||
plugin_settings["cmd"] is not None
|
||||
and plugin_name not in plugin_settings["cmd"]
|
||||
@@ -97,7 +99,7 @@ def init_plugins_settings(data_path: str):
|
||||
plugins2settings_manager.add_plugin_settings(
|
||||
matcher.module,
|
||||
plugin_type=plugin_type,
|
||||
data_dict=plugin_settings,
|
||||
**plugin_settings,
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@@ -25,7 +25,7 @@ __plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_configs__ = {
|
||||
"BLACK_WORD": {
|
||||
"value": ["爸", "妈", "爹", "爷"],
|
||||
"value": ["爸", "爹", "爷"],
|
||||
"help": "昵称所屏蔽的关键词,会被替换为 *",
|
||||
"default_value": None
|
||||
}
|
||||
|
||||
+34
-22
@@ -7,6 +7,7 @@ from services.log import logger
|
||||
from configs.path_config import TEXT_PATH
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.utils import scheduler
|
||||
from pathlib import Path
|
||||
import nonebot
|
||||
|
||||
@@ -27,31 +28,32 @@ async def update_city():
|
||||
"""
|
||||
china_city = Path(TEXT_PATH) / "china_city.json"
|
||||
data = {}
|
||||
try:
|
||||
res = await AsyncHttpx.get(
|
||||
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
provinces_data = json.loads(res.text)
|
||||
for province in provinces_data.keys():
|
||||
data[provinces_data[province]] = []
|
||||
if not china_city.exists():
|
||||
try:
|
||||
res = await AsyncHttpx.get(
|
||||
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
|
||||
timeout=5,
|
||||
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
city_data = json.loads(res.text)
|
||||
for city in city_data.keys():
|
||||
data[provinces_data[province]].append(city_data[city])
|
||||
with open(china_city, "w", encoding="utf8") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
logger.info("自动更新城市列表完成.....")
|
||||
except TimeoutError:
|
||||
logger.warning("自动更新城市列表超时.....")
|
||||
except ValueError:
|
||||
logger.warning("自动城市列表失败.....")
|
||||
except Exception as e:
|
||||
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
|
||||
provinces_data = json.loads(res.text)
|
||||
for province in provinces_data.keys():
|
||||
data[provinces_data[province]] = []
|
||||
res = await AsyncHttpx.get(
|
||||
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
|
||||
timeout=5,
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
city_data = json.loads(res.text)
|
||||
for city in city_data.keys():
|
||||
data[provinces_data[province]].append(city_data[city])
|
||||
with open(china_city, "w", encoding="utf8") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
logger.info("自动更新城市列表完成.....")
|
||||
except TimeoutError:
|
||||
logger.warning("自动更新城市列表超时.....")
|
||||
except ValueError:
|
||||
logger.warning("自动城市列表失败.....")
|
||||
except Exception as e:
|
||||
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
@@ -101,3 +103,13 @@ async def _(bot: Bot):
|
||||
else:
|
||||
await GroupInfo.delete_group_info(group_id)
|
||||
logger.info(f"移除不存在的群聊信息:{group_id}")
|
||||
|
||||
|
||||
# 自动更新城市列表
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=6,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
await update_city()
|
||||
|
||||
Executable → Regular
+1
-1
@@ -11,4 +11,4 @@ Config.add_plugin_config(
|
||||
)
|
||||
|
||||
|
||||
nonebot.load_plugins("plugins/shop")
|
||||
nonebot.load_plugins("basic_plugins/shop")
|
||||
Executable → Regular
+86
-89
@@ -1,89 +1,86 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import get_message_text, is_number
|
||||
from models.bag_user import BagUser
|
||||
from services.db_context import db
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from .models.goods_info import GoodsInfo
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 购买道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
购买道具
|
||||
指令:
|
||||
购买 [序号或名称] ?[数量=1]
|
||||
示例:购买 好感双倍加持卡Ⅰ
|
||||
示例:购买 1 4
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 购买道具"
|
||||
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "购买道具"],
|
||||
}
|
||||
|
||||
|
||||
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@buy.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if get_message_text(event.json()) in ["神秘药水"]:
|
||||
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
goods_name_lst = [x.goods_name for x in goods_lst]
|
||||
msg = get_message_text(event.json()).strip().split(" ")
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
if is_number(msg[1]) and int(msg[1]) > 0:
|
||||
num = int(msg[1])
|
||||
else:
|
||||
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
|
||||
# print(msg, num)
|
||||
if is_number(msg[0]):
|
||||
msg = int(msg[0])
|
||||
if msg > len(goods_lst) or msg < 1:
|
||||
await buy.finish("请输入正确的商品id!", at_sender=True)
|
||||
goods = goods_lst[msg - 1]
|
||||
else:
|
||||
if msg[0] in goods_name_lst:
|
||||
for i in range(len(goods_name_lst)):
|
||||
if msg[0] == goods_name_lst[i]:
|
||||
goods = goods_lst[i]
|
||||
break
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!")
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!", at_sender=True)
|
||||
async with db.transaction():
|
||||
if (
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
if await BagUser.spend_gold(
|
||||
event.user_id, event.group_id, goods.goods_price * num
|
||||
):
|
||||
for _ in range(num):
|
||||
await BagUser.add_props(event.user_id, event.group_id, goods.goods_name)
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||
)
|
||||
else:
|
||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 失败!"
|
||||
)
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import get_message_text, is_number
|
||||
from models.bag_user import BagUser
|
||||
from services.db_context import db
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from models.goods_info import GoodsInfo
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 购买道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
购买道具
|
||||
指令:
|
||||
购买 [序号或名称] ?[数量=1]
|
||||
示例:购买 好感双倍加持卡Ⅰ
|
||||
示例:购买 1 4
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 购买道具"
|
||||
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "购买道具"],
|
||||
}
|
||||
|
||||
|
||||
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@buy.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
goods = None
|
||||
if get_message_text(event.json()) in ["神秘药水"]:
|
||||
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
goods_name_lst = [x.goods_name for x in goods_lst]
|
||||
msg = get_message_text(event.json()).split()
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
if is_number(msg[1]) and int(msg[1]) > 0:
|
||||
num = int(msg[1])
|
||||
else:
|
||||
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
|
||||
# print(msg, num)
|
||||
if is_number(msg[0]):
|
||||
msg = int(msg[0])
|
||||
if msg > len(goods_lst) or msg < 1:
|
||||
await buy.finish("请输入正确的商品id!", at_sender=True)
|
||||
goods = goods_lst[msg - 1]
|
||||
else:
|
||||
if msg[0] in goods_name_lst:
|
||||
for i in range(len(goods_name_lst)):
|
||||
if msg[0] == goods_name_lst[i]:
|
||||
goods = goods_lst[i]
|
||||
break
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!")
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!", at_sender=True)
|
||||
async with db.transaction():
|
||||
if (
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num * goods.goods_discount:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
if await BagUser.buy_props(event.user_id, event.group_id, goods, num):
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||
)
|
||||
else:
|
||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 失败!"
|
||||
)
|
||||
Executable → Regular
Executable → Regular
+52
-52
@@ -1,52 +1,52 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
我的道具
|
||||
指令:
|
||||
我的道具
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 我的道具"
|
||||
__plugin_cmd__ = ["我的道具"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "我的道具"],
|
||||
}
|
||||
|
||||
|
||||
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
pname_list = []
|
||||
pnum_list = []
|
||||
rst = ""
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p in pname_list:
|
||||
pnum_list[pname_list.index(p)] += 1
|
||||
else:
|
||||
pname_list.append(p)
|
||||
pnum_list.append(1)
|
||||
for i in range(len(pname_list)):
|
||||
rst += f"{i+1}.{pname_list[i]}\t×{pnum_list[i]}\n"
|
||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||
else:
|
||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
我的道具
|
||||
指令:
|
||||
我的道具
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 我的道具"
|
||||
__plugin_cmd__ = ["我的道具"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "我的道具"],
|
||||
}
|
||||
|
||||
|
||||
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
pname_list = []
|
||||
pnum_list = []
|
||||
rst = ""
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p in pname_list:
|
||||
pnum_list[pname_list.index(p)] += 1
|
||||
else:
|
||||
pname_list.append(p)
|
||||
pnum_list.append(1)
|
||||
for i in range(len(pname_list)):
|
||||
rst += f"{i+1}.{pname_list[i]}\t×{pnum_list[i]}\n"
|
||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||
else:
|
||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
Executable → Regular
+26
-26
@@ -1,26 +1,26 @@
|
||||
from utils.utils import scheduler
|
||||
from models.bag_user import BagUser
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "每日金币重置 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
# 重置每日金币
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=0,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
user_list = await BagUser.get_all_users()
|
||||
for user in user_list:
|
||||
await user.update(
|
||||
get_today_gold=0,
|
||||
spend_today_gold=0,
|
||||
).apply()
|
||||
except Exception as e:
|
||||
logger.error(f"重置每日金币错误 e:{e}")
|
||||
from utils.utils import scheduler
|
||||
from models.bag_user import BagUser
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "每日金币重置 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
# 重置每日金币
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=0,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
user_list = await BagUser.get_all_users()
|
||||
for user in user_list:
|
||||
await user.update(
|
||||
get_today_gold=0,
|
||||
spend_today_gold=0,
|
||||
).apply()
|
||||
except Exception as e:
|
||||
logger.error(f"重置每日金币错误 e:{e}")
|
||||
@@ -0,0 +1,133 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_shop_help, delete_goods, update_goods, registered_goods, parse_goods_info
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import get_message_text, is_number
|
||||
from nonebot.plugin import export
|
||||
from services.log import logger
|
||||
import os
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
商店项目,这可不是奸商
|
||||
指令:
|
||||
商店
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
usage:
|
||||
商品操作
|
||||
指令:
|
||||
添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)
|
||||
删除商品 [名称或序号]
|
||||
修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时]
|
||||
示例:添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
|
||||
示例:添加商品 name:可疑的药 price:5 des:效果未知
|
||||
示例:删除商品 2
|
||||
示例:修改商品 name:1 price:900 修改序号为1的商品的价格为900
|
||||
* 修改商品只需添加需要值即可 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店系统[金币回收计划]"
|
||||
__plugin_cmd__ = [
|
||||
"商店",
|
||||
"添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)) [_superuser]",
|
||||
"删除商品 [名称或序号] [_superuser]",
|
||||
"修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时] [_superuser]",
|
||||
]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店"],
|
||||
}
|
||||
__plugin_block_limit__ = {
|
||||
"limit_type": "group"
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.registered_goods = registered_goods
|
||||
export.delete_goods = delete_goods
|
||||
export.update_goods = update_goods
|
||||
|
||||
shop_help = on_command("商店", priority=5, block=True)
|
||||
|
||||
shop_add_goods = on_command("添加商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
shop_del_goods = on_command("删除商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@shop_help.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await shop_help.send(image(b64=await create_shop_help()))
|
||||
|
||||
|
||||
@shop_add_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
data = parse_goods_info(msg)
|
||||
if isinstance(data, str):
|
||||
await shop_add_goods.finish(data)
|
||||
if not data.get("name") or not data.get("price") or not data.get("des"):
|
||||
await shop_add_goods.finish("name:price:des 参数不可缺少!")
|
||||
if await registered_goods(**data):
|
||||
await shop_add_goods.send(f"添加商品 {data['name']} 成功!\n"
|
||||
f"名称:{data['name']}\n"
|
||||
f"价格:{data['price']}金币\n"
|
||||
f"简介:{data['des']}\n"
|
||||
f"折扣:{data.get('discount')}\n"
|
||||
f"限时:{data.get('limit_time')}", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 添加商品 {msg} 成功")
|
||||
else:
|
||||
await shop_add_goods.send(f"添加商品 {msg} 失败了...", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} 添加商品 {msg} 失败")
|
||||
|
||||
|
||||
@shop_del_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
name = ""
|
||||
id_ = 0
|
||||
if is_number(msg):
|
||||
id_ = int(msg)
|
||||
else:
|
||||
name = msg
|
||||
rst, goods_name, code = await delete_goods(name, id_)
|
||||
if code == 200:
|
||||
await shop_del_goods.send(f"删除商品 {goods_name} 成功了...", at_sender=True)
|
||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 成功")
|
||||
else:
|
||||
await shop_del_goods.send(f"删除商品 {goods_name} 失败了...", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 失败")
|
||||
|
||||
|
||||
@shop_update_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
data = parse_goods_info(msg)
|
||||
if isinstance(data, str):
|
||||
await shop_add_goods.finish(data)
|
||||
if not data.get("name"):
|
||||
await shop_add_goods.finish("name 参数不可缺少!")
|
||||
flag, name, text = await update_goods(**data)
|
||||
if flag:
|
||||
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功")
|
||||
else:
|
||||
await shop_update_goods.send(f"修改商品 {name} 失败了...", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败")
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
from models.goods_info import GoodsInfo
|
||||
from utils.image_utils import BuildImage
|
||||
from models.sign_group_user import SignGroupUser
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional, Union
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
from nonebot.plugin import require
|
||||
import nonebot
|
||||
import time
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
use = require("use")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def init_default_shop_goods():
|
||||
"""
|
||||
导入内置的三个商品
|
||||
"""
|
||||
|
||||
async def sign_card_1(**kwargs):
|
||||
user_id = kwargs['user_id']
|
||||
group_id = kwargs['group_id']
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.1).apply()
|
||||
|
||||
async def sign_card_2(**kwargs):
|
||||
user_id = kwargs['user_id']
|
||||
group_id = kwargs['group_id']
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.2).apply()
|
||||
|
||||
async def sign_card_3(**kwargs):
|
||||
user_id = kwargs['user_id']
|
||||
group_id = kwargs['group_id']
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.3).apply()
|
||||
|
||||
if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
|
||||
await registered_goods(
|
||||
"好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"
|
||||
)
|
||||
use.registered_use("好感度双倍加持卡Ⅰ", sign_card_1)
|
||||
await registered_goods("好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)")
|
||||
use.registered_use("好感度双倍加持卡Ⅱ", sign_card_2)
|
||||
await registered_goods(
|
||||
"好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"
|
||||
)
|
||||
use.registered_use("好感度双倍加持卡Ⅲ", sign_card_3)
|
||||
|
||||
|
||||
# 创建商店界面
|
||||
async def create_shop_help() -> str:
|
||||
"""
|
||||
制作商店图片
|
||||
:return: 图片base64
|
||||
"""
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
idx = 1
|
||||
_dc = {}
|
||||
font_h = BuildImage(0, 0).getsize("正")[1]
|
||||
h = 10
|
||||
_list = []
|
||||
for goods in goods_lst:
|
||||
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time:
|
||||
h += len(goods.goods_description.strip().split("\n")) * font_h + 80
|
||||
_list.append(goods)
|
||||
A = BuildImage(1000, h, color="#f9f6f2")
|
||||
current_h = 0
|
||||
for goods in _list:
|
||||
bk = BuildImage(
|
||||
700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
goods_image = BuildImage(
|
||||
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
name_image = BuildImage(
|
||||
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
await name_image.atext(
|
||||
(15, 0), f"{idx}.{goods.goods_name}", center_type="by_height"
|
||||
)
|
||||
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
|
||||
await name_image.atext((390, 0), "售价:", center_type="by_height")
|
||||
await name_image.atext(
|
||||
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
|
||||
)
|
||||
await name_image.atext(
|
||||
(
|
||||
440
|
||||
+ BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w,
|
||||
0,
|
||||
),
|
||||
" 金币",
|
||||
center_type="by_height",
|
||||
)
|
||||
await name_image.acircle_corner(5)
|
||||
await goods_image.apaste(name_image, (0, 5), True, center_type="by_width")
|
||||
await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
|
||||
await goods_image.acircle_corner(20)
|
||||
await bk.apaste(goods_image, alpha=True)
|
||||
# 添加限时图标和时间
|
||||
if goods.goods_limit_time > 0:
|
||||
_limit_time_logo = BuildImage(40, 40, background=f"{IMAGE_PATH}/other/time.png")
|
||||
await bk.apaste(_limit_time_logo, (600, 0), True)
|
||||
await bk.apaste(BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"), (640, 10), True)
|
||||
limit_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)).split()
|
||||
y_m_d = limit_time[0]
|
||||
_h_m = limit_time[1].split(":")
|
||||
h_m = _h_m[0] + "时 " + _h_m[1] + "分"
|
||||
await bk.atext((605, 38), str(y_m_d))
|
||||
await bk.atext((615, 57), str(h_m))
|
||||
await bk.aline((550, -1, 710, -1), "#a29ad6", 5)
|
||||
await bk.aline((550, 80, 710, 80), "#a29ad6", 5)
|
||||
idx += 1
|
||||
await A.apaste(bk, (0, current_h), True)
|
||||
current_h += 90
|
||||
w = 1000
|
||||
h = A.h + 230 + 100
|
||||
h = 1000 if h < 1000 else h
|
||||
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
|
||||
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
|
||||
shop.paste(A, (20, 230))
|
||||
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan.png")
|
||||
zx_img.replace_color_tran(((240, 240, 240), (255, 255, 255)), (249, 246, 242))
|
||||
await shop.apaste(zx_img, (780, 100))
|
||||
await shop.apaste(shop_logo, (450, 30), True)
|
||||
shop.text(
|
||||
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
|
||||
"注【通过 序号 或者 商品名称 购买】",
|
||||
)
|
||||
shop.text((20, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
|
||||
return shop.pic2bs4()
|
||||
|
||||
|
||||
async def registered_goods(
|
||||
name: str,
|
||||
price: int,
|
||||
des: str,
|
||||
discount: Optional[float] = 1,
|
||||
limit_time: Optional[int] = 0,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
添加商品
|
||||
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
|
||||
添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
|
||||
添加商品 name:可疑的药 price:5 des:效果未知
|
||||
:param name: 商品名称
|
||||
:param price: 商品价格
|
||||
:param des: 商品简介
|
||||
:param discount: 商品折扣
|
||||
:param limit_time: 商品限时销售时间,单位为小时
|
||||
:param kwargs: kwargs
|
||||
:return: 是否添加成功
|
||||
"""
|
||||
if kwargs:
|
||||
name = kwargs.get("name")
|
||||
price = kwargs.get("price")
|
||||
des = kwargs.get("des")
|
||||
discount = kwargs.get("discount")
|
||||
limit_time = kwargs.get("time_limit")
|
||||
limit_time = float(limit_time) if limit_time else limit_time
|
||||
discount = discount if discount is None else 1
|
||||
limit_time = int(time.time() + limit_time * 60 * 60) if limit_time is not None and limit_time != 0 else 0
|
||||
return await GoodsInfo.add_goods(
|
||||
name, int(price), des, float(discount), limit_time
|
||||
)
|
||||
|
||||
|
||||
# 删除商品
|
||||
async def delete_goods(name: str, id_: int) -> "str, str, int":
|
||||
"""
|
||||
删除商品
|
||||
:param name: 商品名称
|
||||
:param id_: 商品id
|
||||
:return: 删除状况
|
||||
"""
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
if id_:
|
||||
if id_ < 1 or id_ > len(goods_lst):
|
||||
return "序号错误,没有该序号商品...", "", 999
|
||||
goods_name = goods_lst[id_ - 1].goods_name
|
||||
if await GoodsInfo.delete_goods(goods_name):
|
||||
return f"删除商品 {goods_name} 成功!", goods_name, 200
|
||||
else:
|
||||
return f"删除商品 {goods_name} 失败!", goods_name, 999
|
||||
if name:
|
||||
if await GoodsInfo.delete_goods(name):
|
||||
return f"删除商品 {name} 成功!", name, 200
|
||||
else:
|
||||
return f"删除商品 {name} 失败!", name, 999
|
||||
|
||||
|
||||
# 更新商品信息
|
||||
async def update_goods(**kwargs) -> "str, str, int":
|
||||
"""
|
||||
更新商品信息
|
||||
:param kwargs: kwargs
|
||||
:return: 更新状况
|
||||
"""
|
||||
if kwargs:
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
if is_number(kwargs["name"]):
|
||||
if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst):
|
||||
return "序号错误,没有该序号的商品...", "", 999
|
||||
goods = goods_lst[int(kwargs["name"]) - 1]
|
||||
else:
|
||||
goods = await GoodsInfo.get_goods_info(kwargs["name"])
|
||||
if not goods:
|
||||
return "名称错误,没有该名称的商品...", "", 999
|
||||
name = goods.goods_name
|
||||
price = goods.goods_price
|
||||
des = goods.goods_description
|
||||
discount = goods.goods_discount
|
||||
limit_time = goods.goods_limit_time
|
||||
new_time = 0
|
||||
tmp = ""
|
||||
if kwargs.get("price"):
|
||||
tmp += f'价格:{price} --> {kwargs["price"]}\n'
|
||||
price = kwargs["price"]
|
||||
if kwargs.get("des"):
|
||||
tmp += f'描述:{des} --> {kwargs["des"]}\n'
|
||||
des = kwargs["des"]
|
||||
if kwargs.get("discount"):
|
||||
tmp += f'折扣:{discount} --> {kwargs["discount"]}\n'
|
||||
discount = kwargs["discount"]
|
||||
if kwargs.get("limit_time"):
|
||||
new_time = time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
time.localtime(time.time() + int(kwargs["limit_time"] * 60 * 60)),
|
||||
)
|
||||
tmp += f"折扣至: {new_time}\n"
|
||||
limit_time = kwargs["limit_time"]
|
||||
return (
|
||||
await GoodsInfo.update_goods(
|
||||
name,
|
||||
int(price),
|
||||
des,
|
||||
float(discount),
|
||||
int(time.time() + limit_time * 60 * 60 if limit_time != 0 and new_time else 0),
|
||||
),
|
||||
name,
|
||||
tmp[:-1],
|
||||
)
|
||||
|
||||
|
||||
def parse_goods_info(msg: str) -> Union[dict, str]:
|
||||
"""
|
||||
解析格式数据
|
||||
:param msg: 消息
|
||||
:return: 解析完毕的数据data
|
||||
"""
|
||||
if "name:" not in msg:
|
||||
return "必须指定修改的商品名称或序号!"
|
||||
data = {}
|
||||
for x in msg.split():
|
||||
sp = x.split(":", maxsplit=1)
|
||||
if str(sp[1]).strip():
|
||||
sp[1] = sp[1].strip()
|
||||
print(sp)
|
||||
if sp[0] == "name":
|
||||
data["name"] = sp[1]
|
||||
elif sp[0] == "price":
|
||||
if not is_number(sp[1]) or int(sp[1]) < 0:
|
||||
return "price参数不合法,必须大于等于0!"
|
||||
data["price"] = sp[1]
|
||||
elif sp[0] == "des":
|
||||
data["des"] = sp[1]
|
||||
elif sp[0] == "discount":
|
||||
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||
return "discount参数不合法,必须大于0!"
|
||||
data["discount"] = sp[1]
|
||||
elif sp[0] == "limit_time":
|
||||
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||
return "limit_time参数不合法,必须大于0!"
|
||||
data["limit_time"] = sp[1]
|
||||
return data
|
||||
Executable → Regular
+76
-71
@@ -1,71 +1,76 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import is_number, get_message_text
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from services.db_context import db
|
||||
from .data_source import effect
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 使用道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
普通的使用道具
|
||||
指令:
|
||||
使用道具 [序号或道具名称]
|
||||
* 序号以 ”我的道具“ 为准 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 使用道具"
|
||||
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "使用道具"],
|
||||
}
|
||||
|
||||
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@use_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg in ["", "帮助"]:
|
||||
await use_props.finish(__plugin_usage__)
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
async with db.transaction():
|
||||
pname_list = []
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p not in pname_list:
|
||||
pname_list.append(p)
|
||||
if is_number(msg):
|
||||
if 0 < int(msg) <= len(pname_list):
|
||||
name = pname_list[int(msg) - 1]
|
||||
else:
|
||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||
else:
|
||||
if msg not in pname_list:
|
||||
await use_props.finish("道具名称错误!", at_sender=True)
|
||||
name = msg
|
||||
if await BagUser.del_props(
|
||||
event.user_id, event.group_id, name
|
||||
) and await effect(event.user_id, event.group_id, name):
|
||||
await use_props.send(f"使用道具 {name} 成功!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 成功"
|
||||
)
|
||||
else:
|
||||
await use_props.send(f"使用道具 {name} 失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 失败"
|
||||
)
|
||||
else:
|
||||
await use_props.send("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import is_number, get_message_text
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from services.db_context import db
|
||||
from nonebot.plugin import export
|
||||
from .data_source import effect, registered_use
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 使用道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
普通的使用道具
|
||||
指令:
|
||||
使用道具 [序号或道具名称]
|
||||
* 序号以 ”我的道具“ 为准 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 使用道具"
|
||||
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "使用道具"],
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.registered_use = registered_use
|
||||
|
||||
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@use_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg in ["", "帮助"]:
|
||||
await use_props.finish(__plugin_usage__)
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
async with db.transaction():
|
||||
pname_list = []
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p not in pname_list:
|
||||
pname_list.append(p)
|
||||
if is_number(msg):
|
||||
if 0 < int(msg) <= len(pname_list):
|
||||
name = pname_list[int(msg) - 1]
|
||||
else:
|
||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||
else:
|
||||
if msg not in pname_list:
|
||||
await use_props.finish("道具名称错误!", at_sender=True)
|
||||
name = msg
|
||||
if await BagUser.del_props(
|
||||
event.user_id, event.group_id, name
|
||||
) and await effect(event.user_id, event.group_id, name):
|
||||
await use_props.send(f"使用道具 {name} 成功!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 成功"
|
||||
)
|
||||
else:
|
||||
await use_props.send(f"使用道具 {name} 失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 失败"
|
||||
)
|
||||
else:
|
||||
await use_props.send("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
@@ -0,0 +1,45 @@
|
||||
import asyncio
|
||||
from services.log import logger
|
||||
|
||||
_use_func_data = {}
|
||||
|
||||
|
||||
async def effect(user_id: int, group_id: int, goods_name: str) -> bool:
|
||||
"""
|
||||
商品生效
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param goods_name: 商品名称
|
||||
:return: 使用是否成功
|
||||
"""
|
||||
# 优先使用注册的商品插件
|
||||
try:
|
||||
if _use_func_data.get(goods_name):
|
||||
_kwargs = _use_func_data[goods_name]["kwargs"]
|
||||
_kwargs["goods_name"] = goods_name
|
||||
_kwargs["user_id"] = user_id
|
||||
_kwargs["group_id"] = group_id
|
||||
if asyncio.iscoroutinefunction(_use_func_data[goods_name]["func"]):
|
||||
await _use_func_data[goods_name]["func"](
|
||||
**_kwargs,
|
||||
)
|
||||
else:
|
||||
_use_func_data[goods_name]["func"](
|
||||
**_kwargs,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
|
||||
def registered_use(goods_name: str, func, **kwargs):
|
||||
"""
|
||||
注册商品使用方法
|
||||
:param goods_name: 商品名称
|
||||
:param func: 使用函数
|
||||
:param kwargs: kwargs
|
||||
"""
|
||||
if goods_name in _use_func_data.keys():
|
||||
raise ValueError("该商品使用函数已被注册!")
|
||||
_use_func_data[goods_name] = {"func": func, "kwargs": kwargs}
|
||||
@@ -0,0 +1,38 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from services.db_context import db
|
||||
from utils.utils import get_message_text
|
||||
from services.log import logger
|
||||
|
||||
__zx_plugin_name__ = "执行sql [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
执行一段sql语句
|
||||
指令:
|
||||
exec [sql语句]
|
||||
""".strip()
|
||||
__plugin_des__ = "执行一段sql语句"
|
||||
__plugin_cmd__ = [
|
||||
"exec [sql语句]",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
exec_ = on_command("exec", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
|
||||
@exec_.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
sql = get_message_text(event.json())
|
||||
async with db.transaction():
|
||||
try:
|
||||
query = db.text(sql)
|
||||
await db.first(query)
|
||||
await exec_.send("执行 sql 语句成功.")
|
||||
except Exception as e:
|
||||
await exec_.send(f"执行 sql 语句失败 {type(e)}:{e}")
|
||||
logger.error(f"执行 sql 语句失败 {type(e)}:{e}")
|
||||
@@ -40,7 +40,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
group_id = -1
|
||||
level = 0
|
||||
try:
|
||||
args = get_message_text(event.json()).strip().split()
|
||||
args = get_message_text(event.json()).split()
|
||||
qq = get_message_at(event.json())
|
||||
flag = -1
|
||||
if not qq:
|
||||
@@ -55,18 +55,17 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
else:
|
||||
await super_cmd.finish(
|
||||
"权限参数不完全\n\t格式:添加/删除权限 [at] [level]"
|
||||
"\n\t格式:添加/删除权限 [qq] [group] [level]",
|
||||
"\n\t格式:添加/删除权限 [qq] [group_id] [level]",
|
||||
at_sender=True,
|
||||
)
|
||||
else:
|
||||
if not is_number(args[0]):
|
||||
await super_cmd.finish("所有参数必须是数字!", at_sender=True)
|
||||
level = int(args[0])
|
||||
qq = qq[0]
|
||||
group_id = event.group_id
|
||||
flag = 2
|
||||
if state["_prefix"]["raw_command"][:2] == "添加":
|
||||
if is_number(args[0]):
|
||||
level = int(args[0])
|
||||
else:
|
||||
await super_cmd.finish("权限等级必须是数字!", at_sender=True)
|
||||
if await LevelUser.set_level(qq, group_id, level, 1):
|
||||
result = "添加管理成功, 权限: " + str(level)
|
||||
else:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
@@ -32,7 +32,7 @@ def _create_help_image():
|
||||
_plugin_name_list = []
|
||||
width = 0
|
||||
help_str = "超级用户帮助\n\n* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n"
|
||||
tmp_img = CreateImg(0, 0, plain_text='1', font_size=24)
|
||||
tmp_img = BuildImage(0, 0, plain_text='1', font_size=24)
|
||||
for matcher in _matchers:
|
||||
plugin_name = ""
|
||||
try:
|
||||
@@ -72,8 +72,8 @@ def _create_help_image():
|
||||
)
|
||||
height = len(help_str.split("\n")) * 33
|
||||
width += 500
|
||||
A = CreateImg(width, height, font_size=24)
|
||||
_background = CreateImg(width, height, background=background)
|
||||
A = BuildImage(width, height, font_size=24)
|
||||
_background = BuildImage(width, height, background=background)
|
||||
A.text((300, 140), help_str)
|
||||
A.paste(_background, alpha=True)
|
||||
A.save(superuser_help_image)
|
||||
|
||||
@@ -9,10 +9,12 @@ driver.register_adapter("cqhttp", CQHTTPBot)
|
||||
config = driver.config
|
||||
driver.on_startup(init)
|
||||
driver.on_shutdown(disconnect)
|
||||
# 优先加载定时任务插件
|
||||
# 优先加载定时任务
|
||||
nonebot.load_plugin("nonebot_plugin_apscheduler")
|
||||
nonebot.load_plugins("basic_plugins")
|
||||
nonebot.load_plugins("plugins")
|
||||
# 最后加载权限控制
|
||||
nonebot.load_plugins("basic_plugins/hooks")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+2
-2
@@ -17,8 +17,8 @@ address: str = "" # 数据库地址
|
||||
port: str = "" # 数据库端口
|
||||
database: str = "" # 数据库名称
|
||||
|
||||
# 全局代理,例如 "http://127.0.0.1:7890"
|
||||
SYSTEM_PROXY: Optional[str] = None
|
||||
# 代理,例如 "http://127.0.0.1:7890"
|
||||
SYSTEM_PROXY: Optional[str] = None # 全局代理
|
||||
|
||||
|
||||
Config = ConfigsManager(Path() / "data" / "configs" / "plugins2config.yaml")
|
||||
|
||||
@@ -105,11 +105,12 @@ class ConfigsManager:
|
||||
if self._data[module].get(key) is not None:
|
||||
self._data[module][key]["default_value"] = value
|
||||
|
||||
def get_config(self, module: str, key: str) -> Optional[Any]:
|
||||
def get_config(self, module: str, key: str, default: Optional[Any] = None) -> Optional[Any]:
|
||||
"""
|
||||
获取指定配置值
|
||||
:param module: 模块名
|
||||
:param key: 配置名称
|
||||
:param default: 没有key值内容的默认返回值
|
||||
"""
|
||||
key = key.upper()
|
||||
if module in self._data.keys():
|
||||
@@ -118,6 +119,8 @@ class ConfigsManager:
|
||||
if self._data[module][key]["value"] is None:
|
||||
return self._data[module][key]["default_value"]
|
||||
return self._data[module][key]["value"]
|
||||
if default is not None:
|
||||
return default
|
||||
return None
|
||||
|
||||
def get_level2module(self, module: str, key: str) -> Optional[str]:
|
||||
@@ -170,4 +173,3 @@ class ConfigsManager:
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._data[key]
|
||||
|
||||
|
||||
+77
-67
@@ -1,5 +1,6 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
|
||||
|
||||
class BagUser(db.Model):
|
||||
@@ -85,7 +86,7 @@ class BagUser(db.Model):
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def add_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
||||
async def add_gold(cls, user_qq: int, belonging_group: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
增加金币
|
||||
@@ -99,27 +100,23 @@ class BagUser(db.Model):
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold + num,
|
||||
get_total_gold=user.get_total_gold + num,
|
||||
get_today_gold=user.get_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 + num,
|
||||
get_total_gold=num,
|
||||
get_today_gold=num,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold + num,
|
||||
get_total_gold=user.get_total_gold + num,
|
||||
get_today_gold=user.get_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 + num,
|
||||
get_total_gold=num,
|
||||
get_today_gold=num,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
||||
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
花费金币
|
||||
@@ -133,27 +130,23 @@ class BagUser(db.Model):
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold - num,
|
||||
spend_total_gold=user.spend_total_gold + num,
|
||||
spend_today_gold=user.spend_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 - num,
|
||||
spend_total_gold=num,
|
||||
spend_today_gold=num,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold - num,
|
||||
spend_total_gold=user.spend_total_gold + num,
|
||||
spend_today_gold=user.spend_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 - num,
|
||||
spend_total_gold=num,
|
||||
spend_today_gold=num,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def add_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
||||
async def add_props(cls, user_qq: int, belonging_group: int, name: str):
|
||||
"""
|
||||
说明:
|
||||
增加道具
|
||||
@@ -167,16 +160,12 @@ class BagUser(db.Model):
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(props=user.props + f"{name},").apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq, belonging_group=belonging_group, props=f"{name},"
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if user:
|
||||
await user.update(props=user.props + f"{name},").apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq, belonging_group=belonging_group, props=f"{name},"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def del_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
||||
@@ -193,27 +182,48 @@ class BagUser(db.Model):
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
rst = ""
|
||||
props = user.props
|
||||
if props.find(name) != -1:
|
||||
props = props.split(",")
|
||||
try:
|
||||
index = props.index(name)
|
||||
except ValueError:
|
||||
return False
|
||||
props = props[:index] + props[index + 1 :]
|
||||
for p in props:
|
||||
if p != "":
|
||||
rst += p + ","
|
||||
await user.update(props=rst).apply()
|
||||
return True
|
||||
else:
|
||||
if user:
|
||||
rst = ""
|
||||
props = user.props
|
||||
if props.find(name) != -1:
|
||||
props = props.split(",")
|
||||
try:
|
||||
index = props.index(name)
|
||||
except ValueError:
|
||||
return False
|
||||
props = props[:index] + props[index + 1 :]
|
||||
for p in props:
|
||||
if p != "":
|
||||
rst += p + ","
|
||||
await user.update(props=rst).apply()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except Exception:
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def buy_props(
|
||||
cls, user_qq: int, belonging_group: int, goods: "GoodsInfo", goods_num: int
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
购买道具
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param belonging_group: 所在群聊
|
||||
:param goods: 商品
|
||||
:param goods_num: 商品数量
|
||||
"""
|
||||
try:
|
||||
# 折扣后金币
|
||||
spend_gold = goods.goods_discount * goods.goods_price * goods_num
|
||||
await BagUser.spend_gold(user_qq, belonging_group, spend_gold)
|
||||
for _ in range(goods_num):
|
||||
await BagUser.add_props(user_qq, belonging_group, goods.goods_name)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"buy_props 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -83,8 +83,9 @@ class FriendUser(db.Model):
|
||||
if user.nickname:
|
||||
_tmp = ""
|
||||
black_word = Config.get_config("nickname", "BLACK_WORD")
|
||||
for x in user.nickname:
|
||||
_tmp += "*" if x in black_word else x
|
||||
if black_word:
|
||||
for x in user.nickname:
|
||||
_tmp += "*" if x in black_word else x
|
||||
return _tmp
|
||||
return ""
|
||||
|
||||
|
||||
Executable → Regular
+15
-11
@@ -1,5 +1,6 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
|
||||
|
||||
class GoodsInfo(db.Model):
|
||||
@@ -34,16 +35,18 @@ class GoodsInfo(db.Model):
|
||||
:param goods_limit_time: 商品限时
|
||||
"""
|
||||
try:
|
||||
await cls.create(
|
||||
goods_name=goods_name,
|
||||
goods_price=goods_price,
|
||||
goods_description=goods_description,
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if not await cls.get_goods_info(goods_name):
|
||||
await cls.create(
|
||||
goods_name=goods_name,
|
||||
goods_price=goods_price,
|
||||
goods_description=goods_description,
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo add_goods 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_goods(cls, goods_name: str) -> bool:
|
||||
@@ -99,7 +102,8 @@ class GoodsInfo(db.Model):
|
||||
if goods_limit_time:
|
||||
await query.update(goods_limit_time=goods_limit_time).apply()
|
||||
return True
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
@@ -156,8 +156,9 @@ class GroupInfoUser(db.Model):
|
||||
if user.nickname:
|
||||
_tmp = ""
|
||||
black_word = Config.get_config("nickname", "BLACK_WORD")
|
||||
for x in user.nickname:
|
||||
_tmp += "*" if x in black_word else x
|
||||
if black_word:
|
||||
for x in user.nickname:
|
||||
_tmp += "*" if x in black_word else x
|
||||
return _tmp
|
||||
return ""
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
|
||||
from typing import List
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
@@ -26,6 +26,14 @@ class SignGroupUser(db.Model):
|
||||
async def ensure(
|
||||
cls, user_qq: int, belonging_group: int, for_update: bool = False
|
||||
) -> "SignGroupUser":
|
||||
"""
|
||||
说明:
|
||||
获取签到用户
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param belonging_group: 所在群聊
|
||||
:param for_update: 是否存在修改数据
|
||||
"""
|
||||
query = cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
||||
)
|
||||
@@ -40,8 +48,28 @@ class SignGroupUser(db.Model):
|
||||
impression=0,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_user_all_data(cls, user_qq: int) -> List["SignGroupUser"]:
|
||||
"""
|
||||
说明:
|
||||
获取某用户所有数据
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = cls.query.where(cls.user_qq == user_qq)
|
||||
query = query.with_for_update()
|
||||
return await query.gino.all()
|
||||
|
||||
@classmethod
|
||||
async def sign(cls, user: "SignGroupUser", impression: float, checkin_time_last: datetime):
|
||||
"""
|
||||
说明:
|
||||
签到
|
||||
说明:
|
||||
:param user: 用户
|
||||
:param impression: 增加的好感度
|
||||
:param checkin_time_last: 签到时间
|
||||
"""
|
||||
await user.update(
|
||||
checkin_count=user.checkin_count + 1,
|
||||
checkin_time_last=checkin_time_last,
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
from nonebot import on_regex
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
__zx_plugin_name__ = "关于"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
想要更加了解真寻吗
|
||||
指令:
|
||||
关于
|
||||
""".strip()
|
||||
__plugin_des__ = "想要更加了解真寻吗"
|
||||
__plugin_cmd__ = ["关于"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_type__ = ("其他",)
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 1,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["关于"],
|
||||
}
|
||||
|
||||
|
||||
about = on_regex("^关于$", priority=5, block=True, rule=to_me())
|
||||
|
||||
|
||||
@about.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
ver_file = Path() / '__version__'
|
||||
version = None
|
||||
if ver_file.exists():
|
||||
with open(ver_file, 'r', encoding='utf8') as f:
|
||||
version = f.read().split(':')[-1].strip()
|
||||
msg = f"""
|
||||
『绪山真寻Bot』
|
||||
版本:{version}
|
||||
简介:基于Nonebot2与go-cqhttp开发,是一个非常可爱的Bot呀,希望与大家要好好相处
|
||||
项目地址:https://github.com/HibiKier/zhenxun_bot
|
||||
文档地址:https://hibikier.github.io/zhenxun_bot/
|
||||
""".strip()
|
||||
await about.send(msg)
|
||||
+4
-1
@@ -75,7 +75,10 @@ class AiMessageManager(StaticData):
|
||||
:param user_id: 用户id
|
||||
:param nickname: 用户昵称
|
||||
"""
|
||||
if len(self._data[user_id]["message"]) < 2:
|
||||
try:
|
||||
if len(self._data[user_id]["message"]) < 2:
|
||||
return None
|
||||
except KeyError:
|
||||
return None
|
||||
msg = await self._get_user_repeat_message_result(user_id)
|
||||
if not msg:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.message_builder import image
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional
|
||||
@@ -33,14 +33,14 @@ def gen_wbtop_pic(data: dict) -> MessageSegment:
|
||||
生成微博热搜图片
|
||||
:param data: 微博热搜数据
|
||||
"""
|
||||
bk = CreateImg(700, 32 * 50 + 280, 700, 32, color="#797979")
|
||||
wbtop_bk = CreateImg(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
|
||||
bk = BuildImage(700, 32 * 50 + 280, 700, 32, color="#797979")
|
||||
wbtop_bk = BuildImage(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
|
||||
bk.paste(wbtop_bk)
|
||||
text_bk = CreateImg(700, 32 * 50, 700, 32, color="#797979")
|
||||
text_bk = BuildImage(700, 32 * 50, 700, 32, color="#797979")
|
||||
for i, data in enumerate(data):
|
||||
title = f"{i+1}. {data['hot_word']}"
|
||||
hot = data["hot_word_num"]
|
||||
img = CreateImg(700, 30, font_size=20)
|
||||
img = BuildImage(700, 30, font_size=20)
|
||||
w, h = img.getsize(title)
|
||||
img.text((10, int((30 - h) / 2)), title)
|
||||
img.text((580, int((30 - h) / 2)), hot)
|
||||
|
||||
@@ -254,7 +254,7 @@ async def _get_up_status(id_: int) -> Optional[str]:
|
||||
if dynamic_img:
|
||||
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
|
||||
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n"
|
||||
if _user.latest_video_created != latest_video_created and video:
|
||||
if _user.latest_video_created < latest_video_created and video:
|
||||
rst = rst + "-------------\n" if rst else rst
|
||||
await BilibiliSub.update_sub_info(
|
||||
id_, latest_video_created=latest_video_created
|
||||
@@ -304,7 +304,7 @@ async def get_user_dynamic(
|
||||
browser = await get_browser()
|
||||
if dynamic_info.get("cards") and browser:
|
||||
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
||||
if local_user.dynamic_upload_time != dynamic_upload_time:
|
||||
if local_user.dynamic_upload_time < dynamic_upload_time:
|
||||
page = await browser.new_page()
|
||||
await page.goto(
|
||||
f"https://space.bilibili.com/{local_user.uid}/dynamic",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from pathlib import Path
|
||||
@@ -35,21 +35,21 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
|
||||
sex = user_info["sex"]
|
||||
face = user_info["face"]
|
||||
sign = user_info["sign"]
|
||||
ava = CreateImg(100, 100, background=BytesIO(await get_pic(face)))
|
||||
ava = BuildImage(100, 100, background=BytesIO(await get_pic(face)))
|
||||
ava.circle()
|
||||
cover = CreateImg(470, 265, background=BytesIO(await get_pic(cover)))
|
||||
cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover)))
|
||||
print()
|
||||
|
||||
|
||||
def _create_live_des_image(
|
||||
title: str,
|
||||
cover: CreateImg,
|
||||
cover: BuildImage,
|
||||
tags: str,
|
||||
des: str,
|
||||
user_name: str,
|
||||
sex: str,
|
||||
sign: str,
|
||||
ava: CreateImg,
|
||||
ava: BuildImage,
|
||||
):
|
||||
"""
|
||||
生成主播简介图片
|
||||
@@ -66,6 +66,6 @@ def _create_live_des_image(
|
||||
border = BORDER_PATH / "0.png"
|
||||
border_img = None
|
||||
if border.exists():
|
||||
border_img = CreateImg(1772, 2657, background=border)
|
||||
bk = CreateImg(1772, 2657, font_size=30)
|
||||
border_img = BuildImage(1772, 2657, background=border)
|
||||
bk = BuildImage(1772, 2657, font_size=30)
|
||||
bk.paste(cover, (0, 100), center_type="by_width")
|
||||
|
||||
@@ -23,7 +23,10 @@ async def search_song(song_name: str):
|
||||
async def get_song_id(song_name: str) -> int:
|
||||
""" """
|
||||
r = await search_song(song_name)
|
||||
return r["result"]["songs"][0]["id"]
|
||||
try:
|
||||
return r["result"]["songs"][0]["id"]
|
||||
except KeyError:
|
||||
return 0
|
||||
|
||||
|
||||
async def get_song_info(songId: int):
|
||||
|
||||
@@ -2,7 +2,7 @@ import psutil
|
||||
import time
|
||||
from datetime import datetime
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from pathlib import Path
|
||||
import asyncio
|
||||
@@ -49,7 +49,7 @@ class Check:
|
||||
|
||||
async def show(self):
|
||||
await self.check_all()
|
||||
A = CreateImg(0, 0, font_size=24)
|
||||
A = BuildImage(0, 0, font_size=24)
|
||||
rst = (
|
||||
f'[Time] {str(datetime.now()).split(".")[0]}\n'
|
||||
f"-----System-----\n"
|
||||
@@ -69,10 +69,10 @@ class Check:
|
||||
if w > width:
|
||||
width = w
|
||||
height += 30
|
||||
A = CreateImg(width + 50, height + 10, font_size=24, font="HWZhongSong.ttf")
|
||||
A = BuildImage(width + 50, height + 10, font_size=24, font="HWZhongSong.ttf")
|
||||
A.transparent(1)
|
||||
A.text((10, 10), rst)
|
||||
_x = max(width, height)
|
||||
bk = CreateImg(_x + 100, _x + 100, background=Path(IMAGE_PATH) / "background" / "check" / "0.jpg")
|
||||
bk = BuildImage(_x + 100, _x + 100, background=Path(IMAGE_PATH) / "background" / "check" / "0.jpg")
|
||||
bk.paste(A, alpha=True, center_type='center')
|
||||
return bk.pic2bs4()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from nonebot.adapters.cqhttp import Bot, Message
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from utils.http_utils import AsyncHttpx
|
||||
@@ -85,12 +85,12 @@ async def check_update(bot: Bot) -> 'int, str':
|
||||
update_info = data["body"]
|
||||
width = 0
|
||||
height = len(update_info.split('\n')) * 24
|
||||
A = CreateImg(width, height, font_size=20)
|
||||
A = BuildImage(width, height, font_size=20)
|
||||
for m in update_info.split('\n'):
|
||||
w, h = A.getsize(m)
|
||||
if w > width:
|
||||
width = w
|
||||
A = CreateImg(width + 50, height, font_size=20)
|
||||
A = BuildImage(width + 50, height, font_size=20)
|
||||
A.text((10, 10), update_info)
|
||||
A.save(f'{IMAGE_PATH}/update_info.png')
|
||||
await bot.send_private_msg(
|
||||
|
||||
@@ -65,7 +65,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
img_msg = _text("")
|
||||
for img in get_message_imgs(event.json()):
|
||||
img_msg += image(img)
|
||||
if not text or text in ["帮助"]:
|
||||
if not text and not img_msg:
|
||||
await dialogue.send("请发送[滴滴滴]+您要说的内容~", at_sender=True)
|
||||
else:
|
||||
group_id = 0
|
||||
|
||||
@@ -40,7 +40,7 @@ def is_expired(data: dict):
|
||||
|
||||
# 检查写入
|
||||
def check_write(data: dict, up_char_file):
|
||||
if not is_expired(data['char']):
|
||||
if is_expired(data['char']):
|
||||
for x in list(data.keys()):
|
||||
data[x]['title'] = ''
|
||||
else:
|
||||
|
||||
@@ -146,12 +146,14 @@ def _format_card_information(_count: int, user_id, pool_name):
|
||||
five_index_list = []
|
||||
five_list = []
|
||||
five_dict = {}
|
||||
_start_add_count = 72 if pool_name == 'char' else 62
|
||||
_x = 90 if pool_name == 'char' else 80 # 保底
|
||||
add = 0.0
|
||||
if genshin_count.get(user_id) and _count <= 90:
|
||||
if genshin_count.get(user_id) and _count <= _x:
|
||||
f_count = genshin_count[user_id]
|
||||
else:
|
||||
f_count = 0
|
||||
if genshin_pl_count.get(user_id) and _count <= 90:
|
||||
if genshin_pl_count.get(user_id) and _count <= _x:
|
||||
count = genshin_pl_count[user_id]
|
||||
else:
|
||||
count = 0
|
||||
@@ -159,23 +161,23 @@ def _format_card_information(_count: int, user_id, pool_name):
|
||||
count += 1
|
||||
f_count += 1
|
||||
# 十连保底
|
||||
if count == 10 and f_count != 90:
|
||||
if f_count >= 72:
|
||||
if count == 10 and f_count != _x:
|
||||
if f_count >= _start_add_count:
|
||||
add += I72_ADD
|
||||
char, code = _get_genshin_card(2, pool_name, add=add)
|
||||
count = 0
|
||||
# 大保底
|
||||
elif f_count == 90:
|
||||
elif f_count == _x:
|
||||
char, code = _get_genshin_card(3, pool_name)
|
||||
else:
|
||||
if f_count >= 72:
|
||||
if f_count >= _start_add_count:
|
||||
add += I72_ADD
|
||||
char, code = _get_genshin_card(pool_name=pool_name, add=add)
|
||||
if code == 1:
|
||||
count = 0
|
||||
star_list[code] += 1
|
||||
if code == 0:
|
||||
if _count <= 90:
|
||||
if _count <= _x:
|
||||
genshin_five[user_id] = f_count
|
||||
add = 0.0
|
||||
f_count = 0
|
||||
@@ -186,7 +188,7 @@ def _format_card_information(_count: int, user_id, pool_name):
|
||||
except KeyError:
|
||||
five_dict[char.name] = 1
|
||||
char_list.append(char)
|
||||
if _count <= 90:
|
||||
if _count <= _x:
|
||||
genshin_count[user_id] = f_count
|
||||
genshin_pl_count[user_id] = count
|
||||
return char_list, five_list, five_index_list, five_dict, star_list
|
||||
|
||||
@@ -91,22 +91,26 @@ def _get_operator_card(add: float):
|
||||
zoom = z
|
||||
else:
|
||||
weight = z
|
||||
up_operator_name = ""
|
||||
# UP
|
||||
if random.random() < zoom:
|
||||
up_operators = [x.operators for x in UP_OPERATOR if x.star == star and x.zoom < 1][0]
|
||||
up_operator_name = random.choice(up_operators)
|
||||
# print(up_operator_name)
|
||||
acquire_operator = [x for x in ALL_OPERATOR if x.name == up_operator_name][0]
|
||||
else:
|
||||
all_star_operators = [x for x in ALL_OPERATOR if x.star == star
|
||||
and not any([x.limited, x.event_only, x.recruit_only])]
|
||||
weight_up_operators = [x.operators for x in UP_OPERATOR if x.star == star and x.zoom > 1]
|
||||
# 权重
|
||||
if weight_up_operators and random.random() < 1.0 / float(len(all_star_operators)) * weight:
|
||||
up_operator_name = random.choice(weight_up_operators[0])
|
||||
try:
|
||||
if random.random() < zoom:
|
||||
up_operators = [x.operators for x in UP_OPERATOR if x.star == star and x.zoom < 1][0]
|
||||
up_operator_name = random.choice(up_operators)
|
||||
# print(up_operator_name)
|
||||
acquire_operator = [x for x in ALL_OPERATOR if x.name == up_operator_name][0]
|
||||
else:
|
||||
acquire_operator = random.choice(all_star_operators)
|
||||
all_star_operators = [x for x in ALL_OPERATOR if x.star == star
|
||||
and not any([x.limited, x.event_only, x.recruit_only])]
|
||||
weight_up_operators = [x.operators for x in UP_OPERATOR if x.star == star and x.zoom > 1]
|
||||
# 权重
|
||||
if weight_up_operators and random.random() < 1.0 / float(len(all_star_operators)) * weight:
|
||||
up_operator_name = random.choice(weight_up_operators[0])
|
||||
acquire_operator = [x for x in ALL_OPERATOR if x.name == up_operator_name][0]
|
||||
else:
|
||||
acquire_operator = random.choice(all_star_operators)
|
||||
except IndexError:
|
||||
acquire_operator = Operator(up_operator_name, star, True, False, False)
|
||||
else:
|
||||
acquire_operator = random.choice([x for x in ALL_OPERATOR if x.star == star
|
||||
and not any([x.limited, x.event_only, x.recruit_only])])
|
||||
|
||||
+10
-10
@@ -6,7 +6,7 @@ from configs.path_config import IMAGE_PATH
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import nonebot
|
||||
import pypinyin
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
import platform
|
||||
from services.log import logger
|
||||
import random
|
||||
@@ -98,37 +98,37 @@ async def generate_img(card_set: Union[Set[BaseData], List[BaseData]], game_name
|
||||
num = 0
|
||||
for n in star_list:
|
||||
num += n
|
||||
A = CreateImg(w, h)
|
||||
A = BuildImage(w, h)
|
||||
A.paste(card_img)
|
||||
return A.pic2bs4()
|
||||
|
||||
|
||||
def _pst(h: int, img_list: list, game_name: str, background_list: list):
|
||||
card_img = CreateImg(100 * 10, h, 100, 100)
|
||||
card_img = BuildImage(100 * 10, h, 100, 100)
|
||||
idx = 0
|
||||
for img in img_list:
|
||||
try:
|
||||
if game_name == 'prts':
|
||||
bk = CreateImg(100, 100, color=background_list[idx])
|
||||
b = CreateImg(94, 94, background=img)
|
||||
bk = BuildImage(100, 100, color=background_list[idx])
|
||||
b = BuildImage(94, 94, background=img)
|
||||
bk.paste(b, (3, 3))
|
||||
b = bk
|
||||
elif game_name == 'azur' and background_list:
|
||||
bk = CreateImg(100, 100, background=background_list[idx])
|
||||
b = CreateImg(98, 90, background=img)
|
||||
bk = BuildImage(100, 100, background=background_list[idx])
|
||||
b = BuildImage(98, 90, background=img)
|
||||
bk.paste(b, (1, 5))
|
||||
b = bk
|
||||
else:
|
||||
try:
|
||||
b = CreateImg(100, 100, background=img)
|
||||
b = BuildImage(100, 100, background=img)
|
||||
except UnidentifiedImageError as e:
|
||||
logger.warning(f'无法识别图片 已删除图片,下次更新重新下载... e:{e}')
|
||||
if os.path.exists(img):
|
||||
os.remove(img)
|
||||
b = CreateImg(100, 100, color='black')
|
||||
b = BuildImage(100, 100, color='black')
|
||||
except FileNotFoundError:
|
||||
logger.warning(f'{img} not exists')
|
||||
b = CreateImg(100, 100, color='black')
|
||||
b = BuildImage(100, 100, color='black')
|
||||
card_img.paste(b)
|
||||
idx += 1
|
||||
return card_img
|
||||
|
||||
@@ -5,6 +5,7 @@ from nonebot.typing import T_State
|
||||
from utils.utils import scheduler, get_bot
|
||||
from .data_source import get_epic_free
|
||||
from utils.manager import group_manager
|
||||
from configs.config import Config
|
||||
|
||||
__zx_plugin_name__ = "epic免费游戏"
|
||||
__plugin_usage__ = """
|
||||
@@ -24,6 +25,14 @@ __plugin_settings__ = {
|
||||
"cmd": ["epic"],
|
||||
}
|
||||
__plugin_task__ = {"epic_free_game": "epic免费游戏"}
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_EPIC_FREE_GAME",
|
||||
True,
|
||||
help_="被动 epic免费游戏 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
|
||||
epic = on_command("epic", priority=5, block=True)
|
||||
|
||||
@@ -58,9 +67,7 @@ async def _():
|
||||
if await group_manager.check_group_task_status(g, "epic_free_game"):
|
||||
try:
|
||||
msg_list, code = await get_epic_free(bot, GroupMessageEvent)
|
||||
if code == 200:
|
||||
if msg_list and code == 200:
|
||||
await bot.send_group_forward_msg(group_id=g, messages=msg_list)
|
||||
else:
|
||||
await bot.send_group_msg(group_id=g, message=msg_list)
|
||||
except Exception as e:
|
||||
logger.error(f"GROUP {g} epic免费游戏推送错误 {type(e)}: {e}")
|
||||
|
||||
+8
-1
@@ -19,13 +19,20 @@ usage:
|
||||
重复3次相同的消息时会复读
|
||||
""".strip()
|
||||
__plugin_des__ = "群友的本质是什么?是复读机哒!"
|
||||
__plugin_type__ = ("被动相关",)
|
||||
__plugin_type__ = ("其他",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {"fudu": "复读"}
|
||||
__plugin_configs__ = {
|
||||
"FUDU_PROBABILITY": {"value": 0.7, "help": "复读概率", "default_value": 0.7}
|
||||
}
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_FUDU",
|
||||
True,
|
||||
help_="被动 复读 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
|
||||
class Fudu:
|
||||
|
||||
@@ -6,6 +6,7 @@ from services.log import logger
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from .data_source import get_alc_image
|
||||
from utils.manager import group_manager
|
||||
from configs.config import Config
|
||||
from pathlib import Path
|
||||
|
||||
__zx_plugin_name__ = "原神老黄历"
|
||||
@@ -28,6 +29,14 @@ __plugin_settings__ = {
|
||||
}
|
||||
__plugin_task__ = {"genshin_alc": "原神黄历提醒"}
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_GENSHIN_ALC",
|
||||
True,
|
||||
help_="被动 原神黄历提醒 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
almanac = on_command("原神黄历", priority=5, block=True)
|
||||
|
||||
|
||||
|
||||
@@ -2,14 +2,15 @@ from nonebot import on_command, Driver
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from utils.message_builder import image
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.browser import get_browser
|
||||
from configs.path_config import IMAGE_PATH
|
||||
import nonebot
|
||||
from services.log import logger
|
||||
from utils.utils import scheduler
|
||||
from nonebot.permission import SUPERUSER
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
from datetime import datetime, timedelta
|
||||
import os
|
||||
import asyncio
|
||||
import time
|
||||
@@ -52,9 +53,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if time.strftime("%w") == "0":
|
||||
await material.send("今天是周日,所有材料副本都开放了。")
|
||||
return
|
||||
file_name = str((datetime.now() - timedelta(hours=4)).date())
|
||||
if not (Path(IMAGE_PATH) / "genshin" / "material" / f"{file_name}.png").exists():
|
||||
await update_image()
|
||||
await material.send(
|
||||
Message(
|
||||
image("daily_material.png", "genshin/material")
|
||||
image(f"{file_name}.png", "genshin/material")
|
||||
+ "\n※ 每日素材数据来源于 genshin.pub"
|
||||
)
|
||||
)
|
||||
@@ -73,7 +77,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await super_cmd.send(f"更新失败...")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def update_image():
|
||||
page = None
|
||||
try:
|
||||
@@ -131,16 +134,17 @@ async def update_image():
|
||||
height = await asyncio.get_event_loop().run_in_executor(
|
||||
None, get_background_height, weapons_imgs
|
||||
)
|
||||
background_img = CreateImg(1200, height + 100, color="#f6f2ee")
|
||||
background_img = BuildImage(1200, height + 100, color="#f6f2ee")
|
||||
current_width = 50
|
||||
for imgs in [char_imgs, weapons_imgs]:
|
||||
current_height = 20
|
||||
for img in imgs:
|
||||
x = CreateImg(0, 0, background=img)
|
||||
x = BuildImage(0, 0, background=img)
|
||||
background_img.paste(x, (current_width, current_height))
|
||||
current_height += x.size[1]
|
||||
current_width += 600
|
||||
background_img.save(f"{IMAGE_PATH}/genshin/material/daily_material.png")
|
||||
file_name = str((datetime.now() - timedelta(hours=4)).date())
|
||||
background_img.save(f"{IMAGE_PATH}/genshin/material/{file_name}.png")
|
||||
await page.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -154,8 +158,8 @@ async def update_image():
|
||||
def get_background_height(weapons_imgs: List[str]) -> int:
|
||||
height = 0
|
||||
for weapons in weapons_imgs:
|
||||
height += CreateImg(0, 0, background=weapons).size[1]
|
||||
last_weapon = CreateImg(0, 0, background=weapons_imgs[-1])
|
||||
height += BuildImage(0, 0, background=weapons).size[1]
|
||||
last_weapon = BuildImage(0, 0, background=weapons_imgs[-1])
|
||||
w, h = last_weapon.size
|
||||
last_weapon.crop((0, 0, w, h - 10))
|
||||
last_weapon.save(weapons_imgs[-1])
|
||||
@@ -163,16 +167,3 @@ def get_background_height(weapons_imgs: List[str]) -> int:
|
||||
return height
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=4,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
for _ in range(5):
|
||||
try:
|
||||
await update_image()
|
||||
logger.info(f"更新每日天赋素材成功...")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"更新每日天赋素材出错 e:{e}")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from pathlib import Path
|
||||
from configs.path_config import IMAGE_PATH, TEXT_PATH
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from typing import Tuple, List
|
||||
from math import sqrt, pow
|
||||
import random
|
||||
@@ -39,7 +39,7 @@ class Map:
|
||||
:param planning_route: 是否规划最佳线路
|
||||
:param ratio: 压缩比率
|
||||
"""
|
||||
self.map = CreateImg(0, 0, background=map_path)
|
||||
self.map = BuildImage(0, 0, background=map_path)
|
||||
self.resource_name = resource_name
|
||||
self.center_x = center_point[0]
|
||||
self.center_y = center_point[1]
|
||||
@@ -225,13 +225,13 @@ class Map:
|
||||
# self.map.line(xy, (255, 0, 0), width=3)
|
||||
|
||||
# 获取资源图标
|
||||
def _get_icon_image(self, id_: int) -> "CreateImg":
|
||||
def _get_icon_image(self, id_: int) -> "BuildImage":
|
||||
icon = icon_path / f"{id_}.png"
|
||||
if icon.exists():
|
||||
return CreateImg(
|
||||
return BuildImage(
|
||||
int(50 * self.ratio), int(50 * self.ratio), background=icon
|
||||
)
|
||||
return CreateImg(
|
||||
return BuildImage(
|
||||
int(50 * self.ratio),
|
||||
int(50 * self.ratio),
|
||||
background=f"{icon_path}/box.png",
|
||||
|
||||
@@ -3,7 +3,7 @@ from configs.path_config import IMAGE_PATH, TEXT_PATH
|
||||
from PIL.Image import UnidentifiedImageError
|
||||
from utils.message_builder import image
|
||||
from services.log import logger
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from asyncio import Semaphore
|
||||
from utils.image_utils import is_valid
|
||||
@@ -186,11 +186,11 @@ async def download_map_init(
|
||||
force_flag=flag,
|
||||
)
|
||||
idx += 1
|
||||
_w, h = CreateImg(0, 0, background=f"{map_path}/0.png", ratio=MAP_RATIO).size
|
||||
_w, h = BuildImage(0, 0, background=f"{map_path}/0.png", ratio=MAP_RATIO).size
|
||||
w = _w * len(os.listdir(map_path))
|
||||
map_file = CreateImg(w, h, _w, h, ratio=MAP_RATIO)
|
||||
map_file = BuildImage(w, h, _w, h, ratio=MAP_RATIO)
|
||||
for i in range(idx):
|
||||
map_file.paste(CreateImg(0, 0, background=f"{map_path}/{i}.png", ratio=MAP_RATIO))
|
||||
map_file.paste(BuildImage(0, 0, background=f"{map_path}/{i}.png", ratio=MAP_RATIO))
|
||||
map_file.save(f"{map_path}/map.png")
|
||||
else:
|
||||
logger.warning(f'获取原神地图失败 msg: {data["message"]}')
|
||||
@@ -230,10 +230,10 @@ async def download_resource_type():
|
||||
|
||||
# 初始化资源图标
|
||||
def gen_icon(icon: str):
|
||||
A = CreateImg(0, 0, background=f"{icon_path}/box.png")
|
||||
B = CreateImg(0, 0, background=f"{icon_path}/box_alpha.png")
|
||||
A = BuildImage(0, 0, background=f"{icon_path}/box.png")
|
||||
B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png")
|
||||
icon_ = icon_path / f"{icon}"
|
||||
icon_img = CreateImg(115, 115, background=icon_)
|
||||
icon_img = BuildImage(115, 115, background=icon_)
|
||||
icon_img.circle()
|
||||
B.paste(icon_img, (17, 10), True)
|
||||
B.paste(A, alpha=True)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
from configs.config import Config
|
||||
import nonebot
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
"genshin",
|
||||
"mhyVersion",
|
||||
"2.11.1"
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"genshin",
|
||||
"salt",
|
||||
"xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs"
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"genshin",
|
||||
"client_type",
|
||||
"5"
|
||||
)
|
||||
|
||||
nonebot.load_plugins("plugins/genshin/query_user")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from utils.utils import get_message_text, is_number
|
||||
from ..models import Genshin
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "原神绑定"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
绑定原神uid等数据,cookie极为重要,请谨慎绑定
|
||||
** 如果对拥有者不熟悉,并不建议添加cookie **
|
||||
该项目只会对cookie用于”米游社签到“,“原神玩家查询”,“原神便笺查询”
|
||||
指令:
|
||||
原神绑定uid [uid]
|
||||
原神绑定米游社id [mys_id]
|
||||
原神绑定cookie [cookie] # 该绑定请私聊
|
||||
原神解绑
|
||||
示例:原神绑定uid 92342233
|
||||
如果不明白怎么获取cookie请输入“原神绑定cookie”。
|
||||
""".strip()
|
||||
__plugin_des__ = "绑定自己的原神uid等"
|
||||
__plugin_cmd__ = ["原神绑定uid [uid]", "原神绑定米游社id [mys_id]", "原神绑定cookie [cookie]", "原神解绑"]
|
||||
__plugin_type__ = ("原神相关",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["原神绑定"],
|
||||
}
|
||||
|
||||
bind = on_command(
|
||||
"原神绑定uid", aliases={"原神绑定米游社id", "原神绑定cookie"}, priority=5, block=True
|
||||
)
|
||||
|
||||
unbind = on_command("原神解绑", priority=5, block=True)
|
||||
|
||||
|
||||
@bind.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if state["_prefix"]["raw_command"] in ["原神绑定uid", "原神绑定米游社id"]:
|
||||
if not is_number(msg):
|
||||
await bind.finish("uid/id必须为纯数字!", at_senders=True)
|
||||
msg = int(msg)
|
||||
if state["_prefix"]["raw_command"] == "原神绑定uid":
|
||||
uid = await Genshin.get_user_uid(event.user_id)
|
||||
if uid:
|
||||
await bind.finish(f"您已绑定过uid:{uid},如果希望更换uid,请先发送原神解绑")
|
||||
flag = await Genshin.add_uid(event.user_id, msg)
|
||||
if not flag:
|
||||
await bind.finish("添加失败,该uid可能已存在...")
|
||||
_x = f"已成功添加原神uid:{msg}"
|
||||
elif state["_prefix"]["raw_command"] == "原神绑定米游社id":
|
||||
uid = await Genshin.get_user_uid(event.user_id)
|
||||
if not uid:
|
||||
await bind.finish("请先绑定原神uid..")
|
||||
await Genshin.set_mys_id(uid, msg)
|
||||
_x = f"已成功为uid:{uid} 设置米游社id:{msg}"
|
||||
else:
|
||||
if not msg:
|
||||
await bind.finish(
|
||||
"私聊发送!!\n打开https://bbs.mihoyo.com/ys/\n登录后按F12点击控制台输入document.cookie复制输出的内容即可"
|
||||
)
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
await bind.finish("请立即撤回你的消息并私聊发送!")
|
||||
uid = await Genshin.get_user_uid(event.user_id)
|
||||
if not uid:
|
||||
await bind.finish("请先绑定原神uid..")
|
||||
if msg.startswith('"'):
|
||||
msg = msg[1:]
|
||||
if msg.endswith('"'):
|
||||
msg = msg[:-1]
|
||||
await Genshin.set_cookie(uid, msg)
|
||||
_x = f"已成功为uid:{uid} 设置cookie"
|
||||
await bind.send(_x)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, "
|
||||
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" {state['_prefix']['raw_command']}:{msg}"
|
||||
)
|
||||
|
||||
|
||||
@unbind.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if await Genshin.delete_user(event.user_id):
|
||||
await unbind.send("用户数据删除成功...")
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f"原神解绑"
|
||||
)
|
||||
else:
|
||||
await unbind.send("该用户数据不存在..")
|
||||
@@ -0,0 +1,208 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
class Genshin(db.Model):
|
||||
__tablename__ = "genshin"
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
uid = db.Column(db.BigInteger())
|
||||
mys_id = db.Column(db.BigInteger())
|
||||
cookie = db.Column(db.String(), default="")
|
||||
today_query_uid = db.Column(db.String(), default="") # 该cookie今日查询的uid
|
||||
auto_sign = db.Column(db.Boolean(), default=False) # 自动签到
|
||||
|
||||
_idx1 = db.Index("genshin_uid_idx1", "user_qq", "uid", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_uid(cls, user_qq: int, uid: int):
|
||||
"""
|
||||
说明:
|
||||
添加一个uid
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.uid == uid))
|
||||
user = await query.gino.first()
|
||||
if not user:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
uid=uid,
|
||||
)
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def set_mys_id(cls, uid: int, mys_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置米游社id
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param mys_id: 米游社id
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(mys_id=mys_id).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def set_cookie(cls, uid: int, cookie: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置cookie
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param cookie: 米游社id
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(cookie=cookie).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置米游社自动签到
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param flag: 开关状态
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(auto_sign=flag).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_query_cookie(cls, uid: int) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
获取查询角色信息cookie
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
# 查找用户今日是否已经查找过,防止重复
|
||||
query = cls.query.where(cls.today_query_uid.contains(str(uid)))
|
||||
x = await query.gino.first()
|
||||
if x:
|
||||
return x.cookie
|
||||
for u in [x for x in await cls.query.order_by(db.func.random()).gino.all() if x.cookie]:
|
||||
if not u.today_query_uid or len(u.today_query_uid[:-1].split()) < 30:
|
||||
await cls._add_query_uid(uid, u.uid)
|
||||
return u.cookie
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def get_user_cookie(cls, uid: int, flag: bool = False) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
获取用户cookie
|
||||
参数:
|
||||
:param uid:原神uid
|
||||
:param flag:必须使用自己的cookie
|
||||
"""
|
||||
cookie = await cls._get_user_data(None, uid, "cookie")
|
||||
if not cookie and not flag:
|
||||
cookie = await cls.get_query_cookie(uid)
|
||||
return cookie
|
||||
|
||||
@classmethod
|
||||
async def get_user_uid(cls, user_qq: int) -> Optional[int]:
|
||||
"""
|
||||
说明:
|
||||
获取用户uid
|
||||
参数:
|
||||
:param user_qq:用户qq
|
||||
"""
|
||||
return await cls._get_user_data(user_qq, None, "uid")
|
||||
|
||||
@classmethod
|
||||
async def get_user_mys_id(cls, uid: int) -> Optional[int]:
|
||||
"""
|
||||
说嘛:
|
||||
获取用户米游社id
|
||||
参数:
|
||||
:param uid:原神id
|
||||
"""
|
||||
return await cls._get_user_data(None, uid, "mys_id")
|
||||
|
||||
@classmethod
|
||||
async def delete_user_cookie(cls, uid: int):
|
||||
"""
|
||||
说明:
|
||||
删除用户cookie
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(cookie="").apply()
|
||||
|
||||
@classmethod
|
||||
async def delete_user(cls, user_qq: int):
|
||||
"""
|
||||
说明:
|
||||
删除用户数据
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = cls.query.where(cls.user_qq == user_qq).with_for_update()
|
||||
user = await query.gino.first()
|
||||
if not user:
|
||||
return False
|
||||
await user.delete()
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
async def _add_query_uid(cls, uid: int, cookie_uid: int):
|
||||
"""
|
||||
说明:
|
||||
添加每日查询重复uid的cookie
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param cookie_uid: cookie的uid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == cookie_uid).with_for_update()
|
||||
user = await query.gino.first()
|
||||
await user.update(today_query_uid=cls.today_query_uid + f"{uid} ").apply()
|
||||
|
||||
@classmethod
|
||||
async def _get_user_data(
|
||||
cls, user_qq: Optional[int], uid: Optional[int], type_: str
|
||||
) -> Optional[Union[int, str]]:
|
||||
"""
|
||||
说明:
|
||||
获取用户数据
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param uid: uid
|
||||
:param type_: 数据类型
|
||||
"""
|
||||
if type_ == "uid":
|
||||
user = await cls.query.where(cls.user_qq == user_qq).gino.first()
|
||||
return user.uid if user else None
|
||||
user = await cls.query.where(cls.uid == uid).gino.first()
|
||||
if not user:
|
||||
return None
|
||||
if type_ == "mys_id":
|
||||
return user.mys_id
|
||||
elif type_ == "cookie":
|
||||
return user.cookie
|
||||
|
||||
@classmethod
|
||||
async def reset_today_query_uid(cls):
|
||||
for u in await cls.query.with_for_update().gino.all():
|
||||
if u.today_query_uid:
|
||||
await u.update(
|
||||
today_query_uid=""
|
||||
).apply()
|
||||
@@ -0,0 +1,53 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from services.log import logger
|
||||
from .data_source import get_user_memo
|
||||
from ..models import Genshin
|
||||
|
||||
|
||||
__zx_plugin_name__ = "原神便笺查询"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
通过指定cookie和uid查询事实数据
|
||||
指令:
|
||||
原神便笺查询/yss
|
||||
示例:原神便笺查询 92342233
|
||||
""".strip()
|
||||
__plugin_des__ = "不能浪费丝毫体力"
|
||||
__plugin_cmd__ = ["原神便笺查询/yss"]
|
||||
__plugin_type__ = ("原神相关",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["原神便笺查询"],
|
||||
}
|
||||
|
||||
query_memo_matcher = on_command("原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True)
|
||||
|
||||
|
||||
@query_memo_matcher.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
uid = await Genshin.get_user_uid(event.user_id)
|
||||
if not uid or not await Genshin.get_user_cookie(uid, True):
|
||||
await query_memo_matcher.finish("请先绑定uid和cookie!")
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
uname = event.sender.card or event.sender.nickname
|
||||
else:
|
||||
uname = event.sender.nickname
|
||||
data = await get_user_memo(event.user_id, uid, uname)
|
||||
if data:
|
||||
await query_memo_matcher.send(data)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, "
|
||||
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神便笺查询 uid:{uid}"
|
||||
)
|
||||
else:
|
||||
await query_memo_matcher.send("未查询到数据...")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
from typing import Optional, Union
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from configs.config import Config
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from services.log import logger
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.utils import get_user_avatar
|
||||
from utils.message_builder import image
|
||||
from ..utils import get_ds
|
||||
from ..models import Genshin
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from nonebot import Driver
|
||||
import asyncio
|
||||
import nonebot
|
||||
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
memo_path = Path(IMAGE_PATH) / "genshin" / "genshin_memo"
|
||||
memo_path.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
for name, url in zip(
|
||||
["resin.png", "task.png", "resin_discount.png"],
|
||||
[
|
||||
"https://upload-bbs.mihoyo.com/upload/2021/09/29/8819732/54266243c7d15ba31690c8f5d63cc3c6_71491376413333325"
|
||||
"20.png?x-oss-process=image//resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,png",
|
||||
"https://patchwiki.biligame.com/images/ys/thumb/c/cc/6k6kuj1kte6m1n7hexqfrn92z6h4yhh.png/60px-委托任务logo.png",
|
||||
"https://patchwiki.biligame.com/images/ys/d/d9/t1hv6wpucbwucgkhjntmzroh90nmcdv.png",
|
||||
],
|
||||
):
|
||||
file = memo_path / name
|
||||
if not file.exists():
|
||||
await AsyncHttpx.download_file(url, file)
|
||||
logger.info(f"已下载原神便签资源 -> {file}...")
|
||||
|
||||
|
||||
async def get_user_memo(user_id: int, uid: int, uname: str) -> Optional[Union[str, MessageSegment]]:
|
||||
uid = str(uid)
|
||||
if uid[0] == "1" or uid[0] == "2":
|
||||
server_id = "cn_gf01"
|
||||
elif uid[0] == "5":
|
||||
server_id = "cn_qd01"
|
||||
else:
|
||||
return None
|
||||
return await parse_data_and_draw(user_id, uid, server_id, uname)
|
||||
|
||||
|
||||
async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
|
||||
try:
|
||||
req = await AsyncHttpx.get(
|
||||
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
|
||||
headers={
|
||||
"DS": get_ds(f"role_id={uid}&server={server_id}"),
|
||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
|
||||
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
|
||||
"Referer": "https://webstatic.mihoyo.com/",
|
||||
"Cookie": await Genshin.get_user_cookie(int(uid))
|
||||
},
|
||||
)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
return data["data"], 200
|
||||
return data["message"], 999
|
||||
except TimeoutError:
|
||||
return "访问超时,请稍后再试", 997
|
||||
except Exception as e:
|
||||
logger.info(f"便签查询获取失败未知错误 {e}:{e}")
|
||||
return "发生了一些错误,请稍后再试", 998
|
||||
|
||||
|
||||
def create_border(
|
||||
image_name: str, content: str, notice_text: str, value: str
|
||||
) -> BuildImage:
|
||||
border = BuildImage(500, 100, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20)
|
||||
text_bk = BuildImage(350, 96, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf")
|
||||
_x = 70 if image_name == "resin.png" else 50
|
||||
_px = 10 if image_name == "resin.png" else 20
|
||||
text_bk.paste(
|
||||
BuildImage(_x, _x, background=memo_path / image_name),
|
||||
(_px, 0),
|
||||
True,
|
||||
center_type="by_height",
|
||||
)
|
||||
text_bk.text((87, 20), content)
|
||||
text_bk.paste(
|
||||
BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=notice_text,
|
||||
font_color=(203, 189, 175),
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=17,
|
||||
),
|
||||
(87, 50),
|
||||
True,
|
||||
)
|
||||
font_width, _ = border.getsize(value)
|
||||
border.text((350 + 76 - int(font_width / 2), 0), value, center_type="by_height")
|
||||
border.paste(text_bk, (2, 0), center_type="by_height")
|
||||
return border
|
||||
|
||||
|
||||
async def parse_data_and_draw(
|
||||
user_id: int, uid: str, server_id: str, uname: str
|
||||
) -> Union[str, MessageSegment]:
|
||||
data, code = await get_memo(uid, server_id)
|
||||
if code != 200:
|
||||
return data
|
||||
user_avatar = BytesIO(await get_user_avatar(user_id))
|
||||
for x in data["expeditions"]:
|
||||
file_name = x["avatar_side_icon"].split("_")[-1]
|
||||
role_avatar = memo_path / "role_avatar" / file_name
|
||||
if not role_avatar.exists():
|
||||
await AsyncHttpx.download_file(x["avatar_side_icon"], role_avatar)
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
None, _parse_data_and_draw, data, user_avatar, uid, uname
|
||||
)
|
||||
|
||||
|
||||
def _parse_data_and_draw(
|
||||
data: dict, user_avatar: BytesIO, uid: int, uname: str
|
||||
) -> Union[str, MessageSegment]:
|
||||
current_resin = data["current_resin"] # 当前树脂
|
||||
max_resin = data["max_resin"] # 最大树脂
|
||||
resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间
|
||||
finished_task_num = data["finished_task_num"] # 完成的每日任务
|
||||
total_task_num = data["total_task_num"] # 每日任务总数
|
||||
remain_resin_discount_num = data["remain_resin_discount_num"] # 值得铭记的强敌总数
|
||||
resin_discount_num_limit = data["resin_discount_num_limit"] # 剩余值得铭记的强敌
|
||||
current_expedition_num = data["current_expedition_num"] # 当前挖矿人数
|
||||
max_expedition_num = data["max_expedition_num"] # 每日挖矿最大人数
|
||||
expeditions = data["expeditions"] # 挖矿详情
|
||||
|
||||
minute, second = divmod(int(resin_recovery_time), 60)
|
||||
hour, minute = divmod(minute, 60)
|
||||
|
||||
A = BuildImage(1030, 520, color="#f1e9e1", font_size=15, font="HYWenHei-85W.ttf")
|
||||
A.text((10, 15), "原神便笺 | Create By ZhenXun", (198, 186, 177))
|
||||
ava = BuildImage(100, 100, background=user_avatar)
|
||||
ava.circle()
|
||||
A.paste(ava, (40, 40), True)
|
||||
A.paste(
|
||||
BuildImage(0, 0, plain_text=uname, font_size=20, font="HYWenHei-85W.ttf"),
|
||||
(160, 62),
|
||||
True,
|
||||
)
|
||||
A.paste(
|
||||
BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"UID:{uid}",
|
||||
font_size=15,
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_color=(21, 167, 89),
|
||||
),
|
||||
(160, 92),
|
||||
True,
|
||||
)
|
||||
border = create_border(
|
||||
"resin.png",
|
||||
"原粹树脂",
|
||||
"将在{:0>2d}:{:0>2d}:{:0>2d}秒后全部恢复".format(hour, minute, second),
|
||||
f"{current_resin}/{max_resin}",
|
||||
)
|
||||
|
||||
A.paste(border, (10, 155))
|
||||
border = create_border(
|
||||
"task.png",
|
||||
"每日委托",
|
||||
"今日委托已全部完成" if finished_task_num == total_task_num else "今日委托完成数量不足",
|
||||
f"{finished_task_num}/{total_task_num}",
|
||||
)
|
||||
A.paste(border, (10, 265))
|
||||
border = create_border(
|
||||
"resin_discount.png",
|
||||
"值得铭记的强敌",
|
||||
"本周剩余消耗减半次数",
|
||||
f"{remain_resin_discount_num}/{resin_discount_num_limit}",
|
||||
)
|
||||
A.paste(border, (10, 375))
|
||||
expeditions_border = BuildImage(
|
||||
470, 430, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20
|
||||
)
|
||||
expeditions_text = BuildImage(
|
||||
466, 426, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf"
|
||||
)
|
||||
expeditions_text.text(
|
||||
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}", (100, 100, 98)
|
||||
)
|
||||
h = 45
|
||||
for x in expeditions:
|
||||
_bk = BuildImage(400, 66, color="#ECE3D8", font="HYWenHei-85W.ttf", font_size=21)
|
||||
file_name = x["avatar_side_icon"].split("_")[-1]
|
||||
role_avatar = memo_path / "role_avatar" / file_name
|
||||
_ava_img = BuildImage(75, 75, background=role_avatar)
|
||||
_ava_img.circle()
|
||||
if x["status"] == "Finished":
|
||||
msg = "探索完成"
|
||||
font_color = (146, 188, 63)
|
||||
_circle_color = (146, 188, 63)
|
||||
else:
|
||||
minute, second = divmod(int(x["remained_time"]), 60)
|
||||
hour, minute = divmod(minute, 60)
|
||||
font_color = (193, 180, 167)
|
||||
msg = "还剩{:0>2d}小时{:0>2d}分钟{:0>2d}秒".format(hour, minute, second)
|
||||
_circle_color = "#DE9C58"
|
||||
|
||||
_circle_bk = BuildImage(60, 60)
|
||||
_circle_bk.circle()
|
||||
a_circle = BuildImage(55, 55, color=_circle_color)
|
||||
a_circle.circle()
|
||||
b_circle = BuildImage(47, 47)
|
||||
b_circle.circle()
|
||||
a_circle.paste(b_circle, (4, 4), alpha=True)
|
||||
_circle_bk.paste(a_circle, (4, 4), alpha=True)
|
||||
|
||||
_bk.paste(_circle_bk, (25, 0), True, center_type="by_height")
|
||||
_bk.paste(_ava_img, (19, -13), True)
|
||||
_bk.text((100, 0), msg, font_color, "by_height")
|
||||
_bk.circle_corner(20)
|
||||
|
||||
expeditions_text.paste(_bk, (25, h), True)
|
||||
h += 75
|
||||
|
||||
expeditions_border.paste(expeditions_text, center_type="center")
|
||||
|
||||
A.paste(expeditions_border, (550, 45))
|
||||
|
||||
return image(b64=A.pic2bs4())
|
||||
@@ -0,0 +1,61 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from services.log import logger
|
||||
from .data_source import query_role_data
|
||||
from ..models import Genshin
|
||||
from utils.utils import get_message_text, is_number
|
||||
|
||||
|
||||
__zx_plugin_name__ = "原神玩家查询"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
通过uid查询原神玩家信息
|
||||
指令:
|
||||
原神玩家查询/ys ?[uid]
|
||||
示例:原神玩家查询 92342233
|
||||
""".strip()
|
||||
__plugin_des__ = "请问你们有几个肝?"
|
||||
__plugin_cmd__ = ["原神玩家查询/ys"]
|
||||
__plugin_type__ = ("原神相关",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["原神玩家查询"],
|
||||
}
|
||||
|
||||
|
||||
query_role_info_matcher = on_command("原神玩家查询", aliases={"原神玩家查找", "ys"}, priority=5, block=True)
|
||||
|
||||
|
||||
@query_role_info_matcher.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
if not is_number(msg):
|
||||
await query_role_info_matcher.finish("查询uid必须为数字!")
|
||||
msg = int(msg)
|
||||
if not msg:
|
||||
uid = await Genshin.get_user_uid(event.user_id)
|
||||
else:
|
||||
uid = msg
|
||||
if not uid: # or not await Genshin.get_user_cookie(uid):
|
||||
await query_role_info_matcher.finish("请先绑定uid和cookie!")
|
||||
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
mys_id = await Genshin.get_user_mys_id(uid)
|
||||
data = await query_role_data(event.user_id, uid, mys_id, nickname)
|
||||
if data:
|
||||
await query_role_info_matcher.send(data)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, "
|
||||
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神玩家查询 uid:{uid}"
|
||||
)
|
||||
else:
|
||||
await query_role_info_matcher.send("查询失败..")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
from typing import Optional, List, Dict, Union
|
||||
from .draw_image import init_image, get_genshin_image
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from ..utils import get_ds, element_mastery
|
||||
from services.log import logger
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from configs.config import Config
|
||||
from ..models import Genshin
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
async def query_role_data(
|
||||
user_id: int, uid: int, mys_id: Optional[str] = None, nickname: Optional[str] = None
|
||||
) -> Optional[Union[MessageSegment, str]]:
|
||||
uid = str(uid)
|
||||
if uid[0] == "1" or uid[0] == "2":
|
||||
server_id = "cn_gf01"
|
||||
elif uid[0] == "5":
|
||||
server_id = "cn_qd01"
|
||||
else:
|
||||
return None
|
||||
return await get_image(user_id, uid, server_id, mys_id, nickname)
|
||||
|
||||
|
||||
async def get_image(
|
||||
user_id: int,
|
||||
uid: str,
|
||||
server_id: str,
|
||||
mys_id: Optional[str] = None,
|
||||
nickname: Optional[str] = None,
|
||||
) -> Optional[Union[MessageSegment, str]]:
|
||||
"""
|
||||
生成图片
|
||||
:param user_id:用户qq
|
||||
:param uid: 用户uid
|
||||
:param server_id: 服务器
|
||||
:param mys_id: 米游社id
|
||||
:param nickname: QQ昵称
|
||||
:return:
|
||||
"""
|
||||
data, code = await get_info(uid, server_id)
|
||||
if code != 200:
|
||||
return data
|
||||
if data:
|
||||
char_data_list, role_data, world_data_dict, home_data_list = parsed_data(data)
|
||||
mys_data = await get_mys_data(uid, mys_id)
|
||||
if mys_data:
|
||||
nickname = None
|
||||
if char_data_list:
|
||||
char_detailed_data = await get_character(
|
||||
uid, [x["id"] for x in char_data_list], server_id
|
||||
)
|
||||
_x = {}
|
||||
if char_detailed_data:
|
||||
for char in char_detailed_data["avatars"]:
|
||||
_x[char["name"]] = {
|
||||
"weapon": char["weapon"]["name"],
|
||||
"weapon_image": char["weapon"]["icon"],
|
||||
"level": char["weapon"]["level"],
|
||||
"affix_level": char["weapon"]["affix_level"],
|
||||
}
|
||||
|
||||
await init_image(char_data_list, _x, home_data_list)
|
||||
return await get_genshin_image(
|
||||
user_id,
|
||||
uid,
|
||||
char_data_list,
|
||||
role_data,
|
||||
world_data_dict,
|
||||
home_data_list,
|
||||
_x,
|
||||
mys_data,
|
||||
nickname,
|
||||
)
|
||||
return "未找到用户数据..."
|
||||
|
||||
|
||||
# Github-@lulu666lulu https://github.com/Azure99/GenshinPlayerQuery/issues/20
|
||||
"""
|
||||
{body:"",query:{"action_ticket": undefined, "game_biz": "hk4e_cn”}}
|
||||
对应 https://api-takumi.mihoyo.com/binding/api/getUserGameRolesByCookie?game_biz=hk4e_cn //查询米哈游账号下绑定的游戏(game_biz可留空)
|
||||
{body:"",query:{"uid": 12345(被查询账号米哈游uid)}}
|
||||
对应 https://api-takumi.mihoyo.com/game_record/app/card/wapi/getGameRecordCard?uid=
|
||||
{body:"",query:{'role_id': '查询账号的uid(游戏里的)' ,'server': '游戏服务器'}}
|
||||
对应 https://api-takumi.mihoyo.com/game_record/app/genshin/api/index?server= server信息 &role_id= 游戏uid
|
||||
{body:"",query:{'role_id': '查询账号的uid(游戏里的)' , 'schedule_type': 1(我这边只看到出现过1和2), 'server': 'cn_gf01'}}
|
||||
对应 https://api-takumi.mihoyo.com/game_record/app/genshin/api/spiralAbyss?schedule_type=1&server= server信息 &role_id= 游戏uid
|
||||
{body:"",query:{game_id: 2(目前我知道有崩坏3是1原神是2)}}
|
||||
对应 https://api-takumi.mihoyo.com/game_record/app/card/wapi/getAnnouncement?game_id= 这个是公告api
|
||||
b=body q=query
|
||||
其中b只在post的时候有内容,q只在get的时候有内容
|
||||
"""
|
||||
|
||||
|
||||
async def get_info(uid_: str, server_id: str) -> "Optional[Union[dict, str]], int":
|
||||
try:
|
||||
req = await AsyncHttpx.get(
|
||||
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index?server={server_id}&role_id={uid_}",
|
||||
headers={
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
"DS": get_ds(f"role_id={uid_}&server={server_id}"),
|
||||
"Origin": "https://webstatic.mihoyo.com",
|
||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 miHoYoBBS/2.2.0",
|
||||
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
|
||||
"Referer": "https://webstatic.mihoyo.com/app/community-game-records/index.html?v=6",
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Accept-Language": "zh-CN,en-US;q=0.8",
|
||||
"X-Requested-With": "com.mihoyo.hyperion",
|
||||
"Cookie": await Genshin.get_user_cookie(int(uid_))
|
||||
},
|
||||
)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
return data["data"], 200
|
||||
return data["message"], 999
|
||||
except Exception as e:
|
||||
logger.error(f"访问失败,请重试! {type(e)}: {e}")
|
||||
return None, -1
|
||||
|
||||
|
||||
async def get_character(
|
||||
uid: str, character_ids: List[str], server_id="cn_gf01"
|
||||
) -> Optional[dict]:
|
||||
try:
|
||||
req = await AsyncHttpx.post(
|
||||
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/character",
|
||||
headers={
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
"DS": get_ds(
|
||||
"",
|
||||
{
|
||||
"character_ids": character_ids,
|
||||
"role_id": uid,
|
||||
"server": server_id,
|
||||
},
|
||||
),
|
||||
"Origin": "https://webstatic.mihoyo.com",
|
||||
"Cookie": await Genshin.get_user_cookie(int(uid)),
|
||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
|
||||
"x-rpc-client_type": "5",
|
||||
"Referer": "https://webstatic.mihoyo.com/",
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Accept-Language": "zh-CN,en-US;q=0.8",
|
||||
"X-Requested-With": "com.mihoyo.hyperion",
|
||||
},
|
||||
json={"character_ids": character_ids, "role_id": uid, "server": server_id},
|
||||
)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
return data["data"]
|
||||
except Exception as e:
|
||||
logger.error(f"访问失败,请重试! {type(e)}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def parsed_data(
|
||||
data: dict,
|
||||
) -> "Optional[List[Dict[str, str]]], Dict[str, str], Optional[List[Dict[str, str]]], Optional[List[Dict[str, str]]]":
|
||||
"""
|
||||
解析数据
|
||||
:param data: 数据
|
||||
"""
|
||||
char_data_list = []
|
||||
for char in data["avatars"]:
|
||||
_x = {
|
||||
"id": char["id"],
|
||||
"image": char["image"],
|
||||
"name": char["name"],
|
||||
"element": element_mastery[char["element"].lower()],
|
||||
"fetter": char["fetter"],
|
||||
"level": char["level"],
|
||||
"rarity": char["rarity"],
|
||||
"actived_constellation_num": char["actived_constellation_num"],
|
||||
}
|
||||
char_data_list.append(_x)
|
||||
role_data = {
|
||||
"active_day_number": data["stats"]["active_day_number"], # 活跃天数
|
||||
"achievement_number": data["stats"]["achievement_number"], # 达成成就数量
|
||||
"win_rate": data["stats"]["win_rate"],
|
||||
"anemoculus_number": data["stats"]["anemoculus_number"], # 风神瞳已收集
|
||||
"geoculus_number": data["stats"]["geoculus_number"], # 岩神瞳已收集
|
||||
"avatar_number": data["stats"]["avatar_number"], # 获得角色数量
|
||||
"way_point_number": data["stats"]["way_point_number"], # 传送点已解锁
|
||||
"domain_number": data["stats"]["domain_number"], # 秘境解锁数量
|
||||
"spiral_abyss": data["stats"]["spiral_abyss"], # 深渊当期进度
|
||||
"precious_chest_number": data["stats"]["precious_chest_number"], # 珍贵宝箱
|
||||
"luxurious_chest_number": data["stats"]["luxurious_chest_number"], # 华丽宝箱
|
||||
"exquisite_chest_number": data["stats"]["exquisite_chest_number"], # 精致宝箱
|
||||
"magic_chest_number": data["stats"]["magic_chest_number"], # 奇馈宝箱
|
||||
"common_chest_number": data["stats"]["common_chest_number"], # 普通宝箱
|
||||
"electroculus_number": data["stats"]["electroculus_number"], # 雷神瞳已收集
|
||||
}
|
||||
world_data_dict = {}
|
||||
for world in data["world_explorations"]:
|
||||
_x = {
|
||||
"level": world["level"], # 声望等级
|
||||
"exploration_percentage": world["exploration_percentage"], # 探索进度
|
||||
"image": world["icon"],
|
||||
"name": world["name"],
|
||||
"offerings": world["offerings"],
|
||||
}
|
||||
world_data_dict[world["name"]] = _x
|
||||
home_data_list = []
|
||||
for home in data["homes"]:
|
||||
_x = {
|
||||
"level": home["level"], # 最大信任等级
|
||||
"visit_num": home["visit_num"], # 最高历史访客数
|
||||
"comfort_num": home["comfort_num"], # 最高洞天仙力
|
||||
"item_num": home["item_num"], # 已获得摆件数量
|
||||
"name": home["name"],
|
||||
"icon": home["icon"],
|
||||
"comfort_level_name": home["comfort_level_name"],
|
||||
"comfort_level_icon": home["comfort_level_icon"],
|
||||
}
|
||||
home_data_list.append(_x)
|
||||
return char_data_list, role_data, world_data_dict, home_data_list
|
||||
|
||||
|
||||
async def get_mys_data(uid: str, mys_id: Optional[str]) -> Optional[List[Dict]]:
|
||||
"""
|
||||
获取用户米游社数据
|
||||
:param uid: 原神uid
|
||||
:param mys_id: 米游社id
|
||||
"""
|
||||
if mys_id:
|
||||
try:
|
||||
req = await AsyncHttpx.get(
|
||||
url=f"https://api-takumi.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
|
||||
headers={
|
||||
"DS": get_ds(f"uid={mys_id}"),
|
||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
|
||||
"x-rpc-client_type": "5",
|
||||
"Referer": "https://webstatic.mihoyo.com/",
|
||||
"Cookie": await Genshin.get_user_cookie(int(uid))
|
||||
},
|
||||
)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
return data["data"]["list"]
|
||||
except Exception as e:
|
||||
logger.error(f"访问失败,请重试! {type(e)}: {e}")
|
||||
return None
|
||||
@@ -0,0 +1,538 @@
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from pathlib import Path
|
||||
from utils.image_utils import BuildImage
|
||||
from typing import List, Dict, Optional
|
||||
from utils.message_builder import image
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.utils import get_user_avatar
|
||||
from io import BytesIO
|
||||
import random
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
|
||||
image_path = Path(IMAGE_PATH) / "genshin" / "genshin_card"
|
||||
|
||||
|
||||
async def get_genshin_image(
|
||||
user_id: int,
|
||||
uid: str,
|
||||
char_data_list: List[Dict],
|
||||
role_data: Dict,
|
||||
world_data_dict: Dict,
|
||||
home_data_list: List[Dict],
|
||||
char_detailed_dict: dict = None,
|
||||
mys_data: Optional[List[Dict]] = None,
|
||||
nickname: Optional[str] = None,
|
||||
) -> MessageSegment:
|
||||
"""
|
||||
生成图片数据
|
||||
:param user_id:用户qq
|
||||
:param uid: 原神uid
|
||||
:param char_data_list: 角色列表
|
||||
:param role_data: 玩家数据
|
||||
:param world_data_dict: 国家数据字典
|
||||
:param home_data_list: 家园列表
|
||||
:param char_detailed_dict: 角色武器字典
|
||||
:param mys_data: 用户米游社数据
|
||||
:param nickname: 用户昵称
|
||||
"""
|
||||
user_ava = BytesIO(await get_user_avatar(user_id))
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
None,
|
||||
_get_genshin_image,
|
||||
uid,
|
||||
char_data_list,
|
||||
role_data,
|
||||
world_data_dict,
|
||||
home_data_list,
|
||||
char_detailed_dict,
|
||||
mys_data,
|
||||
nickname,
|
||||
user_ava,
|
||||
)
|
||||
|
||||
|
||||
def _get_genshin_image(
|
||||
uid: str,
|
||||
char_data_list: List[Dict],
|
||||
role_data: Dict,
|
||||
world_data_dict: Dict,
|
||||
home_data_list: List[Dict],
|
||||
char_detailed_dict: dict = None,
|
||||
mys_data: Optional[Dict] = None,
|
||||
nickname: Optional[str] = None,
|
||||
user_ava: Optional[BytesIO] = None,
|
||||
) -> MessageSegment:
|
||||
"""
|
||||
生成图片数据
|
||||
:param uid: 原神uid
|
||||
:param char_data_list: 角色列表
|
||||
:param role_data: 玩家数据
|
||||
:param world_data_dict: 国家数据字典
|
||||
:param home_data_list: 家园列表
|
||||
:param char_detailed_dict: 角色武器字典
|
||||
:param mys_data: 用户米游社数据
|
||||
:param nickname: 用户昵称
|
||||
:param user_ava:用户头像
|
||||
"""
|
||||
x = 450 if char_detailed_dict else 330
|
||||
char_height = (
|
||||
len(char_data_list) / 7
|
||||
if len(char_data_list) % 7 == 0
|
||||
else len(char_data_list) / 7 + 1
|
||||
)
|
||||
foot = BuildImage(1700, 87, background=image_path / "head.png")
|
||||
head = BuildImage(1700, 87, background=image_path / "head.png")
|
||||
head.rotate(180)
|
||||
middle = BuildImage(
|
||||
1700, int(1600 + 200 + x * char_height), background=image_path / "middle.png"
|
||||
)
|
||||
A = BuildImage(middle.w, middle.h + foot.h + head.h)
|
||||
A.paste(head, (-5, 0), True)
|
||||
A.paste(middle, (0, head.h), True)
|
||||
A.paste(foot, (0, head.h + middle.h), True)
|
||||
A.crop((0, 0, A.w - 5, A.h))
|
||||
user_image = get_user_data_image(uid, role_data, mys_data, nickname, user_ava)
|
||||
home_image = get_home_data_image(home_data_list)
|
||||
country_image = get_country_data_image(world_data_dict)
|
||||
char_image, _h = get_char_data_image(char_data_list, char_detailed_dict)
|
||||
top_bk = BuildImage(user_image.w, user_image.h + home_image.h + 100, color="#F9F6F2")
|
||||
top_bk.paste(user_image, alpha=True)
|
||||
top_bk.paste(home_image, (0, user_image.h + 50), alpha=True)
|
||||
top_bk.paste(country_image, (home_image.w + 100, user_image.h + 50), alpha=True)
|
||||
bar = BuildImage(1600, 200, font_size=50, color="#F9F6F2", font="HYWenHei-85W.ttf")
|
||||
bar.text((50, 10), "角色背包", (104, 103, 101))
|
||||
bar.line((50, 90, 1550, 90), (227, 219, 209), width=10)
|
||||
if A.h - top_bk.h - bar.h - _h > 200:
|
||||
_h = A.h - top_bk.h - bar.h - _h - 200
|
||||
A.crop((0, 0, A.w, A.h - _h))
|
||||
A.paste(foot, (0, A.h - 87))
|
||||
A.paste(top_bk, (0, 100), center_type="by_width")
|
||||
A.paste(bar, (50, top_bk.h + 80))
|
||||
A.paste(char_image, (0, top_bk.h + bar.h + 10), center_type="by_width")
|
||||
rand = random.randint(1, 10000)
|
||||
A.save(Path(IMAGE_PATH) / "temp" / f"genshin_user_card_{rand}.png")
|
||||
return image(f"genshin_user_card_{rand}.png", "temp")
|
||||
|
||||
|
||||
def get_user_data_image(
|
||||
uid: str,
|
||||
role_data: Dict,
|
||||
mys_data: Optional[Dict] = None,
|
||||
nickname: Optional[str] = None,
|
||||
user_ava: Optional[BytesIO] = None,
|
||||
) -> BuildImage:
|
||||
"""
|
||||
画出玩家基本数据
|
||||
:param uid: 原神uid
|
||||
:param role_data: 玩家数据
|
||||
:param mys_data: 玩家米游社数据
|
||||
:param nickname: 用户昵称
|
||||
:param user_ava:用户头像
|
||||
"""
|
||||
if mys_data:
|
||||
nickname = [x["nickname"] for x in mys_data if x["game_id"] == 2][0]
|
||||
region = BuildImage(1440, 450, color="#E3DBD1", font="HYWenHei-85W.ttf")
|
||||
region.circle_corner(30)
|
||||
uname_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=nickname,
|
||||
font_size=40,
|
||||
color=(255, 255, 255, 0),
|
||||
font="HYWenHei-85W.ttf",
|
||||
)
|
||||
uid_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"UID: {uid}",
|
||||
font_size=25,
|
||||
color=(255, 255, 255, 0),
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_color=(21, 167, 89),
|
||||
)
|
||||
ava_bk = BuildImage(270, 270, background=image_path / "cover.png")
|
||||
# 用户头像
|
||||
if user_ava:
|
||||
ava_img = BuildImage(200, 200, background=user_ava)
|
||||
ava_img.circle()
|
||||
ava_bk.paste(ava_img, alpha=True, center_type="center")
|
||||
else:
|
||||
ava_img = BuildImage(
|
||||
245,
|
||||
245,
|
||||
background=image_path
|
||||
/ "chars_ava"
|
||||
/ random.choice(os.listdir(image_path / "chars_ava")),
|
||||
)
|
||||
ava_bk.paste(ava_img, (12, 16), alpha=True)
|
||||
region.paste(uname_img, (int(170 + uid_img.w / 2 - uname_img.w / 2), 305), True)
|
||||
region.paste(uid_img, (170, 355), True)
|
||||
region.paste(ava_bk, (int(550 / 2 - ava_bk.w / 2), 40), True)
|
||||
data_img = BuildImage(
|
||||
800, 400, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
_height = 0
|
||||
keys = [
|
||||
["活跃天数", "成就达成", "获得角色", "深境螺旋"],
|
||||
["华丽宝箱", "珍贵宝箱", "精致宝箱", "普通宝箱"],
|
||||
["奇馈宝箱", "风神瞳", "岩神瞳", "雷神瞳"],
|
||||
]
|
||||
values = [
|
||||
[
|
||||
role_data["active_day_number"],
|
||||
role_data["achievement_number"],
|
||||
role_data["avatar_number"],
|
||||
role_data["spiral_abyss"],
|
||||
],
|
||||
[
|
||||
role_data["luxurious_chest_number"],
|
||||
role_data["precious_chest_number"],
|
||||
role_data["exquisite_chest_number"],
|
||||
role_data["common_chest_number"],
|
||||
],
|
||||
[
|
||||
role_data["magic_chest_number"],
|
||||
role_data["anemoculus_number"],
|
||||
role_data["geoculus_number"],
|
||||
role_data["electroculus_number"],
|
||||
],
|
||||
]
|
||||
for key, value in zip(keys, values):
|
||||
_tmp_data_img = BuildImage(
|
||||
800, 200, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
_width = 10
|
||||
for k, v in zip(key, value):
|
||||
t_ = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=k,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(138, 143, 143),
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=30,
|
||||
)
|
||||
tmp_ = BuildImage(
|
||||
t_.w, t_.h + 70, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
tmp_.text((0, 0), str(v), center_type="by_width")
|
||||
tmp_.paste(t_, (0, 50), True, "by_width")
|
||||
_tmp_data_img.paste(tmp_, (_width if len(key) > 3 else _width + 15, 0))
|
||||
_width += 200
|
||||
data_img.paste(_tmp_data_img, (0, _height))
|
||||
_height += _tmp_data_img.h - 70
|
||||
region.paste(data_img, (510, 50))
|
||||
return region
|
||||
|
||||
|
||||
def get_home_data_image(home_data_list: List[Dict]) -> BuildImage:
|
||||
"""
|
||||
画出家园数据
|
||||
:param home_data_list: 家园列表
|
||||
"""
|
||||
region = BuildImage(
|
||||
550, 1050, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
try:
|
||||
region.text(
|
||||
(0, 30), f'尘歌壶 Lv.{home_data_list[0]["level"]}', center_type="by_width"
|
||||
)
|
||||
region.text(
|
||||
(0, 980), f'仙力: {home_data_list[0]["comfort_num"]}', center_type="by_width"
|
||||
)
|
||||
except (IndexError, KeyError):
|
||||
region.text((0, 30), f"尘歌壶 Lv.0", center_type="by_width")
|
||||
region.text((0, 980), f"仙力: 0", center_type="by_width")
|
||||
region.circle_corner(30)
|
||||
height = 100
|
||||
homes = os.listdir(image_path / "homes")
|
||||
homes.remove("lock.png")
|
||||
homes.sort()
|
||||
unlock_home = [x["name"] for x in home_data_list]
|
||||
for i, file in enumerate(homes):
|
||||
home_img = image_path / "homes" / file
|
||||
x = BuildImage(500, 250, background=home_img)
|
||||
if file.split(".")[0] not in unlock_home:
|
||||
black_img = BuildImage(500, 250, color="black")
|
||||
lock_img = BuildImage(0, 0, background=image_path / "homes" / "lock.png")
|
||||
black_img.circle_corner(50)
|
||||
black_img.transparent(1)
|
||||
black_img.paste(lock_img, alpha=True, center_type="center")
|
||||
x.paste(black_img, alpha=True)
|
||||
else:
|
||||
black_img = BuildImage(
|
||||
500, 150, color="black", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
black_img.text((55, 55), file.split(".")[0], fill=(226, 211, 146))
|
||||
black_img.transparent(1)
|
||||
text_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text="洞天等级",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_color=(203, 200, 184),
|
||||
font_size=35,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
level_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f'{home_data_list[0]["comfort_level_name"]}',
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_color=(211, 213, 207),
|
||||
font_size=30,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
black_img.paste(text_img, (270, 25), True)
|
||||
black_img.paste(level_img, (278, 85), True)
|
||||
x.paste(black_img, alpha=True, center_type="center")
|
||||
x.circle_corner(50)
|
||||
region.paste(x, (0, height), True, "by_width")
|
||||
height += 300
|
||||
return region
|
||||
|
||||
|
||||
def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
||||
"""
|
||||
画出国家探索供奉等图像
|
||||
:param world_data_dict: 国家数据字典
|
||||
"""
|
||||
region = BuildImage(790, 1050, color="#F9F6F2")
|
||||
height = 0
|
||||
for country in ["蒙德", "龙脊雪山", "璃月", "稻妻"]:
|
||||
x = BuildImage(790, 250, color="#3A4467")
|
||||
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
|
||||
tmp_bk = BuildImage(770, 230, color="#606779")
|
||||
tmp_bk.circle_corner(10)
|
||||
content_bk = BuildImage(
|
||||
755, 215, color="#3A4467", font_size=40, font="HYWenHei-85W.ttf"
|
||||
)
|
||||
content_bk.paste(logo, (50, 0), True, "by_height")
|
||||
if country in ["蒙德", "璃月"]:
|
||||
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 40),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 120), "声望", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 120),
|
||||
f"Lv.{world_data_dict[country]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
elif country in ["龙脊雪山"]:
|
||||
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 40),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 120), "供奉", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 120),
|
||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
elif country in ["稻妻"]:
|
||||
content_bk.text((300, 20), "探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 20),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 85), "声望", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 85),
|
||||
f"Lv.{world_data_dict[country]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 150), "神樱", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 150),
|
||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
x.paste(tmp_bk, alpha=True, center_type="center")
|
||||
x.paste(content_bk, alpha=True, center_type="center")
|
||||
x.circle_corner(20)
|
||||
region.paste(x, (0, height), center_type="by_width")
|
||||
height += 267
|
||||
return region
|
||||
|
||||
|
||||
def get_char_data_image(
|
||||
char_data_list: List[Dict], char_detailed_dict: dict
|
||||
) -> "BuildImage, int":
|
||||
"""
|
||||
画出角色列表
|
||||
:param char_data_list: 角色列表
|
||||
:param char_detailed_dict: 角色武器
|
||||
"""
|
||||
x = 420 if char_detailed_dict else 350
|
||||
_h = x * int(
|
||||
len(char_data_list) / 7
|
||||
if len(char_data_list) % 7 == 0
|
||||
else len(char_data_list) / 7 + 1
|
||||
)
|
||||
region = BuildImage(
|
||||
1600,
|
||||
_h,
|
||||
color="#F9F6F2",
|
||||
)
|
||||
width = 120
|
||||
height = 0
|
||||
idx = 0
|
||||
for char in char_data_list:
|
||||
if width + 230 > 1550:
|
||||
width = 120
|
||||
height += x
|
||||
idx += 1
|
||||
char_img = image_path / "chars" / f'{char["name"]}.png'
|
||||
char_bk = BuildImage(
|
||||
270,
|
||||
500 if char_detailed_dict else 400,
|
||||
background=image_path / "element.png",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=35,
|
||||
)
|
||||
char_img = BuildImage(0, 0, background=char_img)
|
||||
actived_constellation_num = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"命之座: {char['actived_constellation_num']}层",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=25,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
level = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"Lv.{char['level']}",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=30,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(21, 167, 89),
|
||||
)
|
||||
love_log = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text="♥",
|
||||
font="HWZhongSong.ttf",
|
||||
font_size=40,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(232, 31, 168),
|
||||
)
|
||||
fetter = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f'{char["fetter"]}',
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=30,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(232, 31, 168),
|
||||
)
|
||||
if char_detailed_dict.get(char["name"]):
|
||||
weapon = BuildImage(
|
||||
100,
|
||||
100,
|
||||
background=image_path
|
||||
/ "weapons"
|
||||
/ f'{char_detailed_dict[char["name"]]["weapon"]}.png',
|
||||
)
|
||||
weapon_name = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"{char_detailed_dict[char['name']]['weapon']}",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=25,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
weapon_affix_level = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"精炼: {char_detailed_dict[char['name']]['affix_level']}",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=20,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
weapon_level = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"Lv.{char_detailed_dict[char['name']]['level']}",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=25,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(21, 167, 89),
|
||||
)
|
||||
char_bk.paste(weapon, (20, 380), True)
|
||||
char_bk.paste(
|
||||
weapon_name,
|
||||
(100 + int((char_bk.w - 22 - weapon.w - weapon_name.w) / 2 - 10), 390),
|
||||
True,
|
||||
)
|
||||
char_bk.paste(
|
||||
weapon_affix_level,
|
||||
(
|
||||
(
|
||||
100
|
||||
+ int(
|
||||
(char_bk.w - 10 - weapon.w - weapon_affix_level.w) / 2 - 10
|
||||
),
|
||||
420,
|
||||
)
|
||||
),
|
||||
True,
|
||||
)
|
||||
char_bk.paste(
|
||||
weapon_level,
|
||||
(
|
||||
(
|
||||
100
|
||||
+ int((char_bk.w - 10 - weapon.w - weapon_level.w) / 2 - 10),
|
||||
450,
|
||||
)
|
||||
),
|
||||
True,
|
||||
)
|
||||
char_bk.paste(char_img, (0, 5), alpha=True, center_type="by_width")
|
||||
char_bk.text((0, 270), char["name"], center_type="by_width")
|
||||
char_bk.paste(actived_constellation_num, (0, 310), True, "by_width")
|
||||
char_bk.paste(level, (60, 340), True)
|
||||
char_bk.paste(love_log, (155, 330), True)
|
||||
char_bk.paste(fetter, (180, 340), True)
|
||||
char_bk.resize(0.8)
|
||||
region.paste(char_bk, (width, height), True)
|
||||
width += 230
|
||||
return region, _h
|
||||
|
||||
|
||||
async def init_image(char_data_list: List[Dict], char_detailed_dict: dict, home_data_list: List[Dict]):
|
||||
"""
|
||||
下载头像
|
||||
:param char_data_list: 角色列表
|
||||
:param char_detailed_dict: 角色武器
|
||||
:param home_data_list: 家园列表
|
||||
"""
|
||||
for char in char_data_list:
|
||||
file = image_path / "chars" / f'{char["name"]}.png'
|
||||
file.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not file.exists():
|
||||
await AsyncHttpx.download_file(char["image"], file)
|
||||
for char in char_detailed_dict.keys():
|
||||
file = image_path / "weapons" / f'{char_detailed_dict[char]["weapon"]}.png'
|
||||
file.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not file.exists():
|
||||
await AsyncHttpx.download_file(
|
||||
char_detailed_dict[char]["weapon_image"], file
|
||||
)
|
||||
for home in home_data_list:
|
||||
file = image_path / "homes" / f'{home["name"]}.png'
|
||||
file.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not file.exists():
|
||||
await AsyncHttpx.download_file(
|
||||
home["icon"], file
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
from utils.utils import scheduler
|
||||
from ..models import Genshin
|
||||
from services.log import logger
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=0,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
await Genshin.reset_today_query_uid()
|
||||
logger.warning(f"重置原神查询记录成功..")
|
||||
except Exception as e:
|
||||
logger.error(f"重置原神查询记录失败. {type(e)}:{e}")
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
from configs.config import Config
|
||||
import json
|
||||
import time
|
||||
import random
|
||||
import hashlib
|
||||
|
||||
|
||||
def _md5(text):
|
||||
md5 = hashlib.md5()
|
||||
md5.update(text.encode())
|
||||
return md5.hexdigest()
|
||||
|
||||
|
||||
def get_ds(q: str = "", b: dict = None):
|
||||
if b:
|
||||
br = json.dumps(b)
|
||||
else:
|
||||
br = ""
|
||||
s = Config.get_config("genshin", "salt")
|
||||
t = str(int(time.time()))
|
||||
r = str(random.randint(100000, 200000))
|
||||
c = _md5("salt=" + s + "&t=" + t + "&r=" + r + "&b=" + br + "&q=" + q)
|
||||
return t + "," + r + "," + c
|
||||
|
||||
|
||||
element_mastery = {
|
||||
"anemo": "风",
|
||||
"pyro": "火",
|
||||
"geo": "岩",
|
||||
"electro": "雷",
|
||||
"cryo": "冰",
|
||||
"hydro": "水",
|
||||
"dendro": "草",
|
||||
"none": "无",
|
||||
}
|
||||
@@ -41,8 +41,19 @@ usage:
|
||||
示例:塞红包 1000
|
||||
示例:塞红包 1000 10
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
usage:
|
||||
节日全群红包指令
|
||||
指令:
|
||||
节日红包 [金额] [数量] ?[祝福语] ?[指定群]
|
||||
""".strip()
|
||||
__plugin_des__ = "运气项目又来了"
|
||||
__plugin_cmd__ = ["塞红包 [金币数] ?[红包数=5]", "开/抢", "退回"]
|
||||
__plugin_cmd__ = [
|
||||
"塞红包 [金币数] ?[红包数=5]",
|
||||
"开/抢",
|
||||
"退回",
|
||||
"节日红包 [金额] [数量] ?[祝福语] ?[指定群] [_superuser]",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
@@ -51,9 +62,7 @@ __plugin_settings__ = {
|
||||
"limit_superuser": False,
|
||||
"cmd": ["金币红包", "塞红包"],
|
||||
}
|
||||
__plugin_resources__ = {
|
||||
"prts": IMAGE_PATH
|
||||
}
|
||||
__plugin_resources__ = {"prts": IMAGE_PATH}
|
||||
|
||||
gold_redbag = on_command(
|
||||
"塞红包", aliases={"金币红包"}, priority=5, block=True, permission=GROUP
|
||||
@@ -115,6 +124,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
redbag_data[event.group_id]["amount"]
|
||||
- redbag_data[event.group_id]["open_amount"]
|
||||
)
|
||||
await return_gold(event.user_id, event.group_id, amount)
|
||||
await gold_redbag.send(
|
||||
f'{redbag_data[event.group_id]["nickname"]}的红包过时未开完,退还{amount}金币...'
|
||||
)
|
||||
@@ -137,15 +147,17 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
else:
|
||||
amount = msg[0]
|
||||
num = msg[1]
|
||||
if not is_number(num) or int(num) < 1:
|
||||
await gold_redbag.finish("红包个数给我输正确啊!", at_sender=True)
|
||||
flag, amount = await check_gold(event.user_id, event.group_id, amount)
|
||||
if not flag:
|
||||
await gold_redbag.finish(amount, at_sender=True)
|
||||
if not is_number(num) or int(num) < 1:
|
||||
await gold_redbag.finish("红包个数给我输正确啊!", at_sender=True)
|
||||
group_member_num = (await bot.get_group_info(group_id=event.group_id))['member_count']
|
||||
group_member_num = (await bot.get_group_info(group_id=event.group_id))[
|
||||
"member_count"
|
||||
]
|
||||
num = int(num)
|
||||
if num > group_member_num:
|
||||
await gold_redbag.send('你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...')
|
||||
await gold_redbag.send("你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...")
|
||||
num = group_member_num
|
||||
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
flag, result = init_redbag(
|
||||
@@ -180,7 +192,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
.replace("。", "")
|
||||
)
|
||||
if msg:
|
||||
if '红包' not in msg:
|
||||
if "红包" not in msg:
|
||||
return
|
||||
flag1 = True
|
||||
flag2 = True
|
||||
@@ -305,7 +317,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await end_festive_redbag(bot, g)
|
||||
except JobLookupError:
|
||||
pass
|
||||
init_redbag(int(bot.self_id), g, f"{NICKNAME}", amount, num, int(bot.self_id), 1)
|
||||
init_redbag(
|
||||
int(bot.self_id), g, f"{NICKNAME}", amount, num, int(bot.self_id), 1
|
||||
)
|
||||
scheduler.add_job(
|
||||
end_festive_redbag,
|
||||
"date",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from models.bag_user import BagUser
|
||||
from utils.utils import is_number, get_user_avatar
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from .model import RedbagUser
|
||||
import random
|
||||
@@ -44,8 +44,8 @@ async def open_redbag(user_id: int, group_id: int, redbag_data: dict):
|
||||
# 随机红包图片
|
||||
async def generate_send_redbag_pic(user_id: int, msg: str = '恭喜发财 大吉大利'):
|
||||
random_redbag = random.choice(os.listdir(f"{IMAGE_PATH}/prts/redbag_2"))
|
||||
redbag = CreateImg(0, 0, font_size=38, background=f'{IMAGE_PATH}/prts/redbag_2/{random_redbag}')
|
||||
ava = CreateImg(65, 65, background=BytesIO(await get_user_avatar(user_id)))
|
||||
redbag = BuildImage(0, 0, font_size=38, background=f'{IMAGE_PATH}/prts/redbag_2/{random_redbag}')
|
||||
ava = BuildImage(65, 65, background=BytesIO(await get_user_avatar(user_id)))
|
||||
await asyncio.get_event_loop().run_in_executor(None, ava.circle)
|
||||
redbag.text((int((redbag.size[0] - redbag.getsize(msg)[0]) / 2), 210), msg, (240, 218, 164))
|
||||
redbag.paste(ava, (int((redbag.size[0] - ava.size[0])/2), 130), True)
|
||||
@@ -61,19 +61,19 @@ async def generate_open_redbag_pic(user_id: int, send_user_nickname: str, amount
|
||||
async def _generate_open_redbag_pic(user_id: int, send_user_nickname: str, amount: int, text: str):
|
||||
send_user_nickname += '的红包'
|
||||
amount = str(amount)
|
||||
head = CreateImg(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_12.png')
|
||||
size = CreateImg(0, 0, font_size=50).getsize(send_user_nickname)
|
||||
head = BuildImage(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_12.png')
|
||||
size = BuildImage(0, 0, font_size=50).getsize(send_user_nickname)
|
||||
# QQ头像
|
||||
ava_bk = CreateImg(100 + size[0], 66, color='white', font_size=50)
|
||||
ava = CreateImg(66, 66, background=BytesIO(await get_user_avatar(user_id)))
|
||||
ava_bk = BuildImage(100 + size[0], 66, color='white', font_size=50)
|
||||
ava = BuildImage(66, 66, background=BytesIO(await get_user_avatar(user_id)))
|
||||
ava_bk.paste(ava)
|
||||
ava_bk.text((100, 7), send_user_nickname)
|
||||
# ava_bk.show()
|
||||
ava_bk_w, ava_bk_h = ava_bk.size
|
||||
head.paste(ava_bk, (int((1000 - ava_bk_w) / 2), 300))
|
||||
# 金额
|
||||
size = CreateImg(0, 0, font_size=150).getsize(amount)
|
||||
price = CreateImg(size[0], size[1], font_size=150)
|
||||
size = BuildImage(0, 0, font_size=150).getsize(amount)
|
||||
price = BuildImage(size[0], size[1], font_size=150)
|
||||
price.text((0, 0), amount, fill=(209, 171, 108))
|
||||
# 金币中文
|
||||
head.paste(price, (int((1000 - size[0]) / 2) - 50, 460))
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from configs.config import Config
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from pathlib import Path
|
||||
import nonebot
|
||||
|
||||
|
||||
@@ -44,5 +46,16 @@ Config.add_plugin_config(
|
||||
default_value=6,
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"image_management",
|
||||
"SHOW_ID",
|
||||
True,
|
||||
help_="是否消息显示图片下标id",
|
||||
default_value=True
|
||||
)
|
||||
|
||||
|
||||
(Path(IMAGE_PATH) / "image_management").mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
nonebot.load_plugins("plugins/image_management")
|
||||
|
||||
@@ -31,12 +31,17 @@ __plugin_settings__ = {
|
||||
delete_img = on_command("删除图片", priority=5, rule=to_me(), block=True)
|
||||
|
||||
|
||||
_path = Path(IMAGE_PATH) / "image_management"
|
||||
|
||||
|
||||
@delete_img.args_parser
|
||||
async def parse(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if get_message_text(event.json()) in ["取消", "算了"]:
|
||||
await delete_img.finish("已取消操作..", at_sender=True)
|
||||
if state["_current_key"] in ["path"]:
|
||||
if get_message_text(event.json()) not in Config.get_config("image_management", "IMAGE_DIR_LIST"):
|
||||
if get_message_text(event.json()) not in Config.get_config(
|
||||
"image_management", "IMAGE_DIR_LIST"
|
||||
):
|
||||
await delete_img.reject("此目录不正确,请重新输入目录!")
|
||||
state[state["_current_key"]] = get_message_text(event.json())
|
||||
if state["_current_key"] == "id":
|
||||
@@ -52,7 +57,11 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
args = raw_arg.split(" ")
|
||||
if args[0] in ["帮助"]:
|
||||
await delete_img.finish(__plugin_usage__)
|
||||
if len(args) >= 2 and args[0] in Config.get_config("image_management", "IMAGE_DIR_LIST") and is_number(args[1]):
|
||||
if (
|
||||
len(args) >= 2
|
||||
and args[0] in Config.get_config("image_management", "IMAGE_DIR_LIST")
|
||||
and is_number(args[1])
|
||||
):
|
||||
state["path"] = args[0]
|
||||
state["id"] = args[1]
|
||||
|
||||
@@ -60,18 +69,18 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
@delete_img.got("path", prompt="请输入要删除的目标图库?")
|
||||
@delete_img.got("id", prompt="请输入要删除的图片id?")
|
||||
async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
|
||||
path = cn2py(state["path"])
|
||||
img_id = state["id"]
|
||||
# path = IMAGE_PATH + path
|
||||
path = Path(IMAGE_PATH) / path
|
||||
temp = Path(IMAGE_PATH) / "temp"
|
||||
path = _path / cn2py(state["path"])
|
||||
if not path.exists() and (path.parent.parent / cn2py(state["path"])).exists():
|
||||
path = path.parent.parent / cn2py(state["path"])
|
||||
temp = Path(TEMP_PATH)
|
||||
max_id = len(os.listdir(path)) - 1
|
||||
if int(img_id) > max_id or int(img_id) < 0:
|
||||
await delete_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True)
|
||||
try:
|
||||
if os.path.exists(temp / "delete.jpg"):
|
||||
os.remove(temp / "delete.jpg")
|
||||
logger.info("删除图片 delete.jpg 成功")
|
||||
if (temp / "delete.jpg").exists():
|
||||
(temp / "delete.jpg").unlink()
|
||||
logger.info(f"删除{cn2py(state['path'])}图片 {img_id}.jpg 成功")
|
||||
except Exception as e:
|
||||
logger.warning(f"删除图片 delete.jpg 失败 e{e}")
|
||||
try:
|
||||
|
||||
@@ -31,6 +31,9 @@ __plugin_settings__ = {
|
||||
move_img = on_command("移动图片", priority=5, rule=to_me(), block=True)
|
||||
|
||||
|
||||
_path = Path(IMAGE_PATH) / "image_management"
|
||||
|
||||
|
||||
@move_img.args_parser
|
||||
async def parse(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if str(event.get_message()) in ["取消", "算了"]:
|
||||
@@ -72,8 +75,20 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
@move_img.got("id", prompt="要移动的图片id是?")
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
img_id = state["id"]
|
||||
source_path = Path(IMAGE_PATH) / cn2py(state["source_path"])
|
||||
destination_path = Path(IMAGE_PATH) / cn2py(state["destination_path"])
|
||||
source_path = _path / cn2py(state["source_path"])
|
||||
destination_path = _path / cn2py(state["destination_path"])
|
||||
if (
|
||||
not source_path.exists()
|
||||
and (source_path.parent.parent / cn2py(state["source_path"])).exists()
|
||||
):
|
||||
source_path = source_path.parent.parent / cn2py(state["source_path"])
|
||||
if (
|
||||
not destination_path.exists()
|
||||
and (destination_path.parent.parent / cn2py(state["destination_path"])).exists()
|
||||
):
|
||||
destination_path = destination_path.parent.parent / cn2py(
|
||||
state["destination_path"]
|
||||
)
|
||||
destination_path.mkdir(parents=True, exist_ok=True)
|
||||
max_id = len(os.listdir(source_path)) - 1
|
||||
des_max_id = len(os.listdir(destination_path))
|
||||
|
||||
@@ -6,6 +6,7 @@ from services.log import logger
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from utils.utils import FreqLimiter, cn2py
|
||||
from pathlib import Path
|
||||
from configs.config import Config
|
||||
from utils.manager import group_manager, withdraw_message_manager
|
||||
import random
|
||||
@@ -16,10 +17,10 @@ try:
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
__zx_plugin_name__ = "发送本地图库图片"
|
||||
__zx_plugin_name__ = "本地图库"
|
||||
__plugin_usage__ = f"""
|
||||
usage:
|
||||
发送指定图库下的随机或指定id图片
|
||||
发送指定图库下的随机或指定id图片genshin_memo
|
||||
指令:
|
||||
{Config.get_config("image_management", "IMAGE_DIR_LIST")} ?[id]
|
||||
示例:美图
|
||||
@@ -37,49 +38,61 @@ __plugin_settings__ = {
|
||||
"cmd": ["发送图片"] + Config.get_config("image_management", "IMAGE_DIR_LIST"),
|
||||
}
|
||||
__plugin_task__ = {"pa": "丢人爬"}
|
||||
__plugin_resources__ = {
|
||||
"pa": IMAGE_PATH
|
||||
}
|
||||
__plugin_resources__ = {"pa": IMAGE_PATH}
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_PA",
|
||||
True,
|
||||
help_="被动 爬 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
_flmt = FreqLimiter(1)
|
||||
|
||||
cmd = set(Config.get_config("image_management", "IMAGE_DIR_LIST"))
|
||||
|
||||
# print(cmd)
|
||||
|
||||
send_img = on_command("img", aliases=cmd, priority=5, block=True)
|
||||
pa = on_keyword({"丢人爬", "爪巴"}, priority=5, block=True)
|
||||
pa_reg = on_regex("^爬$", priority=5, block=True)
|
||||
|
||||
search_url = "https://api.fantasyzone.cc/tu/search.php"
|
||||
|
||||
_path = Path(IMAGE_PATH) / "image_management"
|
||||
|
||||
|
||||
@send_img.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
img_id = get_message_text(event.json())
|
||||
path = cn2py(state["_prefix"]["raw_command"]) + "/"
|
||||
path = _path / cn2py(state["_prefix"]["raw_command"])
|
||||
if state["_prefix"]["raw_command"] in Config.get_config(
|
||||
"image_management", "IMAGE_DIR_LIST"
|
||||
):
|
||||
if not os.path.exists(f"{IMAGE_PATH}/{path}/"):
|
||||
os.mkdir(f"{IMAGE_PATH}/{path}/")
|
||||
length = len(os.listdir(IMAGE_PATH + path))
|
||||
if not path.exists() and (path.parent.parent / cn2py(state["_prefix"]["raw_command"])).exists():
|
||||
path = Path(IMAGE_PATH) / cn2py(state["_prefix"]["raw_command"])
|
||||
else:
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
length = len(os.listdir(path))
|
||||
if length == 0:
|
||||
logger.warning(f"图库 {path} 为空,调用取消!")
|
||||
logger.warning(f'图库 {cn2py(state["_prefix"]["raw_command"])} 为空,调用取消!')
|
||||
await send_img.finish("该图库中没有图片噢")
|
||||
index = img_id if img_id else str(random.randint(0, length - 1))
|
||||
if not is_number(index):
|
||||
return
|
||||
if int(index) > length - 1 or int(index) < 0:
|
||||
await send_img.finish(f"超过当前上下限!({length - 1})")
|
||||
result = image(f"{index}.jpg", path)
|
||||
result = image(path / f"{index}.jpg")
|
||||
if result:
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送{path}:"
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
|
||||
f"发送{cn2py(state['_prefix']['raw_command'])}:"
|
||||
+ result
|
||||
)
|
||||
msg_id = await send_img.send(f"id:{index}" + result)
|
||||
msg_id = await send_img.send(
|
||||
f"id:{index}" + result
|
||||
if Config.get_config("image_management", "SHOW_ID")
|
||||
else "" + result
|
||||
)
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event,
|
||||
msg_id,
|
||||
@@ -88,7 +101,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
else:
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送 {path} 失败"
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
|
||||
f"发送 {cn2py(state['_prefix']['raw_command'])} 失败"
|
||||
)
|
||||
await send_img.finish(f"不想给你看Ov|")
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
path = get_message_imgs(event.json())
|
||||
if path in Config.get_config("image_management", "IMAGE_DIR_LIST"):
|
||||
state["path"] = path
|
||||
await continuous_upload_img.send("图来!!")
|
||||
await continuous_upload_img.send("图来!!【停止请发送 ‘stop’ 开始上传】")
|
||||
state["tmp"] = []
|
||||
|
||||
|
||||
|
||||
@@ -8,11 +8,16 @@ from utils.http_utils import AsyncHttpx
|
||||
import os
|
||||
|
||||
|
||||
_path = Path(IMAGE_PATH) / "image_management"
|
||||
|
||||
|
||||
async def upload_image_to_local(
|
||||
img_list: List[str], path: str, user_id: int, group_id: int = 0
|
||||
img_list: List[str], path_: str, user_id: int, group_id: int = 0
|
||||
) -> str:
|
||||
_path = path
|
||||
path = Path(IMAGE_PATH) / cn2py(path)
|
||||
_path_name = path_
|
||||
path = _path / cn2py(path_)
|
||||
if not path.exists() and (path.parent.parent / cn2py(path_)).exists():
|
||||
path = path.parent.parent / cn2py(path_)
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
img_id = len(os.listdir(path))
|
||||
failed_list = []
|
||||
@@ -28,15 +33,15 @@ async def upload_image_to_local(
|
||||
failed_result += str(img) + "\n"
|
||||
logger.info(
|
||||
f"USER {user_id} GROUP {group_id}"
|
||||
f" 上传图片至 {_path} 共 {len(img_list)} 张,失败 {len(failed_list)} 张,id={success_id[:-1]}"
|
||||
f" 上传图片至 {_path_name} 共 {len(img_list)} 张,失败 {len(failed_list)} 张,id={success_id[:-1]}"
|
||||
)
|
||||
if failed_list:
|
||||
return (
|
||||
f"这次一共为 {_path}库 添加了 {len(img_list) - len(failed_list)} 张图片\n"
|
||||
f"这次一共为 {_path_name}库 添加了 {len(img_list) - len(failed_list)} 张图片\n"
|
||||
f"依次的Id为:{success_id[:-1]}\n上传失败:{failed_result[:-1]}\n{NICKNAME}感谢您对图库的扩充!WW"
|
||||
)
|
||||
else:
|
||||
return (
|
||||
f"这次一共为 {_path}库 添加了 {len(img_list)} 张图片\n依次的Id为:"
|
||||
f"这次一共为 {_path_name}库 添加了 {len(img_list)} 张图片\n依次的Id为:"
|
||||
f"{success_id[:-1]}\n{NICKNAME}感谢您对图库的扩充!WW"
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from utils.message_builder import image
|
||||
from services.log import logger
|
||||
from utils.utils import get_message_text
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
|
||||
__zx_plugin_name__ = "鲁迅说"
|
||||
__plugin_usage__ = """
|
||||
@@ -31,7 +31,7 @@ __plugin_block_limit__ = {
|
||||
luxun = on_command("鲁迅说过", aliases={"鲁迅说"}, priority=5, block=True)
|
||||
|
||||
|
||||
luxun_author = CreateImg(0, 0, plain_text="--鲁迅", font_size=30, font='msyh.ttf', font_color=(255, 255, 255))
|
||||
luxun_author = BuildImage(0, 0, plain_text="--鲁迅", font_size=30, font='msyh.ttf', font_color=(255, 255, 255))
|
||||
|
||||
|
||||
@luxun.handle()
|
||||
@@ -46,7 +46,7 @@ async def handle_event(bot: Bot, event: MessageEvent, state: T_State):
|
||||
content = state["content"].strip()
|
||||
if content.startswith(",") or content.startswith(","):
|
||||
content = content[1:]
|
||||
A = CreateImg(0, 0, font_size=37, background=f'{IMAGE_PATH}/other/luxun.jpg', font='msyh.ttf')
|
||||
A = BuildImage(0, 0, font_size=37, background=f'{IMAGE_PATH}/other/luxun.jpg', font='msyh.ttf')
|
||||
x = ""
|
||||
if len(content) > 40:
|
||||
await luxun.finish('太长了,鲁迅说不完...')
|
||||
|
||||
@@ -6,7 +6,7 @@ from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from utils.utils import get_message_text, get_message_at, get_user_avatar
|
||||
from utils.message_builder import image
|
||||
import re
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
|
||||
__zx_plugin_name__ = "我有一个朋友"
|
||||
__plugin_usage__ = """
|
||||
@@ -60,13 +60,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = msg.replace("他", "我").replace("她", "我").replace("它", "我")
|
||||
x = await get_user_avatar(qq)
|
||||
if x:
|
||||
ava = CreateImg(200, 100, background=BytesIO(x))
|
||||
ava = BuildImage(200, 100, background=BytesIO(x))
|
||||
else:
|
||||
ava = CreateImg(200, 100, color=(0, 0, 0))
|
||||
ava = BuildImage(200, 100, color=(0, 0, 0))
|
||||
ava.circle()
|
||||
text = CreateImg(300, 30, font_size=30)
|
||||
text = BuildImage(300, 30, font_size=30)
|
||||
text.text((0, 0), user_name)
|
||||
A = CreateImg(700, 150, font_size=25, color="white")
|
||||
A = BuildImage(700, 150, font_size=25, color="white")
|
||||
A.paste(ava, (30, 25), True)
|
||||
A.paste(text, (150, 38))
|
||||
A.text((150, 85), msg, (125, 125, 125))
|
||||
|
||||
@@ -18,6 +18,7 @@ from .open_cases_c import (
|
||||
open_shilian_case,
|
||||
)
|
||||
from .utils import util_get_buff_price, util_get_buff_img, update_count_daily
|
||||
from configs.config import Config
|
||||
|
||||
__zx_plugin_name__ = "开箱"
|
||||
__plugin_usage__ = """
|
||||
@@ -84,6 +85,14 @@ __plugin_configs__ = {
|
||||
"BUFF_PROXY": {"value": None, "help": "使用代理访问BUFF"},
|
||||
}
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_OPEN_CASE_RESET_REMIND",
|
||||
True,
|
||||
help_="被动 每日开箱重置提醒 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
cases_name = ["狂牙大行动", "突围大行动", "命悬一线", "裂空", "光谱"]
|
||||
|
||||
cases_matcher_group = MatcherGroup(priority=5, permission=GROUP, block=True)
|
||||
|
||||
@@ -10,7 +10,7 @@ import random
|
||||
from .utils import get_price
|
||||
from .models.buff_prices import BuffPrice
|
||||
from PIL import Image
|
||||
from utils.image_utils import alpha2white_pil, CreateImg
|
||||
from utils.image_utils import alpha2white_pil, BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
import asyncio
|
||||
from utils.utils import cn2py
|
||||
@@ -239,7 +239,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
|
||||
):
|
||||
skin_name += "".join(i)
|
||||
# img = image(skin_name, "cases/" + case, "png")
|
||||
wImg = CreateImg(200, 270, 200, 200)
|
||||
wImg = BuildImage(200, 270, 200, 200)
|
||||
wImg.paste(
|
||||
alpha2white_pil(
|
||||
Image.open(IMAGE_PATH + f"cases/{case}/{skin_name}.png").resize(
|
||||
@@ -263,7 +263,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
|
||||
logger.warning(
|
||||
f"USER {user_qq} GROUP {group} 开启{case_name}武器箱 {num} 次, 价格:{uplist[10]}, 数据更新失败"
|
||||
)
|
||||
# markImg = CreateImg(1000, h, 200, 270)
|
||||
# markImg = BuildImage(1000, h, 200, 270)
|
||||
# for img in img_list:
|
||||
# markImg.paste(img)
|
||||
markImg = await asyncio.get_event_loop().run_in_executor(
|
||||
@@ -284,7 +284,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
|
||||
|
||||
|
||||
def paste_markImg(h: int, img_list: list):
|
||||
markImg = CreateImg(1000, h, 200, 270)
|
||||
markImg = BuildImage(1000, h, 200, 270)
|
||||
for img in img_list:
|
||||
markImg.paste(img)
|
||||
return markImg
|
||||
@@ -399,7 +399,7 @@ async def my_knifes_name(user_id: int, group: int):
|
||||
|
||||
|
||||
def _pst_my_knife(w, h, knifes_list):
|
||||
A = CreateImg(w, h, 540, 600)
|
||||
A = BuildImage(w, h, 540, 600)
|
||||
for knife in knifes_list:
|
||||
case = knife.split("||")[0]
|
||||
knife = knife.split("||")[1]
|
||||
@@ -415,7 +415,7 @@ def _pst_my_knife(w, h, knifes_list):
|
||||
style=pypinyin.NORMAL,
|
||||
):
|
||||
skin_name += "".join(i)
|
||||
knife_img = CreateImg(470, 600, 470, 470, font_size=20)
|
||||
knife_img = BuildImage(470, 600, 470, 470, font_size=20)
|
||||
knife_img.paste(
|
||||
alpha2white_pil(
|
||||
Image.open(IMAGE_PATH + f"cases/{case}/{skin_name}.png").resize(
|
||||
|
||||
@@ -8,10 +8,10 @@ import os
|
||||
from services.log import logger
|
||||
from utils.utils import get_bot
|
||||
from asyncio.exceptions import TimeoutError
|
||||
import pypinyin
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from configs.config import Config
|
||||
from utils.manager import group_manager
|
||||
from .config import *
|
||||
|
||||
url = "https://buff.163.com/api/market/goods"
|
||||
# proxies = 'http://49.75.59.242:3128'
|
||||
|
||||
@@ -8,10 +8,11 @@ from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from bilibili_api import video
|
||||
from utils.message_builder import image
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.browser import get_browser
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from configs.config import Config
|
||||
import asyncio
|
||||
import time
|
||||
from bilibili_api import settings
|
||||
@@ -25,10 +26,18 @@ usage:
|
||||
B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
|
||||
""".strip()
|
||||
__plugin_des__ = "B站转发解析"
|
||||
__plugin_type__ = ("被动相关",)
|
||||
__plugin_type__ = ("其他",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {"bilibili_parse": "b站转发解析"}
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_BILIBILI_PARSE",
|
||||
True,
|
||||
help_="被动 B站转发解析 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
|
||||
if get_local_proxy():
|
||||
settings.proxy = get_local_proxy()
|
||||
@@ -154,5 +163,5 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
|
||||
|
||||
def resize(path: str):
|
||||
A = CreateImg(0, 0, background=path, ratio=0.5)
|
||||
A = BuildImage(0, 0, background=path, ratio=0.5)
|
||||
A.save(path)
|
||||
|
||||
@@ -69,6 +69,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
data = (await AsyncHttpx.get(url, params=params, timeout=5)).json()
|
||||
except TimeoutError:
|
||||
pass
|
||||
except Exception as e:
|
||||
await pid_search.finish(f"发生了一些错误..{type(e)}:{e}")
|
||||
else:
|
||||
if not data["width"] and not data["height"]:
|
||||
await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True)
|
||||
|
||||
@@ -57,6 +57,14 @@ Config.add_plugin_config(
|
||||
default_value=10
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"pix",
|
||||
"SHOW_INFO",
|
||||
True,
|
||||
help_="是否显示图片的基本信息,如PID等",
|
||||
default_value=True
|
||||
)
|
||||
|
||||
nonebot.load_plugins("plugins/pix_gallery")
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from asyncio.exceptions import TimeoutError
|
||||
from .model.pixiv import Pixiv
|
||||
from typing import List, Optional
|
||||
from utils.utils import change_pixiv_image_links
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from services.log import logger
|
||||
from configs.config import Config
|
||||
@@ -347,16 +347,16 @@ def gen_keyword_pic(
|
||||
del img_data["_n_pid"]
|
||||
del img_data["_n_uid"]
|
||||
current_width = 0
|
||||
A = CreateImg(img_width, 1100)
|
||||
A = BuildImage(img_width, 1100)
|
||||
for x in list(img_data.keys()):
|
||||
if img_data[x]["data"]:
|
||||
img = CreateImg(img_data[x]["width"] * 200, 1100, 200, 1100, font_size=40)
|
||||
img = BuildImage(img_data[x]["width"] * 200, 1100, 200, 1100, font_size=40)
|
||||
start_index = 0
|
||||
end_index = 40
|
||||
total_index = img_data[x]["width"] * 40
|
||||
for _ in range(img_data[x]["width"]):
|
||||
tmp = CreateImg(198, 1100, font_size=20)
|
||||
text_img = CreateImg(198, 100, font_size=50)
|
||||
tmp = BuildImage(198, 1100, font_size=20)
|
||||
text_img = BuildImage(198, 100, font_size=50)
|
||||
key_str = "\n".join(
|
||||
[key for key in img_data[x]["data"][start_index:end_index]]
|
||||
)
|
||||
@@ -370,7 +370,7 @@ def gen_keyword_pic(
|
||||
end_index = (
|
||||
end_index + 40 if end_index + 40 <= total_index else total_index
|
||||
)
|
||||
background_img = CreateImg(200, 1100, color="#FFE4C4")
|
||||
background_img = BuildImage(200, 1100, color="#FFE4C4")
|
||||
background_img.paste(tmp, (1, 1))
|
||||
img.paste(background_img)
|
||||
A.paste(img, (current_width, 0))
|
||||
|
||||
@@ -143,14 +143,17 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
uid = img.uid
|
||||
_img = await get_image(img_url, event.user_id)
|
||||
if _img:
|
||||
msg_id = await pix.send(
|
||||
Message(
|
||||
f"title:{title}\n"
|
||||
f"author:{author}\n"
|
||||
f"PID:{pid}\nUID:{uid}\n"
|
||||
f"{image(_img, 'temp')}"
|
||||
if Config.get_config("pix", "SHOW_INFO"):
|
||||
msg_id = await pix.send(
|
||||
Message(
|
||||
f"title:{title}\n"
|
||||
f"author:{author}\n"
|
||||
f"PID:{pid}\nUID:{uid}\n"
|
||||
f"{image(_img, 'temp')}"
|
||||
)
|
||||
)
|
||||
)
|
||||
else:
|
||||
msg_id = await pix.send(image(_img, 'temp'))
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 查看PIX图库PID: {pid}"
|
||||
|
||||
@@ -16,7 +16,7 @@ usage:
|
||||
戳一戳随机掉落语音或美图萝莉图
|
||||
""".strip()
|
||||
__plugin_des__ = "戳一戳发送语音美图萝莉图不美哉?"
|
||||
__plugin_type__ = ("被动相关",)
|
||||
__plugin_type__ = ("其他",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from .model import RussianUser
|
||||
from typing import Optional
|
||||
from utils.data_utils import init_rank
|
||||
from utils.image_utils import CreateMat
|
||||
from utils.image_utils import BuildMat
|
||||
|
||||
|
||||
async def rank(group_id: int, itype: str, num: int) -> Optional[CreateMat]:
|
||||
async def rank(group_id: int, itype: str, num: int) -> Optional[BuildMat]:
|
||||
all_users = await RussianUser.get_all_user(group_id)
|
||||
all_user_id = [user.user_qq for user in all_users]
|
||||
if itype == 'win_rank':
|
||||
|
||||
@@ -124,6 +124,27 @@ class Setu(db.Model):
|
||||
).gino.first()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def delete_image(cls, pid: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
删除图片并替换
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
"""
|
||||
query = await cls.query.where(cls.pid == pid).gino.first()
|
||||
if query:
|
||||
is_r18 = query.is_r18
|
||||
num = await cls.get_image_count(is_r18)
|
||||
x = await cls.query.where((cls.is_r18 == is_r18) & (cls.local_id == num - 1)).gino.first()
|
||||
_tmp_local_id = x.local_id
|
||||
if x:
|
||||
x.update(local_id=query.local_id).apply()
|
||||
await cls.delete.where(cls.pid == pid).gino.status()
|
||||
return _tmp_local_id
|
||||
return -1
|
||||
|
||||
|
||||
@classmethod
|
||||
async def update_setu_data(
|
||||
cls,
|
||||
|
||||
@@ -98,6 +98,11 @@ __plugin_configs__ = {
|
||||
"value": 10,
|
||||
"help": "色图下载超时限制(秒)",
|
||||
"default_value": 10
|
||||
},
|
||||
"SHOW_INFO": {
|
||||
"value": True,
|
||||
"help": "是否显示色图的基本信息,如PID等",
|
||||
"default_value": True
|
||||
}
|
||||
}
|
||||
Config.add_plugin_config(
|
||||
|
||||
@@ -183,13 +183,15 @@ def gen_message(setu_image: Setu, img_msg: bool = False) -> str:
|
||||
title = setu_image.title
|
||||
author = setu_image.author
|
||||
pid = setu_image.pid
|
||||
return (
|
||||
f"id:{local_id}\n"
|
||||
f"title:{title}\n"
|
||||
f"author:{author}\n"
|
||||
f"PID:{pid}\n"
|
||||
f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
|
||||
)
|
||||
if Config.get_config("send_setu", "SHOW_INFO"):
|
||||
return (
|
||||
f"id:{local_id}\n"
|
||||
f"title:{title}\n"
|
||||
f"author:{author}\n"
|
||||
f"PID:{pid}\n"
|
||||
f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
|
||||
)
|
||||
return f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
|
||||
|
||||
|
||||
# 罗翔老师!
|
||||
|
||||
@@ -3,7 +3,7 @@ from services.log import logger
|
||||
from datetime import datetime
|
||||
from utils.image_utils import compressed_image, get_img_hash
|
||||
from utils.utils import get_bot
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from PIL import UnidentifiedImageError
|
||||
from ..model import Setu
|
||||
from asyncpg.exceptions import UniqueViolationError
|
||||
from configs.config import Config
|
||||
@@ -142,6 +142,14 @@ async def update_setu_img():
|
||||
continue
|
||||
img_hash = str(get_img_hash(f"{path}/{image.local_id}.jpg"))
|
||||
await Setu.update_setu_data(image.pid, img_hash=img_hash)
|
||||
except UnidentifiedImageError:
|
||||
# 图片已删除
|
||||
with open(local_image, 'r') as f:
|
||||
if '404 Not Found' in f.read():
|
||||
max_num = await Setu.delete_image(image.pid)
|
||||
local_image.unlink()
|
||||
os.rename(path / f"{max_num}.jpg", local_image)
|
||||
logger.warning(f"更新色图 PID:{image.pid} 404,已删除并替换")
|
||||
except Exception as e:
|
||||
_success -= 1
|
||||
logger.error(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}")
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, PrivateMessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
|
||||
__zx_plugin_name__ = "服务器 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
server_ip = on_command("服务器", aliases={"ip"}, rule=to_me(), priority=5, block=True)
|
||||
|
||||
|
||||
@server_ip.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
await server_ip.finish(
|
||||
"|* 请不要发给其他人! *|\n"
|
||||
"\t121.40.195.22\n"
|
||||
"|* 请不要发给其他人! *|\n"
|
||||
"csgo ~号键控制台输入 connect 121.40.195.22 进入服务器\n"
|
||||
"然后再公屏输入 !diy 来使用皮肤(英文感叹号,注意)\n"
|
||||
"【说不定可以凑到内战噢,欢迎~{娱乐为主}】",
|
||||
at_sender=True,
|
||||
)
|
||||
|
||||
|
||||
@server_ip.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if event.group_id == 698279647:
|
||||
await server_ip.finish(
|
||||
"嗨呀!当前服务器地址是:" "\n\tay: 121.40.195.22" "\n\t夜之北枭: 101.132.170.254"
|
||||
)
|
||||
elif event.group_id == 1046451860:
|
||||
await server_ip.finish("嗨呀!当前服务器地址是:\n121.40.195.22\n !diy")
|
||||
else:
|
||||
await server_ip.finish("不好意思呀,小真寻不能为你使用此功能,因为服务器IP是真寻的小秘密呀!", at_sender=True)
|
||||
@@ -1 +0,0 @@
|
||||
from .goods_info import *
|
||||
@@ -1,154 +0,0 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_shop_help, add_goods, del_goods, update_goods
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import get_message_text, is_number
|
||||
from services.log import logger
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
商店项目,这可不是奸商
|
||||
指令:
|
||||
商店
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
usage:
|
||||
商品操作
|
||||
指令:
|
||||
添加商品 [名称]-[价格]-[描述]-?[折扣](小数)-?[限时时间](分钟)
|
||||
删除商品 [名称或序号]
|
||||
修改商品 -name [名称或序号] -price [价格] -des [描述] -discount [折扣] -time [限时]
|
||||
示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60
|
||||
示例:删除商品 2
|
||||
示例:修改商品 -name 1 -price 900: 修改序号为1的商品的价格为900
|
||||
* 修改商品只需添加需要值即可 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店系统[金币回收计划]"
|
||||
__plugin_cmd__ = [
|
||||
"商店",
|
||||
"添加商品 [名称]-[价格]-[描述]-?[折扣](小数)-?[限时时间](分钟) [_superuser]",
|
||||
"删除商品 [名称或序号] [_superuser]",
|
||||
"修改商品 -name [名称或序号] -price [价格] -des [描述] -discount [折扣] -time [限时] [_superuser]",
|
||||
]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店"],
|
||||
}
|
||||
|
||||
|
||||
shop_help = on_command("商店", priority=5, block=True)
|
||||
|
||||
shop_add_goods = on_command("添加商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
shop_del_goods = on_command("删除商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@shop_help.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if not os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
||||
await create_shop_help()
|
||||
await shop_help.send(image("shop_help.png"))
|
||||
|
||||
|
||||
@shop_add_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
msg = msg.split("-")
|
||||
if len(msg) < 3:
|
||||
await shop_add_goods.finish("商品参数不完全...", at_sender=True)
|
||||
if not is_number(msg[1]):
|
||||
await shop_add_goods.finish("商品的价格必须是合法数字!", at_sender=True)
|
||||
msg[1] = int(msg[1])
|
||||
if len(msg) > 3:
|
||||
if not is_number(msg[3]):
|
||||
await shop_add_goods.finish("商品的折扣要小数啊!", at_sender=True)
|
||||
msg[3] = float(msg[3])
|
||||
if len(msg) > 4:
|
||||
if not is_number(msg[4]):
|
||||
await shop_add_goods.finish("商品的限时时间是要写多少分钟噢!", at_sender=True)
|
||||
msg[4] = time.time() + int(msg[4]) * 60
|
||||
if await add_goods(msg):
|
||||
await shop_add_goods.send(f"添加商品 {msg[0]} 成功...", at_sender=True)
|
||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
||||
logger.info(f"USER {event.user_id} 上传商品 {msg} 成功")
|
||||
else:
|
||||
await shop_add_goods.send(f"添加商品 {msg[0]} 失败了...", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} 上传商品 {msg} 失败")
|
||||
|
||||
|
||||
@shop_del_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
name = ""
|
||||
id_ = 0
|
||||
if is_number(msg):
|
||||
id_ = int(msg)
|
||||
else:
|
||||
name = msg
|
||||
rst, goods_name, code = await del_goods(name, id_)
|
||||
if code == 200:
|
||||
await shop_del_goods.send(f"删除商品 {goods_name} 成功了...", at_sender=True)
|
||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 成功")
|
||||
else:
|
||||
await shop_del_goods.send(f"删除商品 {goods_name} 失败了...", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 失败")
|
||||
|
||||
|
||||
@shop_update_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
tmp = {}
|
||||
msg = msg.split("-")
|
||||
for x in msg:
|
||||
if x.find("name") != -1:
|
||||
tmp["name"] = x.split(" ")[1].strip()
|
||||
elif x.find("price") != -1:
|
||||
tmp["price"] = x.split(" ")[1].strip()
|
||||
if not is_number(tmp["price"]):
|
||||
await shop_update_goods.finish("价格必须是数字啊!", at_sender=True)
|
||||
tmp["price"] = int(tmp["price"])
|
||||
elif x.find("des") != -1:
|
||||
tmp["des"] = x.split(" ")[1].strip()
|
||||
elif x.find("discount") != -1:
|
||||
tmp["discount"] = x.split(" ")[1].strip()
|
||||
if not is_number(tmp["discount"]):
|
||||
await shop_update_goods.finish("折扣必须是数字啊!", at_sender=True)
|
||||
tmp["discount"] = float(tmp["discount"])
|
||||
elif x.find("time") != -1:
|
||||
tmp["time"] = x.split(" ")[1].strip()
|
||||
if not is_number(tmp["time"]):
|
||||
await shop_update_goods.finish("限时时间必须是数字啊!", at_sender=True)
|
||||
tmp["time"] = time.time() + tmp["time"] * 60
|
||||
if not tmp.get("name"):
|
||||
await shop_update_goods.finish("未指定商品名称(序号也可)!", at_sender=True)
|
||||
if is_number(tmp["name"]):
|
||||
tmp["name"] = int(tmp["name"])
|
||||
flag, name, text = await update_goods(tmp)
|
||||
if flag:
|
||||
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
|
||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {tmp} 成功")
|
||||
else:
|
||||
await shop_update_goods.send(f"修改商品 {name} 失败了...", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {tmp} 失败")
|
||||
@@ -1,126 +0,0 @@
|
||||
from ..models.goods_info import GoodsInfo
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
import nonebot
|
||||
import time
|
||||
import os
|
||||
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
# 导入内置商品 | 重新生成商店图片
|
||||
@driver.on_startup
|
||||
async def init_default_shop_goods():
|
||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
||||
if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
|
||||
await add_goods(["好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"])
|
||||
await add_goods(["好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)"])
|
||||
await add_goods(["好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"])
|
||||
|
||||
|
||||
# 创建商店界面
|
||||
async def create_shop_help():
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
tmp = ""
|
||||
idx = 1
|
||||
for goods in goods_lst:
|
||||
tmp += (
|
||||
f"{idx}.{goods.goods_name}\t\t售价:{goods.goods_price}金币\n"
|
||||
f"\t\t{goods.goods_description}\n"
|
||||
)
|
||||
idx += 1
|
||||
w = 1000
|
||||
h = 400 + len(goods_lst) * 40
|
||||
h = 1000 if h < 1000 else h
|
||||
shop_logo = CreateImg(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
|
||||
shop = CreateImg(w, h, font_size=20)
|
||||
zhenxun_img = CreateImg(525, 581, background=f"{IMAGE_PATH}/zhenxun/toukan_2.png")
|
||||
shop.paste(zhenxun_img, (780, 100))
|
||||
shop.paste(shop_logo, (450, 30), True)
|
||||
shop.text(
|
||||
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
|
||||
"注【通过 序号 或者 商品名称 购买】",
|
||||
)
|
||||
shop.text((20, 230), tmp[:-1])
|
||||
shop.text((20, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
|
||||
shop.save(f"{IMAGE_PATH}/shop_help.png")
|
||||
|
||||
|
||||
# 添加商品
|
||||
async def add_goods(msg: list):
|
||||
data = {
|
||||
"名称": None,
|
||||
"价格": None,
|
||||
"描述": None,
|
||||
"折扣": 1,
|
||||
"限时": 0,
|
||||
}
|
||||
keys = list(data.keys())
|
||||
idx = 0
|
||||
for x in msg:
|
||||
data[keys[idx]] = x
|
||||
idx += 1
|
||||
return await GoodsInfo.add_goods(
|
||||
data["名称"], data["价格"], data["描述"], data["折扣"], data["限时"]
|
||||
)
|
||||
|
||||
|
||||
# 删除商品
|
||||
async def del_goods(name: str, id_: int):
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
if id_:
|
||||
if id_ < 1 or id_ > len(goods_lst):
|
||||
return "序号错误,没有该序号商品...", "", 999
|
||||
goods_name = goods_lst[id_ - 1].goods_name
|
||||
if await GoodsInfo.delete_goods(goods_name):
|
||||
return f"删除商品 {goods_name} 成功!", goods_name, 200
|
||||
else:
|
||||
return f"删除商品 {goods_name} 失败!", goods_name, 999
|
||||
if name:
|
||||
if await GoodsInfo.delete_goods(name):
|
||||
return f"删除商品 {name} 成功!", name, 200
|
||||
else:
|
||||
return f"删除商品 {name} 失败!", name, 999
|
||||
|
||||
|
||||
# 更新商品信息
|
||||
async def update_goods(data: dict):
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
if is_number(data["name"]):
|
||||
if data["name"] < 1 or data["name"] > len(goods_lst):
|
||||
return "序号错误,没有该序号的商品...", "", 999
|
||||
goods = goods_lst[data["name"] - 1]
|
||||
else:
|
||||
goods = await GoodsInfo.get_goods_info(data["name"])
|
||||
if not goods:
|
||||
return "名称错误,没有该名称的商品...", "", 999
|
||||
name = goods.goods_name
|
||||
price = goods.goods_price
|
||||
des = goods.goods_description
|
||||
discount = goods.goods_discount
|
||||
limit_time = goods.goods_limit_time
|
||||
tmp = ""
|
||||
if data.get("price"):
|
||||
tmp += f'价格:{price} --> {data["price"]}\n'
|
||||
price = data["price"]
|
||||
if data.get("des"):
|
||||
tmp += f'描述:{des} --> {data["des"]}\n'
|
||||
des = data["des"]
|
||||
if data.get("discount"):
|
||||
tmp += f'折扣:{discount} --> {data["discount"]}\n'
|
||||
discount = data["discount"]
|
||||
if data.get("time"):
|
||||
old_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(limit_time))
|
||||
new_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(data["time"]))
|
||||
tmp += f"折扣:{old_time} --> {new_time}\n"
|
||||
limit_time = data["time"]
|
||||
return (
|
||||
await GoodsInfo.update_goods(name, price, des, discount, limit_time),
|
||||
name,
|
||||
tmp[:-1],
|
||||
)
|
||||
@@ -1,14 +0,0 @@
|
||||
from models.sign_group_user import SignGroupUser
|
||||
|
||||
|
||||
async def effect(user_id: int, group_id: int, name: str) -> bool:
|
||||
if name in ["好感双倍加持卡Ⅰ", "好感度双倍加持卡Ⅰ"]:
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.1).apply()
|
||||
if name in ["好感双倍加持卡Ⅱ", "好感度双倍加持卡Ⅱ"]:
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.2).apply()
|
||||
if name in ["好感双倍加持卡Ⅲ", "好感度双倍加持卡Ⅲ"]:
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.3).apply()
|
||||
return True
|
||||
+14
-18
@@ -3,6 +3,7 @@ from .group_user_checkin import (
|
||||
group_user_check,
|
||||
group_impression_rank,
|
||||
impression_rank,
|
||||
check_in_all
|
||||
)
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
@@ -27,14 +28,14 @@ usage:
|
||||
每日签到
|
||||
会影响色图概率和开箱次数,以及签到的随机道具获取
|
||||
指令:
|
||||
签到
|
||||
签到 ?[all]: all代表签到所有群
|
||||
我的签到
|
||||
好感度排行
|
||||
好感度总排行
|
||||
* 签到时有 3% 概率 * 2 *
|
||||
""".strip()
|
||||
__plugin_des__ = "每日签到,证明你在这里"
|
||||
__plugin_cmd__ = ["签到", "我的签到", "好感度排行", "好感度总排行"]
|
||||
__plugin_cmd__ = ["签到 ?[all]", "我的签到", "好感度排行", "好感度总排行"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
@@ -45,26 +46,18 @@ __plugin_settings__ = {
|
||||
}
|
||||
__plugin_cd_limit__ = {}
|
||||
__plugin_configs__ = {
|
||||
"MAX_SIGN_GOLD": {
|
||||
"value": 200,
|
||||
"help": "签到好感度加成额外获得的最大金币数",
|
||||
"default_value": 200
|
||||
},
|
||||
"SIGN_CARD1_PROB": {
|
||||
"value": 0.2,
|
||||
"help": "签到好感度双倍加持卡Ⅰ掉落概率",
|
||||
"default_value": 0.2
|
||||
},
|
||||
"MAX_SIGN_GOLD": {"value": 200, "help": "签到好感度加成额外获得的最大金币数", "default_value": 200},
|
||||
"SIGN_CARD1_PROB": {"value": 0.2, "help": "签到好感度双倍加持卡Ⅰ掉落概率", "default_value": 0.2},
|
||||
"SIGN_CARD2_PROB": {
|
||||
"value": 0.09,
|
||||
"help": "签到好感度双倍加持卡Ⅱ掉落概率",
|
||||
"default_value": 0.09
|
||||
"default_value": 0.09,
|
||||
},
|
||||
"SIGN_CARD3_PROB": {
|
||||
"value": 0.05,
|
||||
"help": "签到好感度双倍加持卡Ⅲ掉落概率",
|
||||
"default_value": 0.05
|
||||
}
|
||||
"default_value": 0.05,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +91,9 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await group_user_check_in(nickname, event.user_id, event.group_id),
|
||||
at_sender=True,
|
||||
)
|
||||
if get_message_text(event.json()) == "all":
|
||||
await check_in_all(nickname, event.user_id)
|
||||
|
||||
|
||||
|
||||
@my_sign.handle()
|
||||
@@ -142,12 +138,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
'interval',
|
||||
"interval",
|
||||
hours=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
clear_sign_data_pic()
|
||||
logger.info('清理日常签到图片数据数据完成....')
|
||||
logger.info("清理日常签到图片数据数据完成....")
|
||||
except Exception as e:
|
||||
logger.error(f'清理日常签到图片数据数据失败..{type(e)}: {e}')
|
||||
logger.error(f"清理日常签到图片数据数据失败..{type(e)}: {e}")
|
||||
|
||||
@@ -4,7 +4,7 @@ from models.group_member_info import GroupInfoUser
|
||||
from models.bag_user import BagUser
|
||||
from configs.config import NICKNAME
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from utils.image_utils import CreateImg, CreateMat
|
||||
from utils.image_utils import BuildImage, BuildMat
|
||||
from services.db_context import db
|
||||
from .utils import get_card, SIGN_TODAY_CARD_PATH
|
||||
from typing import Optional
|
||||
@@ -39,6 +39,26 @@ async def group_user_check_in(
|
||||
return await _handle_check_in(nickname, user_qq, group, present) # ok
|
||||
|
||||
|
||||
async def check_in_all(nickname: str, user_qq: int):
|
||||
"""
|
||||
说明:
|
||||
签到所有群
|
||||
参数:
|
||||
:param nickname: 昵称
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
async with db.transaction():
|
||||
present = datetime.now()
|
||||
for u in await SignGroupUser.get_user_all_data(user_qq):
|
||||
group = u.belonging_group
|
||||
if not ((
|
||||
u.checkin_time_last + timedelta(hours=8)
|
||||
).date() >= present.date() or f"{u}_{group}_sign_{datetime.now().date()}" in os.listdir(
|
||||
SIGN_TODAY_CARD_PATH
|
||||
)):
|
||||
await _handle_check_in(nickname, user_qq, group, present)
|
||||
|
||||
|
||||
async def _handle_check_in(
|
||||
nickname: str, user_qq: int, group: int, present: datetime
|
||||
) -> MessageSegment:
|
||||
@@ -58,6 +78,7 @@ async def _handle_check_in(
|
||||
await BagUser.add_gold(user_qq, group, gold + gift)
|
||||
gift = f"额外金币 + {gift}"
|
||||
else:
|
||||
await BagUser.add_gold(user_qq, group, gold)
|
||||
await BagUser.add_props(user_qq, group, gift)
|
||||
gift += ' + 1'
|
||||
if critx2 + add_probability > 0.97 or critx2 < specify_probability:
|
||||
@@ -83,7 +104,7 @@ async def group_user_check(nickname: str, user_qq: int, group: int) -> MessageSe
|
||||
return await get_card(user, nickname, None, gold, "", is_card_view=True)
|
||||
|
||||
|
||||
async def group_impression_rank(group: int, num: int) -> Optional[CreateMat]:
|
||||
async def group_impression_rank(group: int, num: int) -> Optional[BuildMat]:
|
||||
user_qq_list, impression_list, _ = await SignGroupUser.get_all_impression(group)
|
||||
return await init_rank("好感度排行榜", user_qq_list, impression_list, group, num)
|
||||
|
||||
@@ -140,9 +161,9 @@ async def _pst(users: list, impressions: list, groups: list):
|
||||
count = math.ceil(lens / 33)
|
||||
width = 10
|
||||
idx = 0
|
||||
A = CreateImg(1740, 3300, color="#FFE4C4")
|
||||
A = BuildImage(1740, 3300, color="#FFE4C4")
|
||||
for _ in range(count):
|
||||
col_img = CreateImg(550, 3300, 550, 100, color="#FFE4C4")
|
||||
col_img = BuildImage(550, 3300, 550, 100, color="#FFE4C4")
|
||||
for _ in range(33 if int(lens / 33) >= 1 else lens % 33 - 1):
|
||||
idx += 1
|
||||
if idx > 100:
|
||||
@@ -163,13 +184,13 @@ async def _pst(users: list, impressions: list, groups: list):
|
||||
user_name = user_name if len(user_name) < 11 else user_name[:10] + "..."
|
||||
ava = await get_user_avatar(user)
|
||||
if ava:
|
||||
ava = CreateImg(
|
||||
ava = BuildImage(
|
||||
50, 50, background=BytesIO(ava)
|
||||
)
|
||||
else:
|
||||
ava = CreateImg(50, 50, color="white")
|
||||
ava = BuildImage(50, 50, color="white")
|
||||
ava.circle()
|
||||
bk = CreateImg(550, 100, color="#FFE4C4", font_size=30)
|
||||
bk = BuildImage(550, 100, color="#FFE4C4", font_size=30)
|
||||
font_w, font_h = bk.getsize(f"{idx}")
|
||||
bk.text((5, int((100 - font_h) / 2)), f"{idx}.")
|
||||
bk.paste(ava, (55, int((100 - 50) / 2)), True)
|
||||
@@ -179,7 +200,7 @@ async def _pst(users: list, impressions: list, groups: list):
|
||||
A.paste(col_img, (width, 0))
|
||||
lens -= 33
|
||||
width += 580
|
||||
W = CreateImg(1740, 3700, color="#FFE4C4", font_size=130)
|
||||
W = BuildImage(1740, 3700, color="#FFE4C4", font_size=130)
|
||||
W.paste(A, (0, 260))
|
||||
font_w, font_h = W.getsize(f"{NICKNAME}的好感度总榜")
|
||||
W.text((int((1740 - font_w) / 2), int((260 - font_h) / 2)), f"{NICKNAME}的好感度总榜")
|
||||
|
||||
+30
-30
@@ -12,7 +12,7 @@ from models.sign_group_user import SignGroupUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from utils.utils import get_user_avatar
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.message_builder import image
|
||||
from configs.config import NICKNAME
|
||||
from pathlib import Path
|
||||
@@ -112,18 +112,18 @@ def _generate_card(
|
||||
is_double: bool = False,
|
||||
is_card_view: bool = False,
|
||||
) -> MessageSegment:
|
||||
ava_bk = CreateImg(140, 140, is_alpha=True)
|
||||
ava_border = CreateImg(
|
||||
ava_bk = BuildImage(140, 140, is_alpha=True)
|
||||
ava_border = BuildImage(
|
||||
140,
|
||||
140,
|
||||
background=SIGN_BORDER_PATH / "ava_border_01.png",
|
||||
)
|
||||
ava = CreateImg(102, 102, background=ava_bytes)
|
||||
ava = BuildImage(102, 102, background=ava_bytes)
|
||||
ava.circle()
|
||||
ava_bk.paste(ava, center_type="center")
|
||||
ava_bk.paste(ava_border, alpha=True, center_type="center")
|
||||
|
||||
info_img = CreateImg(250, 150, color=(255, 255, 255, 0), font_size=15)
|
||||
info_img = BuildImage(250, 150, color=(255, 255, 255, 0), font_size=15)
|
||||
level, next_impression, previous_impression = get_level_and_next_impression(
|
||||
user.impression
|
||||
)
|
||||
@@ -131,8 +131,8 @@ def _generate_card(
|
||||
info_img.text((0, 20), f"· {NICKNAME}对你的态度:{level2attitude[level]}")
|
||||
info_img.text((0, 40), f"· 距离升级还差 {next_impression - user.impression:.2f} 好感度")
|
||||
|
||||
bar_bk = CreateImg(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png")
|
||||
bar = CreateImg(220, 20, background=SIGN_RESOURCE_PATH / "bar.png")
|
||||
bar_bk = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png")
|
||||
bar = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar.png")
|
||||
bar_bk.paste(
|
||||
bar,
|
||||
(
|
||||
@@ -150,7 +150,7 @@ def _generate_card(
|
||||
font_size = 30
|
||||
if "好感度双倍加持卡" in gift:
|
||||
font_size = 20
|
||||
gift_border = CreateImg(
|
||||
gift_border = BuildImage(
|
||||
270,
|
||||
100,
|
||||
background=SIGN_BORDER_PATH / "gift_border_02.png",
|
||||
@@ -158,20 +158,20 @@ def _generate_card(
|
||||
)
|
||||
gift_border.text((0, 0), gift, center_type="center")
|
||||
|
||||
bk = CreateImg(
|
||||
bk = BuildImage(
|
||||
876,
|
||||
424,
|
||||
background=SIGN_BACKGROUND_PATH
|
||||
/ random.choice(os.listdir(SIGN_BACKGROUND_PATH)),
|
||||
font_size=25,
|
||||
)
|
||||
A = CreateImg(876, 274, background=SIGN_RESOURCE_PATH / "white.png")
|
||||
line = CreateImg(2, 180, color="black")
|
||||
A = BuildImage(876, 274, background=SIGN_RESOURCE_PATH / "white.png")
|
||||
line = BuildImage(2, 180, color="black")
|
||||
A.transparent(2)
|
||||
A.paste(ava_bk, (25, 80), True)
|
||||
A.paste(line, (200, 70))
|
||||
|
||||
nickname_img = CreateImg(
|
||||
nickname_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=nickname,
|
||||
@@ -184,7 +184,7 @@ def _generate_card(
|
||||
uid = uid[:4] + " " + uid[4:8] + " " + uid[8:]
|
||||
else:
|
||||
uid = "XXXX XXXX XXXX"
|
||||
uid_img = CreateImg(
|
||||
uid_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"UID: {uid}",
|
||||
@@ -192,7 +192,7 @@ def _generate_card(
|
||||
font_size=30,
|
||||
font_color=(255, 255, 255),
|
||||
)
|
||||
sign_day_img = CreateImg(
|
||||
sign_day_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"{user.checkin_count}",
|
||||
@@ -200,17 +200,17 @@ def _generate_card(
|
||||
font_size=40,
|
||||
font_color=(211, 64, 33),
|
||||
)
|
||||
lik_text1_img = CreateImg(
|
||||
lik_text1_img = BuildImage(
|
||||
0, 0, plain_text="当前", color=(255, 255, 255, 0), font_size=20
|
||||
)
|
||||
lik_text2_img = CreateImg(
|
||||
lik_text2_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"好感度:{user.impression:.2f}",
|
||||
color=(255, 255, 255, 0),
|
||||
font_size=30,
|
||||
)
|
||||
watermark = CreateImg(
|
||||
watermark = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"{NICKNAME}@{datetime.now().year}",
|
||||
@@ -218,15 +218,15 @@ def _generate_card(
|
||||
font_size=15,
|
||||
font_color=(155, 155, 155),
|
||||
)
|
||||
today_data = CreateImg(300, 300, color=(255, 255, 255, 0), font_size=20)
|
||||
today_data = BuildImage(300, 300, color=(255, 255, 255, 0), font_size=20)
|
||||
if is_card_view:
|
||||
today_sign_text_img = CreateImg(
|
||||
today_sign_text_img = BuildImage(
|
||||
0, 0, plain_text="", color=(255, 255, 255, 0), font_size=30
|
||||
)
|
||||
if impression_list:
|
||||
impression_list.sort(reverse=True)
|
||||
index = impression_list.index(user.impression)
|
||||
rank_img = CreateImg(
|
||||
rank_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"* 此群好感排名第 {index + 1} 位",
|
||||
@@ -247,7 +247,7 @@ def _generate_card(
|
||||
_type = "view"
|
||||
else:
|
||||
A.paste(gift_border, (570, 140), True)
|
||||
today_sign_text_img = CreateImg(
|
||||
today_sign_text_img = BuildImage(
|
||||
0, 0, plain_text="今日签到", color=(255, 255, 255, 0), font_size=30
|
||||
)
|
||||
if is_double:
|
||||
@@ -262,7 +262,7 @@ def _generate_card(
|
||||
hour = current_date.hour
|
||||
minute = current_date.minute
|
||||
second = current_date.second
|
||||
data_img = CreateImg(
|
||||
data_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"时间:{data} {weekdays[week]} {hour}:{minute}:{second}",
|
||||
@@ -296,14 +296,14 @@ def generate_progress_bar_pic():
|
||||
bg_2 = (254, 1, 254)
|
||||
bg_1 = (0, 245, 246)
|
||||
|
||||
bk = CreateImg(1000, 50, is_alpha=True)
|
||||
img_x = CreateImg(50, 50, color=bg_2)
|
||||
bk = BuildImage(1000, 50, is_alpha=True)
|
||||
img_x = BuildImage(50, 50, color=bg_2)
|
||||
img_x.circle()
|
||||
img_x.crop((25, 0, 50, 50))
|
||||
img_y = CreateImg(50, 50, color=bg_1)
|
||||
img_y = BuildImage(50, 50, color=bg_1)
|
||||
img_y.circle()
|
||||
img_y.crop((0, 0, 25, 50))
|
||||
A = CreateImg(950, 50)
|
||||
A = BuildImage(950, 50)
|
||||
width, height = A.size
|
||||
|
||||
step_r = (bg_2[0] - bg_1[0]) / width
|
||||
@@ -321,12 +321,12 @@ def generate_progress_bar_pic():
|
||||
bk.paste(img_x, (975, 0), True)
|
||||
bk.save(SIGN_RESOURCE_PATH / "bar.png")
|
||||
|
||||
A = CreateImg(950, 50)
|
||||
bk = CreateImg(1000, 50, is_alpha=True)
|
||||
img_x = CreateImg(50, 50)
|
||||
A = BuildImage(950, 50)
|
||||
bk = BuildImage(1000, 50, is_alpha=True)
|
||||
img_x = BuildImage(50, 50)
|
||||
img_x.circle()
|
||||
img_x.crop((25, 0, 50, 50))
|
||||
img_y = CreateImg(50, 50)
|
||||
img_y = BuildImage(50, 50)
|
||||
img_y.circle()
|
||||
img_y.crop((0, 0, 25, 50))
|
||||
bk.paste(img_y, (0, 0), True)
|
||||
|
||||
@@ -5,7 +5,7 @@ from nonebot.typing import T_State
|
||||
from pathlib import Path
|
||||
from configs.path_config import DATA_PATH, IMAGE_PATH
|
||||
from utils.utils import get_message_text
|
||||
from utils.image_utils import CreateMat
|
||||
from utils.image_utils import BuildMat
|
||||
from utils.message_builder import image
|
||||
from utils.manager import plugins2settings_manager
|
||||
import asyncio
|
||||
@@ -202,7 +202,7 @@ async def generate_statistics_img(
|
||||
except KeyError:
|
||||
count.append(0)
|
||||
week_lst = ["7" if i == "0" else i for i in week_lst]
|
||||
bar_graph = CreateMat(
|
||||
bar_graph = BuildMat(
|
||||
y=count,
|
||||
mat_type="line",
|
||||
title=f"{name} 周 {plugin} 功能调用统计【为7天统计】",
|
||||
@@ -226,7 +226,7 @@ async def generate_statistics_img(
|
||||
day_lst.append(i)
|
||||
count = [data[str(day_lst[i])][plugin] for i in range(30)]
|
||||
day_lst = [str(x + 1) for x in day_lst]
|
||||
bar_graph = CreateMat(
|
||||
bar_graph = BuildMat(
|
||||
y=count,
|
||||
mat_type="line",
|
||||
title=f"{name} 月 {plugin} 功能调用统计【为30天统计】",
|
||||
@@ -246,12 +246,12 @@ async def generate_statistics_img(
|
||||
return bar_graph.pic2bs4()
|
||||
|
||||
|
||||
async def init_bar_graph(data: dict, title: str) -> CreateMat:
|
||||
async def init_bar_graph(data: dict, title: str) -> BuildMat:
|
||||
return await asyncio.get_event_loop().run_in_executor(None, _init_bar_graph, data, title)
|
||||
|
||||
|
||||
def _init_bar_graph(data: dict, title: str) -> CreateMat:
|
||||
bar_graph = CreateMat(
|
||||
def _init_bar_graph(data: dict, title: str) -> BuildMat:
|
||||
bar_graph = BuildMat(
|
||||
y=[data[x] for x in data.keys() if data[x] != 0],
|
||||
mat_type="barh",
|
||||
title=title,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user