update 0.0.7.0
158
README.md
@ -20,7 +20,7 @@
|
||||
|
||||
## 未完成的文档
|
||||
|
||||
[传送门](https://hibikier.github.io/zhenxun_bot/)
|
||||
<h1>[传送门](https://hibikier.github.io/zhenxun_bot/)</h1>
|
||||
|
||||
## 真寻的帮助
|
||||
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
|
||||
@ -51,9 +51,11 @@
|
||||
- [x] 商店/我的金币/购买道具/使用道具
|
||||
- [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
|
||||
- [x] 我有一个朋友想问问..(借鉴pcrbot插件)
|
||||
- [x] 原神黄历 (使用[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
|
||||
- [x] 原神黄历
|
||||
- [x] 原神今日素材
|
||||
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
|
||||
- [x] 原神便笺查询
|
||||
- [x] 原神玩家查询
|
||||
- [x] 金币红包
|
||||
- [x] 微博热搜
|
||||
- [x] B站主播/UP/番剧订阅
|
||||
@ -89,6 +91,8 @@
|
||||
- [x] 通过PID获取图片
|
||||
- [x] 功能统计可视化
|
||||
|
||||
- [x] 关于
|
||||
|
||||
### 已实现的管理员功能
|
||||
- [x] 更新群组成员信息
|
||||
- [x] 95%的群功能开关
|
||||
@ -101,6 +105,7 @@
|
||||
- [x] 删除图片 (同上)
|
||||
- [x] 群内B站订阅
|
||||
- [x] 群词条
|
||||
- [x] 休息吧/醒来
|
||||
|
||||
### 已实现的超级用户功能
|
||||
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
|
||||
@ -126,6 +131,11 @@
|
||||
- [x] 功能开关(更多设置)
|
||||
- [x] 功能状态
|
||||
- [x] b了
|
||||
- [x] 执行sql
|
||||
- [x] 重载配置
|
||||
- [x] 清理临时数据
|
||||
- [x] 增删群认证
|
||||
- [x] 同意/拒绝好友/群聊请求
|
||||
|
||||
#### 超级用户的被动技能
|
||||
- [x] 邀请入群提醒(别人邀请真寻入群)
|
||||
@ -152,127 +162,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,6 +210,29 @@ python bot.py
|
||||
|
||||
## 更新
|
||||
|
||||
### 2021/12/16 \[v0.0.7.0]
|
||||
|
||||
* 提供了真寻群聊功能总开关和对应默认配置项,命令:休息吧 醒来
|
||||
* 新增原神玩家查询,原神便笺查询
|
||||
* 群功能管理提供全部开启/关闭命令:开启/关闭全部功能
|
||||
* 提供主要数据自动备份,且提供自定义配置项
|
||||
* 提供命令:关于,用于介绍Bot之类的
|
||||
* 新增命令exec,用于执行sql语句
|
||||
* 签到提供参数 "all",用于签到所有群聊
|
||||
* Ban提醒提供cd
|
||||
* 本地图库提供配置项SHOW_ID,用于设置发送图片时是否显示id
|
||||
* 色图和PIX提供配置项SHOW_INFO,用于设置发送图片时是否显示图片信息
|
||||
* 所有被动技能提供了进群默认状态配置项
|
||||
|
||||
* 修复添加权限第二种添加形式无法正确添加正确的权限
|
||||
* 修复签到获取好感度卡时金币不会增加
|
||||
* 修复当红包数量不合法时依旧扣除金币
|
||||
* 修复金币红包再次使用塞红包时无法正确退回上次未开完的金币
|
||||
* 修复 滴滴滴- 只包含图片时不会发送至管理员
|
||||
|
||||
* 修改了权限插件加载顺序防止小概率优先加载权限插件引起报错
|
||||
* 本地图库新图库会统一建立在resource/img/image_management文件夹下,如果该文件夹内未找到图库,会从上级目录查找(即:resource/img/)
|
||||
|
||||
### 2021/12/1 \[v0.0.6.5/6]
|
||||
|
||||
* 群权限-1时超级用户命令依旧生效
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -13,7 +13,7 @@ from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
PokeNotifyEvent,
|
||||
PokeNotifyEvent
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
@ -37,16 +37,19 @@ 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
|
||||
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)
|
||||
@ -59,10 +62,19 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
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):
|
||||
# 个人权限
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -25,7 +25,7 @@ __plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_configs__ = {
|
||||
"BLACK_WORD": {
|
||||
"value": ["爸", "妈", "爹", "爷"],
|
||||
"value": ["爸", "爹", "爷"],
|
||||
"help": "昵称所屏蔽的关键词,会被替换为 *",
|
||||
"default_value": None
|
||||
}
|
||||
|
||||
38
basic_plugins/super_cmd/exec_sql.py
Normal file
@ -0,0 +1,38 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from services.db_context import db
|
||||
from utils.utils import get_message_text
|
||||
from services.log import logger
|
||||
|
||||
__zx_plugin_name__ = "执行sql [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
执行一段sql语句
|
||||
指令:
|
||||
exec [sql语句]
|
||||
""".strip()
|
||||
__plugin_des__ = "执行一段sql语句"
|
||||
__plugin_cmd__ = [
|
||||
"exec [sql语句]",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
exec_ = on_command("exec", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
|
||||
@exec_.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
sql = get_message_text(event.json())
|
||||
async with db.transaction():
|
||||
try:
|
||||
query = db.text(sql)
|
||||
await db.first(query)
|
||||
await exec_.send("执行 sql 语句成功.")
|
||||
except Exception as e:
|
||||
await exec_.send(f"执行 sql 语句失败 {type(e)}:{e}")
|
||||
logger.error(f"执行 sql 语句失败 {type(e)}:{e}")
|
||||
@ -40,7 +40,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
group_id = -1
|
||||
level = 0
|
||||
try:
|
||||
args = get_message_text(event.json()).strip().split()
|
||||
args = get_message_text(event.json()).split()
|
||||
qq = get_message_at(event.json())
|
||||
flag = -1
|
||||
if not qq:
|
||||
@ -55,7 +55,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
else:
|
||||
await super_cmd.finish(
|
||||
"权限参数不完全\n\t格式:添加/删除权限 [at] [level]"
|
||||
"\n\t格式:添加/删除权限 [qq] [group] [level]",
|
||||
"\n\t格式:添加/删除权限 [qq] [group_id] [level]",
|
||||
at_sender=True,
|
||||
)
|
||||
else:
|
||||
@ -63,10 +63,6 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
group_id = event.group_id
|
||||
flag = 2
|
||||
if state["_prefix"]["raw_command"][:2] == "添加":
|
||||
if is_number(args[0]):
|
||||
level = int(args[0])
|
||||
else:
|
||||
await super_cmd.finish("权限等级必须是数字!", at_sender=True)
|
||||
if await LevelUser.set_level(qq, group_id, level, 1):
|
||||
result = "添加管理成功, 权限: " + str(level)
|
||||
else:
|
||||
|
||||
@ -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)
|
||||
|
||||
4
bot.py
@ -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__":
|
||||
|
||||
@ -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]
|
||||
|
||||
|
||||
@ -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 ""
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
45
plugins/about.py
Normal file
@ -0,0 +1,45 @@
|
||||
from nonebot import on_regex
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
__zx_plugin_name__ = "关于"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
想要更加了解真寻吗
|
||||
指令:
|
||||
关于
|
||||
""".strip()
|
||||
__plugin_des__ = "想要更加了解真寻吗"
|
||||
__plugin_cmd__ = ["关于"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_type__ = ("其他",)
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 1,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["关于"],
|
||||
}
|
||||
|
||||
|
||||
about = on_regex("^关于$", priority=5, block=True, rule=to_me())
|
||||
|
||||
|
||||
@about.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
ver_file = Path() / '__version__'
|
||||
version = None
|
||||
if ver_file.exists():
|
||||
with open(ver_file, 'r', encoding='utf8') as f:
|
||||
version = f.read().split(':')[-1].strip()
|
||||
msg = f"""
|
||||
『绪山真寻Bot』
|
||||
版本:{version}
|
||||
简介:基于Nonebot2与go-cqhttp开发,是一个非常可爱的Bot呀,希望与大家要好好相处
|
||||
项目地址:https://github.com/HibiKier/zhenxun_bot
|
||||
文档地址:https://hibikier.github.io/zhenxun_bot/
|
||||
""".strip()
|
||||
await about.send(msg)
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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}")
|
||||
|
||||
@ -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,7 +2,7 @@ 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
|
||||
@ -131,12 +131,12 @@ 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
|
||||
@ -154,8 +154,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])
|
||||
|
||||
@ -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)
|
||||
|
||||
26
plugins/genshin/query_user/__init__.py
Normal file
@ -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")
|
||||
|
||||
|
||||
|
||||
97
plugins/genshin/query_user/bind/__init__.py
Normal file
@ -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]
|
||||
示例:原神绑定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/登录后按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("该用户数据不存在..")
|
||||
210
plugins/genshin/query_user/models/__init__.py
Normal file
@ -0,0 +1,210 @@
|
||||
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")
|
||||
print(uid, cookie)
|
||||
if not cookie and not flag:
|
||||
cookie = await cls.get_query_cookie(uid)
|
||||
print(uid, cookie)
|
||||
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()
|
||||
53
plugins/genshin/query_user/query_memo/__init__.py
Normal file
@ -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("未查询到数据...")
|
||||
|
||||
|
||||
|
||||
|
||||
237
plugins/genshin/query_user/query_memo/data_source.py
Normal file
@ -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.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())
|
||||
61
plugins/genshin/query_user/query_role/__init__.py
Normal file
@ -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("查询失败..")
|
||||
|
||||
|
||||
|
||||
|
||||
249
plugins/genshin/query_user/query_role/data_source.py
Normal file
@ -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)
|
||||
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.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
|
||||
530
plugins/genshin/query_user/query_role/draw_image.py
Normal file
@ -0,0 +1,530 @@
|
||||
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):
|
||||
"""
|
||||
下载头像
|
||||
:param char_data_list: 角色列表
|
||||
:param char_detailed_dict: 角色武器
|
||||
"""
|
||||
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
|
||||
)
|
||||
@ -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}")
|
||||
|
||||
35
plugins/genshin/query_user/utils/__init__.py
Normal file
@ -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": "无",
|
||||
}
|
||||
@ -115,6 +115,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,11 +138,11 @@ 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']
|
||||
num = int(num)
|
||||
if num > group_member_num:
|
||||
|
||||
@ -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,7 +17,7 @@ try:
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
__zx_plugin_name__ = "发送本地图库图片"
|
||||
__zx_plugin_name__ = "本地图库"
|
||||
__plugin_usage__ = f"""
|
||||
usage:
|
||||
发送指定图库下的随机或指定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|")
|
||||
|
||||
|
||||
@ -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':
|
||||
|
||||
@ -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 ''}"
|
||||
|
||||
|
||||
# 罗翔老师!
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
from ..models.goods_info import GoodsInfo
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from configs.config import Config
|
||||
@ -37,9 +37,9 @@ async def create_shop_help():
|
||||
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_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
|
||||
shop = BuildImage(w, h, font_size=20)
|
||||
zhenxun_img = BuildImage(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(
|
||||
|
||||
@ -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
|
||||
@ -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:
|
||||
@ -84,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)
|
||||
|
||||
@ -141,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:
|
||||
@ -164,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)
|
||||
@ -180,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}的好感度总榜")
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -9,7 +9,7 @@ from nonebot.typing import T_State
|
||||
from utils.utils import get_message_imgs
|
||||
from pathlib import Path
|
||||
from utils.utils import is_number, get_message_text
|
||||
from utils.image_utils import CreateImg, pic2b64
|
||||
from utils.image_utils import BuildImage, pic2b64
|
||||
from configs.config import NICKNAME
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import cv2
|
||||
@ -83,7 +83,7 @@ for i in range(len(method_list)):
|
||||
method_oper.append(method_list[i])
|
||||
method_oper.append(str(i + 1))
|
||||
|
||||
update_img_help = CreateImg(960, 700, font_size=24)
|
||||
update_img_help = BuildImage(960, 700, font_size=24)
|
||||
update_img_help.text((10, 10), __plugin_usage__)
|
||||
update_img_help.save(IMAGE_PATH + "update_img_help.png")
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ from nonebot import on_command
|
||||
from utils.utils import get_message_imgs, get_message_text, is_chinese
|
||||
from utils.message_builder import image
|
||||
from configs.path_config import TEMP_PATH
|
||||
from utils.image_utils import CreateImg
|
||||
from utils.image_utils import BuildImage
|
||||
from services.log import logger
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from pathlib import Path
|
||||
@ -57,12 +57,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
):
|
||||
await w2b_img.finish("下载图片失败...请稍后再试...")
|
||||
msg = await get_translate(msg)
|
||||
w2b = CreateImg(0, 0, background=Path(TEMP_PATH) / f"{event.user_id}_w2b.png")
|
||||
w2b = BuildImage(0, 0, background=Path(TEMP_PATH) / f"{event.user_id}_w2b.png")
|
||||
w2b.convert("L")
|
||||
msg_sp = msg.split("<|>")
|
||||
w, h = w2b.size
|
||||
add_h, font_size = init_h_font_size(h)
|
||||
bg = CreateImg(w, h + add_h, color="black", font_size=font_size)
|
||||
bg = BuildImage(w, h + add_h, color="black", font_size=font_size)
|
||||
bg.paste(w2b)
|
||||
chinese_msg = formalization_msg(msg)
|
||||
if not bg.check_font_size(chinese_msg):
|
||||
@ -84,7 +84,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
)
|
||||
|
||||
|
||||
def centered_text(img: CreateImg, text: str, add_h: int):
|
||||
def centered_text(img: BuildImage, text: str, add_h: int):
|
||||
top_h = img.h - add_h + (img.h / 100)
|
||||
bottom_h = img.h - (img.h / 100)
|
||||
text_sp = text.split("<|>")
|
||||
|
||||
@ -59,11 +59,11 @@ show_word = on_command("显示词条", aliases={"查看词条"}, priority=5, blo
|
||||
@add_word.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
r = re.search(r"^问(.+)\s?答(.*)", msg)
|
||||
r = re.search(r"^问(.+)\s?答([\s\S]*)", msg)
|
||||
if not r:
|
||||
await add_word.finish("未检测到词条问题...")
|
||||
problem = r.group(1).strip()
|
||||
answer = r.group(2).strip()
|
||||
answer = msg.split('答', maxsplit=1)[-1]
|
||||
if not answer:
|
||||
await add_word.finish("未检测到词条回答...")
|
||||
idx = 0
|
||||
|
||||
@ -54,4 +54,4 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情失败"
|
||||
)
|
||||
else:
|
||||
await yiqing.send(f"{NICKNAME}只支持国内的疫情查询喔...")
|
||||
await yiqing.send(f"{NICKNAME}没有查到{msg}的疫情查询...")
|
||||
|
||||
BIN
resources/img/genshin/genshin_card/chars_ava/10000002.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000003.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000005.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000006.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000007.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000014.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000015.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000016.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000020.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000021.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000022.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000023.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000024.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000025.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000026.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000027.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000029.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000030.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000031.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000032.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000033.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000034.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
resources/img/genshin/genshin_card/chars_ava/10000035.png
Normal file
|
After Width: | Height: | Size: 39 KiB |