mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-03 19:00:00 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f32d8b4eff | ||
|
|
685f2b8c53 | ||
|
|
1e63ca2549 | ||
|
|
c1bc4eff2b | ||
|
|
bc903d3813 | ||
|
|
80fc17b610 | ||
|
|
0efb2bbc60 | ||
|
|
4cb91b47e6 | ||
|
|
30b56583bd | ||
|
|
5e5168f804 | ||
|
|
4a8122829e | ||
|
|
52ba2cf89a | ||
|
|
58957cdf44 | ||
|
|
71f860a500 | ||
|
|
9b4cde819e | ||
|
|
99637de1de | ||
|
|
19dbd3f2b0 | ||
|
|
7567794f74 | ||
|
|
df0d15c1b3 | ||
|
|
9a84c02bb5 | ||
|
|
e623c4f30f | ||
|
|
3fd7acffb2 | ||
|
|
71f8c16c26 | ||
|
|
b64699c4ab | ||
|
|
786d62bb2f | ||
|
|
ac48d3d542 | ||
|
|
c4d9523ec2 |
+4
-1
@@ -142,4 +142,7 @@ test.py
|
|||||||
server.py
|
server.py
|
||||||
member_activity_handle.py
|
member_activity_handle.py
|
||||||
Yu-Gi-Oh/
|
Yu-Gi-Oh/
|
||||||
|
search_image/
|
||||||
|
black_word/
|
||||||
|
csgo/
|
||||||
|
fantasy_card/
|
||||||
|
|||||||
@@ -18,17 +18,31 @@
|
|||||||
## 声明
|
## 声明
|
||||||
此项目仅用于学习交流,请勿用于非法用途
|
此项目仅用于学习交流,请勿用于非法用途
|
||||||
|
|
||||||
|
## Gitee同步
|
||||||
|
# [Gitee](https://gitee.com/two_Dimension/zhenxun_bot)
|
||||||
|
|
||||||
## 未完成的文档
|
## 未完成的文档
|
||||||
|
|
||||||
[传送门](https://hibikier.github.io/zhenxun_bot/)
|
# [传送门](https://hibikier.github.io/zhenxun_bot/)
|
||||||
|
|
||||||
## 真寻的帮助
|
## 真寻的帮助
|
||||||
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
|
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
|
||||||
|
|
||||||
|
## 普通帮助图片
|
||||||
|

|
||||||
|
|
||||||
## 提供符合真寻标准的插件仓库
|
## 提供符合真寻标准的插件仓库
|
||||||
|
|
||||||
[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
|
[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
|
||||||
|
|
||||||
|
## 来点优点?
|
||||||
|
一.作为bot:
|
||||||
|
* 实现了许多功能,且提供了大量功能管理命令
|
||||||
|
* 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改
|
||||||
|
* 方便增删插件,原生nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
|
||||||
|
* 提供了cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`__plugin_cd_limit__`
|
||||||
|
* __..... 更多详细请通过`传送门`查看文档!__
|
||||||
|
|
||||||
|
|
||||||
## 功能列表
|
## 功能列表
|
||||||
<details>
|
<details>
|
||||||
@@ -56,6 +70,8 @@
|
|||||||
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
|
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
|
||||||
- [x] 原神便笺查询
|
- [x] 原神便笺查询
|
||||||
- [x] 原神玩家查询
|
- [x] 原神玩家查询
|
||||||
|
- [x] 原神树脂提醒
|
||||||
|
- [x] 原神签到/自动签到
|
||||||
- [x] 金币红包
|
- [x] 金币红包
|
||||||
- [x] 微博热搜
|
- [x] 微博热搜
|
||||||
- [x] B站主播/UP/番剧订阅
|
- [x] B站主播/UP/番剧订阅
|
||||||
@@ -136,6 +152,7 @@
|
|||||||
- [x] 清理临时数据
|
- [x] 清理临时数据
|
||||||
- [x] 增删群认证
|
- [x] 增删群认证
|
||||||
- [x] 同意/拒绝好友/群聊请求
|
- [x] 同意/拒绝好友/群聊请求
|
||||||
|
- [x] 配置重载
|
||||||
|
|
||||||
#### 超级用户的被动技能
|
#### 超级用户的被动技能
|
||||||
- [x] 邀请入群提醒(别人邀请真寻入群)
|
- [x] 邀请入群提醒(别人邀请真寻入群)
|
||||||
@@ -160,6 +177,7 @@
|
|||||||
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
|
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
|
||||||
- [x] 群权限系统
|
- [x] 群权限系统
|
||||||
- [x] 定时更新权限
|
- [x] 定时更新权限
|
||||||
|
- [x] 自动配置重载
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
|
## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
|
||||||
@@ -206,10 +224,75 @@ python bot.py
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 使用Docker
|
||||||
|
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
||||||
|
#### GitHub:[Sakuracio/zxenv](https://github.com/Sakuracio/zxenv)
|
||||||
|
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 更新
|
## 更新
|
||||||
|
|
||||||
|
### 2021/2/10 \[v0.1.1]
|
||||||
|
|
||||||
|
* 修复购买道具出错
|
||||||
|
|
||||||
|
### 2021/2/9 \[v0.1]
|
||||||
|
|
||||||
|
* 新增原神自动签到和手动签到
|
||||||
|
* 新增原神树脂提醒
|
||||||
|
* 新增手动重载Config.yaml命令以及重载配置定时任务(极少部分帮助或配置可能需要重启
|
||||||
|
* 修改了发送本地图库的matcher,改为on_message
|
||||||
|
* register_use可以通过返回值发送消息
|
||||||
|
* 修复修改商品时限制时间出错
|
||||||
|
* 修复超时商品依旧可以被购买
|
||||||
|
|
||||||
|
### 2021/1/16 \[v0.0.9.0]
|
||||||
|
|
||||||
|
* Ai提供文本敏感词过滤器
|
||||||
|
* 疫情插件适配新版腾讯API
|
||||||
|
* 修复/t回复带空格切分
|
||||||
|
* 修复原神玩家查询缺少渊下宫和稻妻家园以及角色不完全
|
||||||
|
* 修复方法 text2image 中 padding 和 font 无法对纯文本生效
|
||||||
|
* 修复签到图片中信息并未使用配置文件中的色图概率
|
||||||
|
* 修改原神大地图合成方式,改为先压缩再合成
|
||||||
|
* bag_user弃用字段props(该字段会在下次更新删除),使用新字段property
|
||||||
|
* 数据库中所有belonging_group统一修改为group_id
|
||||||
|
* 商店将registered_use和register_goods更名为register_use何register_goods
|
||||||
|
* 商品注册提供了kwargs参数提供:
|
||||||
|
* bot
|
||||||
|
* event
|
||||||
|
* 特殊字段
|
||||||
|
* “send_success_msg”(发送成功的交互信息->即:使用道具 {name} {num} 次成功)
|
||||||
|
* “_max_num_limit”(该道具单次使用的最多个数,默认1)
|
||||||
|
|
||||||
|
### 2021/1/5 \[v0.0.8.2]
|
||||||
|
|
||||||
|
* 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币
|
||||||
|
* 商店插件将作为内置插件移动至basic_plugins
|
||||||
|
* 商店插件通过export提供了方法,不需要修改商店插件代码添加商品数据和生效方法
|
||||||
|
* 修改了hook插件顺序,主要以auth_hook为主
|
||||||
|
* 修改商店图片样式
|
||||||
|
* 取消每次启动更新城市列表(首次除外),采用定时更新,加快bot启动速度
|
||||||
|
* 取消每次启动时截取今日素材,采用调用时截取保存,加快bot启动速度
|
||||||
|
* 更新色图时当图片404时会删除并替换
|
||||||
|
* 疫情消息回复改为图片
|
||||||
|
* 修复商店折扣和限时时间无法生效
|
||||||
|
* 修复原神玩家查询尘歌壶缺少图片
|
||||||
|
|
||||||
|
### 2021/12/26
|
||||||
|
|
||||||
|
* 修复群词条问题 空格 会被录入导致不断回复
|
||||||
|
* 修复米游社app替换api导致无法正常查询
|
||||||
|
|
||||||
|
### 2021/12/24
|
||||||
|
|
||||||
|
* 支持国际疫情数据查询 [@pull/99](https://github.com/HibiKier/zhenxun_bot/pull/99)
|
||||||
|
|
||||||
|
### 2021/12/20
|
||||||
|
|
||||||
|
* 只有发布小于存储时间的新动态/视频的时候才获取并推送 [@pull/96](https://github.com/HibiKier/zhenxun_bot/pull/96)
|
||||||
|
|
||||||
### 2021/12/16 \[v0.0.7.0]
|
### 2021/12/16 \[v0.0.7.0]
|
||||||
|
|
||||||
* 提供了真寻群聊功能总开关和对应默认配置项,命令:休息吧 醒来
|
* 提供了真寻群聊功能总开关和对应默认配置项,命令:休息吧 醒来
|
||||||
@@ -228,370 +311,31 @@ python bot.py
|
|||||||
* 修复当红包数量不合法时依旧扣除金币
|
* 修复当红包数量不合法时依旧扣除金币
|
||||||
* 修复金币红包再次使用塞红包时无法正确退回上次未开完的金币
|
* 修复金币红包再次使用塞红包时无法正确退回上次未开完的金币
|
||||||
* 修复 滴滴滴- 只包含图片时不会发送至管理员
|
* 修复 滴滴滴- 只包含图片时不会发送至管理员
|
||||||
|
* 修复添加权限等级错误
|
||||||
* 修复群词条以bot名称为开头时无法正确触发
|
* 修复群词条以bot名称为开头时无法正确触发
|
||||||
* 修改了权限插件加载顺序防止小概率优先加载权限插件引起报错
|
* 修改了权限插件加载顺序防止小概率优先加载权限插件引起报错
|
||||||
* 本地图库新图库会统一建立在resource/img/image_management文件夹下,如果该文件夹内未找到图库,会从上级目录查找(即:resource/img/)
|
* 本地图库新图库会统一建立在resource/img/image_management文件夹下,如果该文件夹内未找到图库,会从上级目录查找(即:resource/img/)
|
||||||
|
|
||||||
### 2021/12/1 \[v0.0.6.5/6]
|
<br>
|
||||||
|
|
||||||
* 群权限-1时超级用户命令依旧生效
|
__..... 更多更新信息请查看文档__
|
||||||
* 修复以真寻为开头的词条不会被回复
|
|
||||||
* 修复购买道具可以为负数
|
|
||||||
* P站排行/搜图提供配置项,将略过大于指定张数的作品
|
|
||||||
* 昵称提供关键词屏蔽配置项,会将指定关键词替换为“*”
|
|
||||||
* 取消了自动更新,改为自动检测版本
|
|
||||||
* 自动更新不再覆盖config.py和移动config.yaml
|
|
||||||
|
|
||||||
### 2021/11/29 \[v0.0.6.4]
|
|
||||||
|
|
||||||
* 新增cos图撤回配置项
|
|
||||||
* 新增默认群权限配置项
|
|
||||||
* 修复权限等级类配置无法正常应用
|
|
||||||
|
|
||||||
### 2021/11/24 \[v0.0.6.3]
|
|
||||||
|
|
||||||
* 修复在线搜索色图出错
|
|
||||||
* 修复pix无法正确获取HIBIAPI
|
|
||||||
|
|
||||||
### 2021/11/23 \[v0.0.6.2]
|
|
||||||
|
|
||||||
* 替换cos API
|
|
||||||
* 提供私聊b了,即跨群b了用户
|
|
||||||
* 修复游戏抽卡导入角色失败(原神)
|
|
||||||
* 修复无Pixiv代理时报错
|
|
||||||
* 将项目中大部分aiohttp替换为httpx
|
|
||||||
* 删除了丘丘人翻译插件
|
|
||||||
* 新增群词条
|
|
||||||
* 修复游戏抽卡碧蓝航线bwiki格式更改导致获取报错
|
|
||||||
* 首次启动会生成配置文件后停止程序,配置后再次启动即可
|
|
||||||
|
|
||||||
### 2021/11/18
|
|
||||||
|
|
||||||
* 修复超级用户无法正确拉真寻入群
|
|
||||||
|
|
||||||
### 2021/11/14
|
|
||||||
|
|
||||||
* 修复功能总开关无法正确开启
|
|
||||||
|
|
||||||
### 2021/11/12
|
|
||||||
|
|
||||||
* 修复PIX无法url无法正确获取
|
|
||||||
|
|
||||||
### 2021/11/10
|
|
||||||
|
|
||||||
* 修复PIX表重复创建导致首次无法运行
|
|
||||||
* 检测Omage图库改为命令方式:检测omega图库
|
|
||||||
|
|
||||||
### 2021/11/9
|
|
||||||
|
|
||||||
* 修复管理员帮助无法正常响应
|
|
||||||
* 修复被ban时会一直回复被ban提醒
|
|
||||||
|
|
||||||
### 2021/11/5
|
|
||||||
|
|
||||||
* 修复ai没有图灵key时报错
|
|
||||||
* 提供图片路径resource/img/background/check
|
|
||||||
|
|
||||||
### 2021/11/4
|
|
||||||
|
|
||||||
* 通用排行榜改用图片消息,且可以自定义排行榜人数
|
|
||||||
* 优化CreateMat排行榜数据显示
|
|
||||||
* 修复了pix更新多余参数导致失败的问题
|
|
||||||
* 修复滴滴滴-注入风险
|
|
||||||
* 修复无法正常关闭滴滴滴,戳一戳
|
|
||||||
* 添加了发送图片撤回配置项WITHDRAW_IMAGE_TIME
|
|
||||||
* 修复了天气regex文本过长时会正则匹配过久导致nb卡顿
|
|
||||||
* message_build新增custom_forward_msg用于快捷生成转发消息
|
|
||||||
* 插件配置改为yaml存储,新增Config,用于获取和新增插件配置
|
|
||||||
* 新增 当插件加载失败时,会发送消息提醒超级用户,且在功能状态中对应失败插件写上[ERROR]
|
|
||||||
* 修复当查看-spuer插件帮助时无法正确回复
|
|
||||||
* 群内帮助图片会随群内功能开关和插件总开关变化
|
|
||||||
* 自检改为图像形式
|
|
||||||
* 更新色图删除了rar_setu,r18_rar和rar文件夹,压缩将统一在temp文件夹
|
|
||||||
* 更新色图只有在有更新数量或报错时才会提醒超级用户
|
|
||||||
* 群欢迎消息加入cd
|
|
||||||
* 加入资源管理resources_manager
|
|
||||||
* 新增 好友请求/群聊邀请 控制命令
|
|
||||||
|
|
||||||
### 2021/10/15
|
|
||||||
|
|
||||||
* 适配了原神资源查询米游社地图返回的新格式
|
|
||||||
|
|
||||||
### 2021/10/8
|
|
||||||
|
|
||||||
* 修复疫情省份查询失效
|
|
||||||
* 修复功能调用统计全局下统计可能发生错误
|
|
||||||
|
|
||||||
### 2021/10/4
|
|
||||||
|
|
||||||
* 修复了功能调用统计失效问题
|
|
||||||
* 当色图库中没有色图时,会在线搜索色图而不是‘没找到符合条件的色图...’
|
|
||||||
* 快速更新权限再给超级用户发送错误日志
|
|
||||||
* 修复疫情未加载省份城市无法正常使用
|
|
||||||
|
|
||||||
### 2021/10/3
|
|
||||||
|
|
||||||
* 对插件进行分离
|
|
||||||
* 重写了插件与限制管理器以及帮助获取
|
|
||||||
* 修改一些插件目录和数据存储目录
|
|
||||||
* 插件通用配置与限制数据将以ymal文件存储 \[路径:data/configs]
|
|
||||||
* 所有商店相关操作调用统计合并为商店(包括之前已经保存的数据,会先进行备份)
|
|
||||||
* 简化了点歌的代码相关
|
|
||||||
* 修复了碧蓝航线抽卡新框导致报错无法正常初始化
|
|
||||||
* 修复了P站排行/搜图在PC端无法正常显示
|
|
||||||
* 添加了插件对超级用户是否限制的配置 ‘limit_superuser’
|
|
||||||
* 添加命令 ‘重载插件配置’,用于生效手动修改配文件
|
|
||||||
* 超级用户帮助可以添加 -super 来显示该插件的超级用户帮助,示例:帮助.ban -super
|
|
||||||
* 原神黄历改为网页截图
|
|
||||||
* 修改了鲁迅说逻辑结构
|
|
||||||
* 修改了统计图表样式,改为自定义CreateMat
|
|
||||||
* 节日红包不再被24小时限制,群内多个节日红包将会覆盖
|
|
||||||
* 当群权限为-1时,不会对群发送修改权限通知,并屏蔽此群一切命令(包括提醒)
|
|
||||||
* 修复了红包数量可以过大或为负数,红包数量大于群员数量时会修改为群员数量
|
|
||||||
* 修复了负数开箱
|
|
||||||
* 签到最低好感度设置为0.01 [@pull/53](https://github.com/HibiKier/zhenxun_bot/pull/53)
|
|
||||||
* pip安装新依赖 ruamel.yaml
|
|
||||||
* 修复功能 EPIC [@pull/58](https://github.com/HibiKier/zhenxun_bot/pull/58)
|
|
||||||
|
|
||||||
### 2021/9/10
|
|
||||||
|
|
||||||
* 修复撤回消息有时无法正确获取消息id
|
|
||||||
|
|
||||||
### 2021/9/9
|
|
||||||
|
|
||||||
* 替换coser API
|
|
||||||
* 修复签到uid可能不默认为0
|
|
||||||
* 修复签到可能重复的问题
|
|
||||||
* 修复无订阅时递归出错
|
|
||||||
* 启用了plugins2info_dict, plugins2cd_dict, plugins2exists_dict配置文件,通过USE_CONFIG_FILE=True开启
|
|
||||||
* 修复涩图local_id会被固定为50
|
|
||||||
* 优化图库数量查询
|
|
||||||
* 修复原神大地图过大无法打开报错
|
|
||||||
* 修复无法显示正确的涩图上限
|
|
||||||
|
|
||||||
### 2021/9/7
|
|
||||||
|
|
||||||
* 修改 update_info.json
|
|
||||||
* 修改 更新信息 图片大小
|
|
||||||
* 修复 查看订阅 命令 UP和番剧无法正常显示
|
|
||||||
* 修复订阅推送无法正确推送
|
|
||||||
* 修复搜图返回列表为空时无法正确回复 [@pull/40](https://github.com/HibiKier/zhenxun_bot/pull/40)
|
|
||||||
|
|
||||||
### 2021/9/5
|
|
||||||
* 添加配置PIX_IMAGE_SIZE,调整PIX下载图片大小,当设置的图片404时,改为原图
|
|
||||||
* 新增配置DEFAULT_GROUP_LEVEL,默认群等级
|
|
||||||
* 新增超级用户功能 super ban,将屏蔽被ban用户的所有消息,指令:b了
|
|
||||||
* b站转发解析支持纯BV号解析,且五分钟内不会解析相同url
|
|
||||||
* 俄罗斯轮盘新增 连胜/最高连胜/连败/最高连败 纪录,新增 最高连胜排行榜/最高连败排行榜
|
|
||||||
* 增加扩展图库 OmegaPixivIllusts,不想自己找图的人福音([Ailitonia](https://github.com/Ailitonia) 佬的高质量精品手筛图库)([传送门](https://github.com/Ailitonia/omega-miya/blob/master/archive_data/db_pixiv.7z) ),可以手动导入图库,也可以将解压文件放在bot.py同级目录重启bot
|
|
||||||
* 增加配置PIX_OMEGA_PIXIV_RATIO,PIX功能发送PIX图库和扩展图库OmegaPixivIllusts图片的比例,如果没有使用扩展图库OmegaPixivIllusts,请设置为(10, 0)
|
|
||||||
* 增加配置WITHDRAW_PIX_TIME,用于配置在开关PIX图片在群私聊的自动撤回
|
|
||||||
* 上传图库cases, 开箱 也可以连抽(未更新过没有价格)
|
|
||||||
* 新增命令 查看群白名单
|
|
||||||
* plugins2info_dict新增键"default_status",设置加入新群时功能的默认开关状态
|
|
||||||
* 增加配置plugins2exists_dict,可自定义是否阻塞某命令同时触发多次
|
|
||||||
* 增加配置plugins2cd_dict,可自定义为命令添加cd
|
|
||||||
* 新增B站订阅(直播/番剧/UP)[测试],提供命令:添加订阅 [主播/UP/番剧] [id/链接/番名],删除订阅 [id],查看订阅
|
|
||||||
* 优化pix和色图的数据库查询
|
|
||||||
* 触发已关闭的功能的正则时不再触发ai
|
|
||||||
* 更换coser API
|
|
||||||
* PIX搜索pid功能在群聊无法搜索PIX图库的r18和OmegaPixivIllusts的r15以及r18,超级用户除外
|
|
||||||
* PIX单次搜索的图片张数超级用户限制为至多30张,普通用户10张
|
|
||||||
* PIX超级用户新增-s,-r,可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
|
|
||||||
* 优化P站排行和搜图,现在需要艾特,改为使用HIBIAPI,在群内时将使用合并消息(群聊搜图会屏蔽R-18)
|
|
||||||
* win10下playwright相关功能无法使用,但是不再需要删除文件
|
|
||||||
* 签到大改,优化签到方式与逻辑,改为图片形式发送,有概率额外获得随机道具(好感度有加成)
|
|
||||||
* 修改撤回功能,改为回复撤回,回复发送撤回
|
|
||||||
* 更改logging为loguru
|
|
||||||
* 删除了 发送图片 中的 [N]张图[keyword] 功能
|
|
||||||
* 修复私聊 关闭[功能] 默认不为 全部 而要添加参数 ‘a’
|
|
||||||
* 修复0权限用户可以修改禁言检测相关设置
|
|
||||||
|
|
||||||
### 2021/8/17
|
|
||||||
|
|
||||||
* 新增配置CHECK_NOTICE_INFO_CD,修改群权限,个人权限检测各种检测的提示消息cd
|
|
||||||
* 新增功能‘连续上传图片’功能,直到输入‘stop’停止
|
|
||||||
* 新增功能维护时白名单以及对应命令(白名单中的群聊不受维护限制)
|
|
||||||
* 新增ALAPI功能,微博热搜,可以通过序号来查看部分热搜内容
|
|
||||||
* 新增配置NICKNAME,偶尔也想换换名字的说(自我介绍仅当NICKNAME=真寻时生效)
|
|
||||||
* 提供 更新信息 命令,可以使群员查看更新内容(可开关,与其他功能无异,但不会被统计,该命令图片由自动更新生成)
|
|
||||||
* 超级用户可以通过私聊来对指定qq进行ban/unban
|
|
||||||
* 超级用户帮助改为图片形式
|
|
||||||
* 公开图库删除‘色图’
|
|
||||||
* 群权限检测,个人权限检测,功能开关检测合并,权限检测顺序:个人权限 > 群权限 > 插件开关 >超级用户禁用某群插件 > 超级用户限制群里插件 > 插件维护检测
|
|
||||||
* 重写群功能管理,超级用户可对群/私聊分别禁用,也可禁用指定群指定功能,新增命令‘功能状态’,超级用户关闭功能提供参数(默认ALL):group/g(群聊),private/p(私聊)
|
|
||||||
* 超级用户不会被任何权限等检测阻挡
|
|
||||||
* 不会重复复读,复读消息只会发送一次
|
|
||||||
* b站转发解析支持b23.tv,www.bilibili.com链接,cv专栏(playwright截图,压缩倍率0.5,较慢且文字可能不清晰,后优化)
|
|
||||||
* 我有一个朋友功能,当艾特一个对象时,‘朋友’改为艾特对象的群名片或昵称
|
|
||||||
* 修复‘上传/删除/移动图片’目录不正确
|
|
||||||
* 修复天气功能,当城市名在‘天气’后时报错
|
|
||||||
* 修复配置INITIAL_SETU_PROBABILITY不生效
|
|
||||||
|
|
||||||
### 2021/8/10
|
|
||||||
|
|
||||||
* 重复的好友请求和邀群提示在5分钟内不会重复提示
|
|
||||||
* 疫情会优先检查城市,城市省份市区重名时请添加‘市’
|
|
||||||
* 添加命令‘原神资源查找’,‘设置cookie’
|
|
||||||
* 添加配置AUTO_UPDATE_ZHENXUN,是否自动更新真寻,默认True
|
|
||||||
* 添加配置MAX_RUSSIAN_BET_GOLD,俄罗斯轮盘赌注最大金额,默认1000
|
|
||||||
* 检查更新真寻定时任务时间改为12 : 00
|
|
||||||
* 添加功能能不能好好说话(nbnhhsh)
|
|
||||||
* 添加功能随机roll,无参为数字,有参为随机参数
|
|
||||||
* 添加linux重启脚本以及重启命令‘重启’(建议首次生成restart.sh先查看命令是否正确)
|
|
||||||
* 修复管理员功能的权限检测
|
|
||||||
* 修复丢人爬开关
|
|
||||||
|
|
||||||
### 2021/8/6
|
|
||||||
|
|
||||||
* 天气查询会优先遍历城市
|
|
||||||
* 添加自动更新真寻命令
|
|
||||||
|
|
||||||
##### 如果你的版本为 2021/8/4,可以直接复制plugins/check_zhenxun_update后,通过指令来更新真寻
|
|
||||||
|
|
||||||
### 2021/8/4
|
|
||||||
|
|
||||||
* 修改天气与疫情城市数据,改为api获取,丰富疫情的回复消息
|
|
||||||
* 原神资源查询,大地图将被压缩至9M,且启动时当大地图存在时不再自动更新地图
|
|
||||||
* 下载数据库内色图时将直接存储至_setu,不再存储至临时文件
|
|
||||||
* 重复的好友请求或邀请请求在一定时间不会重复发送提醒
|
|
||||||
* 添加每日自动清理临时图片定时任务
|
|
||||||
* 修复金币排行显示
|
|
||||||
* 修复无法正常关闭戳一戳功能
|
|
||||||
|
|
||||||
### 2021/7/30
|
|
||||||
|
|
||||||
* 重构代码,进行优化,添加注释,删除冗余代码,降低代码耦合
|
|
||||||
* 添加功能:PIX(一套快捷的pixiv存图命令,自建图库存储url等信息?意在获取自己或群友xp的图)
|
|
||||||
* 添加功能:清理临时图片文件(temp/rar/r18_rar文件夹)
|
|
||||||
* 添加额外定时任务(5分钟检测一次),解决加入新群时无法及时为管理员提供权限
|
|
||||||
* 添加配置ALAPI_AI_CHECK,开关AI回复文本检测
|
|
||||||
* 添加配置IMPORT_DEFAULT_SHOP_GOODS,控制是否导入内置的三个商品(好感度加持卡ⅠⅡⅢ)
|
|
||||||
* 添加配置ONLY_USE_LOCAL_SETU,仅仅使用本地色图(有的话),提升速度,但无法在线搜索色图和保存链接
|
|
||||||
* 添加配置WITHDRAW_SETU_TIME,是否需要延迟撤回色图,可配置仅群里,私聊或全部
|
|
||||||
* 好友请求,入群请求,滴滴滴-,/t,被踢出群提醒,的提示消息更加丰富
|
|
||||||
* 彻底重写原神资源查找,添加规划路线(路线残缺缺缺缺版,有空补)添加命令‘更新原神资源信息’,强制更新地图等资源
|
|
||||||
* 优化色图和P站排行/搜图检测用户是否正在触发命令代码
|
|
||||||
* 当群最后发言大于36小时,也会关闭广播通知
|
|
||||||
* 功能维护时超级用户依然可以调用(苦了谁都不能苦了自己)
|
|
||||||
* 修复获取赛马娘UP公告
|
|
||||||
* 重写 色图/更新色图
|
|
||||||
* 色图数据存储改为数据库,启动时会更新之前的色图数据(有的话),更新完毕后会删除原数据文件,如果需要保留请提前备份,
|
|
||||||
* lolicon api改为v2
|
|
||||||
* 取消r18次数限制
|
|
||||||
* 单次搜索至多保存100条链接
|
|
||||||
* 添加定时撤回
|
|
||||||
* 暂时取消上传/删除色图
|
|
||||||
*
|
|
||||||
* 更新建议(不要替换你的data和resources文件夹!)
|
|
||||||
* 删除configs,plugins,services,utils,models文件夹重新clone
|
|
||||||
* 删除多余文件夹,resources/img/genshin/seek_god_eye
|
|
||||||
* 清空resources/img/genshin/genshin_icon文件夹,仅保留box.png和box_alpha.png
|
|
||||||
* 替换bot.py
|
|
||||||
|
|
||||||
### 2021/7/27
|
|
||||||
|
|
||||||
* 原神今日素材改为单张截图+拼图,更新文件utils/img_utils.py及plugins/genshin/material_remind/__init__.py
|
|
||||||
|
|
||||||
### 2021/7/26
|
|
||||||
|
|
||||||
* 修复原神今日素材稻妻城开放后截图不完整的问题
|
|
||||||
|
|
||||||
### 2021/7/14
|
|
||||||
|
|
||||||
* 原神今日素材自动更新时间由 00:01 -> 04:01 [#issues7](https://github.com/HibiKier/zhenxun_bot/issues/7)
|
|
||||||
* 小问题的修复和优化
|
|
||||||
|
|
||||||
### 2021/7/12
|
|
||||||
|
|
||||||
* 修复开箱功能单抽出金时存储格式错误导致 ‘我的金色’ 无法正常发送图片
|
|
||||||
* 小问题的修复和优化
|
|
||||||
|
|
||||||
### 2021/7/6
|
|
||||||
|
|
||||||
* 识番功能 trace.moe 替换为新API(旧API已失效)
|
|
||||||
* 小问题的修复和优化
|
|
||||||
|
|
||||||
### 2021/6/30
|
|
||||||
|
|
||||||
* 将plugin2name和plugin2level合并为plugin2info
|
|
||||||
* util改为utils(。。!)
|
|
||||||
* 修复当用户发送速度极快时开箱会突破每日限制
|
|
||||||
* 新增功能:通过PID获取图片
|
|
||||||
* 发送图片新增功能:搜索图片
|
|
||||||
* 功能统计可视化
|
|
||||||
* 新增命令:好感度总排行
|
|
||||||
* 原神每日素材改为从"可莉特调"截图,提供命令‘更新原神每日素材’和定时任务
|
|
||||||
* 修复月功能统计错误的问题
|
|
||||||
|
|
||||||
### 2021/6/24
|
|
||||||
|
|
||||||
* 添加了一些ALAPI:网易云热评,获取b站视频封面,古诗(需要填写ALAPI_TOKEN)
|
|
||||||
* 如果填写了ALAPI_TOKEN,将会检测备用接口回复的文本是否合规
|
|
||||||
* 优化了色图,当搜索色图下载失败时,会从本地色图库中发送相关tag色图
|
|
||||||
* 当网易云点歌繁忙时会尝试多次点歌
|
|
||||||
|
|
||||||
### 2021/6/23
|
|
||||||
|
|
||||||
* 添加功能:群权限(所以说内鬼都快爬,可以在configs/config.py中修改各个功能的权限等级)
|
|
||||||
* 优化了数据统计,将以7天,30天为周期,为将来更方便实现数据可视化
|
|
||||||
* 更新坎公骑冠剑UP卡池
|
|
||||||
* 修复赛马娘UP卡池
|
|
||||||
* 修复一些小问题
|
|
||||||
|
|
||||||
### 2021/6/18
|
|
||||||
|
|
||||||
* 修复p站排行,搜图因网络问题爆炸时没有具体回复
|
|
||||||
* 更换色图显示方式为 id,title,author,pid
|
|
||||||
* 修复修改商品后商品顺序改变
|
|
||||||
* 滴滴滴- 和 /t支持图片回复
|
|
||||||
* 将/t回复更加简单(可以通过序号),且可以直接发送群
|
|
||||||
* 修复bt功能无法交互
|
|
||||||
|
|
||||||
### 2021/6/17
|
|
||||||
|
|
||||||
* 修复p站排行,搜图因网络问题爆炸时没有具体回复
|
|
||||||
* 更换色图显示方式为 id,title,author,pid
|
|
||||||
|
|
||||||
### 2021/6/15
|
|
||||||
* 修改了‘帮助’功能,具体为‘帮助 指令名’,未指定指令名时则为查看全部功能列表
|
|
||||||
* 修改了色图的存储数据格式
|
|
||||||
* 色图功能搜索的色图改为随机从urls中随机抽取
|
|
||||||
* 将商品数据存储入数据库,提供 '增加/删除/修改商品' 指令
|
|
||||||
* 商店列表图片不再使用固定背景图,改为直接拼图
|
|
||||||
* 增加功能:俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
|
|
||||||
* 增加功能:金币红包(节日红包与群红包相互独立)
|
|
||||||
* 金币排行
|
|
||||||
* 重写一个朋友插件
|
|
||||||
* 其他微小调整
|
|
||||||
|
|
||||||
### 2021/6/4
|
|
||||||
* 重写BT功能
|
|
||||||
* 进行一些BUG修复和微小调整
|
|
||||||
* 添加撤回功能[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
|
|
||||||
* 为色图功能添加额外的 上传色图 和 删除色图方法(影响hash)
|
|
||||||
|
|
||||||
### 2021/5/26
|
|
||||||
* 将语录源更换为一言api
|
|
||||||
|
|
||||||
|
|
||||||
## Todo
|
## Todo
|
||||||
- [ ] 提供更多对插件的控制
|
|
||||||
- [ ] 明日方舟卡片式的签到..(大概)
|
|
||||||
- [ ] 更多的群管理功能
|
|
||||||
- [ ] 数据清理控制
|
|
||||||
- [ ] docker容器
|
- [ ] docker容器
|
||||||
|
- [ ] web管理
|
||||||
|
|
||||||
## 感谢
|
## 感谢
|
||||||
[Onebot](https://github.com/howmanybots/onebot)
|
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
|
||||||
[go-cqhttp](https://github.com/Mrs4s/go-cqhttp)
|
[Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台.
|
||||||
[nonebot2](https://github.com/nonebot/nonebot2)
|
[nonebot / nonebot2](https://github.com/nonebot/nonebot2) :跨平台Python异步机器人框架
|
||||||
[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)
|
[Angel-Hair / XUN_Bot](https://github.com/Angel-Hair/XUN_Bot) :一个基于NoneBot和酷Q的功能性QQ机器人
|
||||||
[cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins#%E7%94%9F%E6%88%90%E5%99%A8%E6%8F%92%E4%BB%B6)
|
[pcrbot / cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins) :hoshino插件合集
|
||||||
[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
|
[MeetWq /nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw) :A simple withdraw plugin for Nonebot2
|
||||||
[nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)
|
[maxesisn / nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) :适用于nonebot2的点歌插件
|
||||||
[nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager)
|
[nonepkg / nonebot-plugin-manager](https://github.com/nonepkg/nonebot-plugin-manager) :Nonebot Plugin Manager base on import hook
|
||||||
[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)
|
[H-K-Y / Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot) :原神bot,这是一个基于nonebot和HoshinoBot的原神娱乐及信息查询插件
|
||||||
[nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says)
|
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
|
||||||
[AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus)
|
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
|
||||||
[omega-miya](https://github.com/Ailitonia/omega-miya)
|
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
|
||||||
|
[KimigaiiWuyi / GenshinUID]("https://github.com/KimigaiiWuyi/GenshinUID") :一个基于HoshinoBot/NoneBot2的原神UID查询插件
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
__version__: v0.0.6.5
|
__version__: v0.1.1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from utils.utils import get_message_text, get_message_imgs
|
from utils.utils import get_message_text, get_message_img
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||||
from .data_source import custom_group_welcome
|
from .data_source import custom_group_welcome
|
||||||
@@ -38,7 +38,7 @@ custom_welcome = on_command(
|
|||||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||||
try:
|
try:
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
imgs = get_message_imgs(event.json())
|
imgs = get_message_img(event.json())
|
||||||
if not msg and not imgs:
|
if not msg and not imgs:
|
||||||
await custom_welcome.finish(__plugin_usage__)
|
await custom_welcome.finish(__plugin_usage__)
|
||||||
await custom_welcome.send(
|
await custom_welcome.send(
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from nonebot.typing import T_State
|
|||||||
from nonebot.adapters import Bot, Event
|
from nonebot.adapters import Bot, Event
|
||||||
from nonebot.permission import SUPERUSER
|
from nonebot.permission import SUPERUSER
|
||||||
import asyncio
|
import asyncio
|
||||||
from utils.utils import get_message_text, get_message_imgs
|
from utils.utils import get_message_text, get_message_img
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from utils.manager import group_manager
|
from utils.manager import group_manager
|
||||||
@@ -35,7 +35,7 @@ broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
|
|||||||
@broadcast.handle()
|
@broadcast.handle()
|
||||||
async def _(bot: Bot, event: Event, state: T_State):
|
async def _(bot: Bot, event: Event, state: T_State):
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
imgs = get_message_imgs(event.json())
|
imgs = get_message_img(event.json())
|
||||||
rst = ""
|
rst = ""
|
||||||
for img in imgs:
|
for img in imgs:
|
||||||
rst += image(img)
|
rst += image(img)
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ def _create_help_img(
|
|||||||
logger.warning(f"{type(e)}: {e}")
|
logger.warning(f"{type(e)}: {e}")
|
||||||
else:
|
else:
|
||||||
matchers_data[plugin_type][plugin_name] = {
|
matchers_data[plugin_type][plugin_name] = {
|
||||||
"module": matcher.module,
|
"modules": matcher.module,
|
||||||
"des": plugin_des,
|
"des": plugin_des,
|
||||||
"cmd": plugin_cmd,
|
"cmd": plugin_cmd,
|
||||||
"text_type": text_type,
|
"text_type": text_type,
|
||||||
@@ -147,16 +147,16 @@ def _create_help_img(
|
|||||||
# 禁用flag
|
# 禁用flag
|
||||||
flag = True
|
flag = True
|
||||||
if plugins_manager.get_plugin_status(
|
if plugins_manager.get_plugin_status(
|
||||||
matchers_data[type_][k]["module"], "all"
|
matchers_data[type_][k]["modules"], "all"
|
||||||
):
|
):
|
||||||
flag = False
|
flag = False
|
||||||
if group_id:
|
if group_id:
|
||||||
flag = flag and plugins_manager.get_plugin_status(
|
flag = flag and plugins_manager.get_plugin_status(
|
||||||
matchers_data[type_][k]["module"], "group"
|
matchers_data[type_][k]["modules"], "group"
|
||||||
)
|
)
|
||||||
simple_help_str += (
|
simple_help_str += (
|
||||||
f"{i+1}.{k}<|_|~|>"
|
f"{i+1}.{k}<|_|~|>"
|
||||||
f"{group_manager.get_plugin_status(matchers_data[type_][k]['module'], group_id) if group_id else '_'}|"
|
f"{group_manager.get_plugin_status(matchers_data[type_][k]['modules'], group_id) if group_id else '_'}|"
|
||||||
f"{flag}\n"
|
f"{flag}\n"
|
||||||
)
|
)
|
||||||
if matchers_data[type_][k]["text_type"] == 1:
|
if matchers_data[type_][k]["text_type"] == 1:
|
||||||
|
|||||||
@@ -1,19 +1,29 @@
|
|||||||
from nonebot.matcher import Matcher
|
from nonebot.matcher import Matcher
|
||||||
from nonebot.message import run_preprocessor, IgnoredException
|
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
||||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||||
|
from models.friend_user import FriendUser
|
||||||
|
from models.group_member_info import GroupInfoUser
|
||||||
|
from models.bag_user import BagUser
|
||||||
from utils.manager import (
|
from utils.manager import (
|
||||||
plugins2settings_manager,
|
plugins2settings_manager,
|
||||||
admin_manager,
|
admin_manager,
|
||||||
group_manager,
|
group_manager,
|
||||||
plugins_manager,
|
plugins_manager,
|
||||||
|
plugins2cd_manager,
|
||||||
|
plugins2block_manager,
|
||||||
|
plugins2count_manager
|
||||||
)
|
)
|
||||||
from .utils import set_block_limit_false, status_message_manager
|
from .utils import set_block_limit_false, status_message_manager
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
|
from typing import Optional
|
||||||
from nonebot.adapters.cqhttp import (
|
from nonebot.adapters.cqhttp import (
|
||||||
Bot,
|
Bot,
|
||||||
MessageEvent,
|
MessageEvent,
|
||||||
GroupMessageEvent,
|
GroupMessageEvent,
|
||||||
PokeNotifyEvent
|
PokeNotifyEvent,
|
||||||
|
PrivateMessageEvent,
|
||||||
|
Message,
|
||||||
|
Event
|
||||||
)
|
)
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from models.ban_user import BanUser
|
from models.ban_user import BanUser
|
||||||
@@ -22,13 +32,11 @@ from utils.message_builder import at
|
|||||||
from models.level_user import LevelUser
|
from models.level_user import LevelUser
|
||||||
import nonebot
|
import nonebot
|
||||||
|
|
||||||
|
|
||||||
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||||
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||||
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||||
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||||
|
|
||||||
|
|
||||||
ignore_rst_module = ["ai", "poke", "dialogue"]
|
ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||||
|
|
||||||
|
|
||||||
@@ -37,15 +45,27 @@ ignore_rst_module = ["ai", "poke", "dialogue"]
|
|||||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||||
module = matcher.module
|
module = matcher.module
|
||||||
plugins2info_dict = plugins2settings_manager.get_data()
|
plugins2info_dict = plugins2settings_manager.get_data()
|
||||||
|
# 功能的金币检测 #######################################
|
||||||
|
# 功能的金币检测 #######################################
|
||||||
|
# 功能的金币检测 #######################################
|
||||||
|
cost_gold = 0
|
||||||
|
if isinstance(event, GroupMessageEvent) and plugins2settings_manager.get_plugin_data(module).get('cost_gold'):
|
||||||
|
cost_gold = plugins2settings_manager.get_plugin_data(module).get('cost_gold')
|
||||||
|
if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
|
||||||
|
await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
|
||||||
|
raise IgnoredException(f"{module} 金币限制...")
|
||||||
|
# 当插件不阻塞超级用户时,超级用户提前扣除金币
|
||||||
|
if str(event.user_id) in bot.config.superusers and not plugins2info_dict[module]["limit_superuser"]:
|
||||||
|
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||||
try:
|
try:
|
||||||
if (
|
if (
|
||||||
(not isinstance(event, MessageEvent) and module != "poke")
|
(not isinstance(event, MessageEvent) and module != "poke")
|
||||||
or await BanUser.is_ban(event.user_id)
|
or await BanUser.is_ban(event.user_id)
|
||||||
and str(event.user_id) not in bot.config.superusers
|
and str(event.user_id) not in bot.config.superusers
|
||||||
) or (
|
) or (
|
||||||
str(event.user_id) in bot.config.superusers
|
str(event.user_id) in bot.config.superusers
|
||||||
and plugins2info_dict.get(module)
|
and plugins2info_dict.get(module)
|
||||||
and not plugins2info_dict[module]["limit_superuser"]
|
and not plugins2info_dict[module]["limit_superuser"]
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@@ -56,8 +76,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
_module = _plugin.module
|
_module = _plugin.module
|
||||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||||
if (
|
if (
|
||||||
"[superuser]" in plugin_name.lower()
|
"[superuser]" in plugin_name.lower()
|
||||||
and str(event.user_id) in bot.config.superusers
|
and str(event.user_id) in bot.config.superusers
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@@ -79,12 +99,12 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
# 个人权限
|
# 个人权限
|
||||||
if (
|
if (
|
||||||
not await LevelUser.check_level(
|
not await LevelUser.check_level(
|
||||||
event.user_id,
|
event.user_id,
|
||||||
event.group_id,
|
event.group_id,
|
||||||
admin_manager.get_plugin_level(module),
|
admin_manager.get_plugin_level(module),
|
||||||
)
|
)
|
||||||
and admin_manager.get_plugin_level(module) > 0
|
and admin_manager.get_plugin_level(module) > 0
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
if _flmt.check(event.user_id):
|
if _flmt.check(event.user_id):
|
||||||
@@ -92,7 +112,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
await bot.send_group_msg(
|
await bot.send_group_msg(
|
||||||
group_id=event.group_id,
|
group_id=event.group_id,
|
||||||
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
|
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
|
||||||
f"{admin_manager.get_plugin_level(module)}",
|
f"{admin_manager.get_plugin_level(module)}",
|
||||||
)
|
)
|
||||||
except ActionFailed:
|
except ActionFailed:
|
||||||
pass
|
pass
|
||||||
@@ -102,7 +122,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
raise IgnoredException("权限不足")
|
raise IgnoredException("权限不足")
|
||||||
else:
|
else:
|
||||||
if not await LevelUser.check_level(
|
if not await LevelUser.check_level(
|
||||||
event.user_id, 0, admin_manager.get_plugin_level(module)
|
event.user_id, 0, admin_manager.get_plugin_level(module)
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
await bot.send_private_msg(
|
await bot.send_private_msg(
|
||||||
@@ -118,12 +138,12 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
|
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
|
||||||
# 戳一戳单独判断
|
# 戳一戳单独判断
|
||||||
if isinstance(event, GroupMessageEvent) or (
|
if isinstance(event, GroupMessageEvent) or (
|
||||||
isinstance(event, PokeNotifyEvent) and event.group_id
|
isinstance(event, PokeNotifyEvent) and event.group_id
|
||||||
):
|
):
|
||||||
if status_message_manager.get(event.group_id) is None:
|
if status_message_manager.get(event.group_id) is None:
|
||||||
status_message_manager.delete(event.group_id)
|
status_message_manager.delete(event.group_id)
|
||||||
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
|
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
|
||||||
event.group_id
|
event.group_id
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
|
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
|
||||||
@@ -141,7 +161,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
if not group_manager.get_plugin_status(module, event.group_id):
|
if not group_manager.get_plugin_status(module, event.group_id):
|
||||||
try:
|
try:
|
||||||
if module not in ignore_rst_module and _flmt_s.check(
|
if module not in ignore_rst_module and _flmt_s.check(
|
||||||
event.group_id
|
event.group_id
|
||||||
):
|
):
|
||||||
_flmt_s.start_cd(event.group_id)
|
_flmt_s.start_cd(event.group_id)
|
||||||
await bot.send_group_msg(
|
await bot.send_group_msg(
|
||||||
@@ -157,8 +177,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
|
if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
|
||||||
try:
|
try:
|
||||||
if (
|
if (
|
||||||
_flmt_s.check(event.group_id)
|
_flmt_s.check(event.group_id)
|
||||||
and module not in ignore_rst_module
|
and module not in ignore_rst_module
|
||||||
):
|
):
|
||||||
_flmt_s.start_cd(event.group_id)
|
_flmt_s.start_cd(event.group_id)
|
||||||
await bot.send_group_msg(
|
await bot.send_group_msg(
|
||||||
@@ -174,8 +194,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
if not plugins_manager.get_plugin_status(module, block_type="group"):
|
if not plugins_manager.get_plugin_status(module, block_type="group"):
|
||||||
try:
|
try:
|
||||||
if (
|
if (
|
||||||
_flmt_c.check(event.group_id)
|
_flmt_c.check(event.group_id)
|
||||||
and module not in ignore_rst_module
|
and module not in ignore_rst_module
|
||||||
):
|
):
|
||||||
_flmt_c.start_cd(event.group_id)
|
_flmt_c.start_cd(event.group_id)
|
||||||
await bot.send_group_msg(
|
await bot.send_group_msg(
|
||||||
@@ -205,14 +225,14 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
# 维护
|
# 维护
|
||||||
if not plugins_manager.get_plugin_status(module, block_type="all"):
|
if not plugins_manager.get_plugin_status(module, block_type="all"):
|
||||||
if isinstance(
|
if isinstance(
|
||||||
event, GroupMessageEvent
|
event, GroupMessageEvent
|
||||||
) and group_manager.check_group_is_white(event.group_id):
|
) and group_manager.check_group_is_white(event.group_id):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
if (
|
if (
|
||||||
_flmt_c.check(event.group_id)
|
_flmt_c.check(event.group_id)
|
||||||
and module not in ignore_rst_module
|
and module not in ignore_rst_module
|
||||||
):
|
):
|
||||||
_flmt_c.start_cd(event.group_id)
|
_flmt_c.start_cd(event.group_id)
|
||||||
await bot.send_group_msg(
|
await bot.send_group_msg(
|
||||||
@@ -233,3 +253,126 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
status_message_manager.add(id_)
|
status_message_manager.add(id_)
|
||||||
set_block_limit_false(event, module)
|
set_block_limit_false(event, module)
|
||||||
raise IgnoredException("此功能正在维护...")
|
raise IgnoredException("此功能正在维护...")
|
||||||
|
|
||||||
|
# 以下为限制检测 #######################################################
|
||||||
|
# 以下为限制检测 #######################################################
|
||||||
|
# 以下为限制检测 #######################################################
|
||||||
|
# 以下为限制检测 #######################################################
|
||||||
|
# 以下为限制检测 #######################################################
|
||||||
|
# 以下为限制检测 #######################################################
|
||||||
|
# Cd
|
||||||
|
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||||
|
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||||
|
check_type = plugin_cd_data["check_type"]
|
||||||
|
limit_type = plugin_cd_data["limit_type"]
|
||||||
|
rst = plugin_cd_data["rst"]
|
||||||
|
if (
|
||||||
|
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||||
|
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||||
|
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||||
|
):
|
||||||
|
cd_type_ = event.user_id
|
||||||
|
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||||
|
cd_type_ = event.group_id
|
||||||
|
if not plugins2cd_manager.check(module, cd_type_):
|
||||||
|
if rst:
|
||||||
|
rst = await init_rst(rst, event)
|
||||||
|
await send_msg(rst, bot, event)
|
||||||
|
raise IgnoredException(f"{module} 正在cd中...")
|
||||||
|
else:
|
||||||
|
plugins2cd_manager.start_cd(module, cd_type_)
|
||||||
|
# Block
|
||||||
|
if plugins2block_manager.check_plugin_block_status(module):
|
||||||
|
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||||
|
check_type = plugin_block_data["check_type"]
|
||||||
|
limit_type = plugin_block_data["limit_type"]
|
||||||
|
rst = plugin_block_data["rst"]
|
||||||
|
if (
|
||||||
|
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||||
|
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||||
|
or check_type == "all"
|
||||||
|
):
|
||||||
|
block_type_ = event.user_id
|
||||||
|
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||||
|
block_type_ = event.group_id
|
||||||
|
if plugins2block_manager.check(block_type_, module):
|
||||||
|
if rst:
|
||||||
|
rst = await init_rst(rst, event)
|
||||||
|
await send_msg(rst, bot, event)
|
||||||
|
raise IgnoredException(f"{event.user_id}正在调用{module}....")
|
||||||
|
else:
|
||||||
|
plugins2block_manager.set_true(block_type_, module)
|
||||||
|
# Count
|
||||||
|
if (
|
||||||
|
plugins2count_manager.check_plugin_count_status(module)
|
||||||
|
and event.user_id not in bot.config.superusers
|
||||||
|
):
|
||||||
|
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
|
||||||
|
limit_type = plugin_count_data["limit_type"]
|
||||||
|
rst = plugin_count_data["rst"]
|
||||||
|
count_type_ = event.user_id
|
||||||
|
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||||
|
count_type_ = event.group_id
|
||||||
|
if not plugins2count_manager.check(module, count_type_):
|
||||||
|
if rst:
|
||||||
|
rst = await init_rst(rst, event)
|
||||||
|
await send_msg(rst, bot, event)
|
||||||
|
raise IgnoredException(f"{module} count次数限制...")
|
||||||
|
else:
|
||||||
|
plugins2count_manager.increase(module, count_type_)
|
||||||
|
# 功能花费的金币 #######################################
|
||||||
|
# 功能花费的金币 #######################################
|
||||||
|
if cost_gold:
|
||||||
|
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||||
|
|
||||||
|
|
||||||
|
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
|
||||||
|
"""
|
||||||
|
发送信息
|
||||||
|
:param rst: pass
|
||||||
|
:param bot: pass
|
||||||
|
:param event: pass
|
||||||
|
"""
|
||||||
|
rst = await init_rst(rst, event)
|
||||||
|
try:
|
||||||
|
if isinstance(event, GroupMessageEvent):
|
||||||
|
status_message_manager.add(event.group_id)
|
||||||
|
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
|
||||||
|
else:
|
||||||
|
status_message_manager.add(event.user_id)
|
||||||
|
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
|
||||||
|
except ActionFailed:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# 解除命令block阻塞
|
||||||
|
@run_postprocessor
|
||||||
|
async def _(
|
||||||
|
matcher: Matcher,
|
||||||
|
exception: Optional[Exception],
|
||||||
|
bot: Bot,
|
||||||
|
event: Event,
|
||||||
|
state: T_State,
|
||||||
|
):
|
||||||
|
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
||||||
|
return
|
||||||
|
module = matcher.module
|
||||||
|
set_block_limit_false(event, module)
|
||||||
|
|
||||||
|
|
||||||
|
async def init_rst(rst: str, event: MessageEvent):
|
||||||
|
if "[uname]" in rst:
|
||||||
|
uname = event.sender.card if event.sender.card else event.sender.nickname
|
||||||
|
rst = rst.replace("[uname]", uname)
|
||||||
|
if "[nickname]" in rst:
|
||||||
|
if isinstance(event, GroupMessageEvent):
|
||||||
|
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||||
|
event.user_id, event.group_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||||
|
rst = rst.replace("[nickname]", nickname)
|
||||||
|
if "[at]" in rst and isinstance(event, GroupMessageEvent):
|
||||||
|
rst = rst.replace("[at]", str(at(event.user_id)))
|
||||||
|
return rst
|
||||||
|
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
from nonebot.matcher import Matcher
|
|
||||||
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
|
||||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
|
||||||
from models.friend_user import FriendUser
|
|
||||||
from models.group_member_info import GroupInfoUser
|
|
||||||
from utils.message_builder import at
|
|
||||||
from .utils import status_message_manager, set_block_limit_false
|
|
||||||
from utils.manager import (
|
|
||||||
plugins2cd_manager,
|
|
||||||
plugins2block_manager,
|
|
||||||
plugins2count_manager,
|
|
||||||
)
|
|
||||||
from typing import Optional
|
|
||||||
from nonebot.typing import T_State
|
|
||||||
from nonebot.adapters.cqhttp import (
|
|
||||||
Bot,
|
|
||||||
Event,
|
|
||||||
MessageEvent,
|
|
||||||
PrivateMessageEvent,
|
|
||||||
GroupMessageEvent,
|
|
||||||
Message,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# 命令cd | 命令阻塞 | 命令次数
|
|
||||||
@run_preprocessor
|
|
||||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
|
||||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
|
||||||
return
|
|
||||||
module = matcher.module
|
|
||||||
if (
|
|
||||||
isinstance(event, GroupMessageEvent)
|
|
||||||
and status_message_manager.get(event.group_id) is None
|
|
||||||
):
|
|
||||||
status_message_manager.delete(event.group_id)
|
|
||||||
# Count
|
|
||||||
if (
|
|
||||||
plugins2count_manager.check_plugin_count_status(module)
|
|
||||||
and event.user_id not in bot.config.superusers
|
|
||||||
):
|
|
||||||
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
|
|
||||||
limit_type = plugin_count_data["limit_type"]
|
|
||||||
rst = plugin_count_data["rst"]
|
|
||||||
count_type_ = event.user_id
|
|
||||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
|
||||||
count_type_ = event.group_id
|
|
||||||
if not plugins2count_manager.check(module, count_type_):
|
|
||||||
if rst:
|
|
||||||
rst = await init_rst(rst, event)
|
|
||||||
await send_msg(rst, bot, event)
|
|
||||||
raise IgnoredException(f"{module} count次数限制...")
|
|
||||||
else:
|
|
||||||
plugins2count_manager.increase(module, count_type_)
|
|
||||||
# Cd
|
|
||||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
|
||||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
|
||||||
check_type = plugin_cd_data["check_type"]
|
|
||||||
limit_type = plugin_cd_data["limit_type"]
|
|
||||||
rst = plugin_cd_data["rst"]
|
|
||||||
if (
|
|
||||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
|
||||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
|
||||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
|
||||||
):
|
|
||||||
cd_type_ = event.user_id
|
|
||||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
|
||||||
cd_type_ = event.group_id
|
|
||||||
if not plugins2cd_manager.check(module, cd_type_):
|
|
||||||
if rst:
|
|
||||||
rst = await init_rst(rst, event)
|
|
||||||
await send_msg(rst, bot, event)
|
|
||||||
raise IgnoredException(f"{module} 正在cd中...")
|
|
||||||
else:
|
|
||||||
plugins2cd_manager.start_cd(module, cd_type_)
|
|
||||||
# Block
|
|
||||||
if plugins2block_manager.check_plugin_block_status(module):
|
|
||||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
|
||||||
check_type = plugin_block_data["check_type"]
|
|
||||||
limit_type = plugin_block_data["limit_type"]
|
|
||||||
rst = plugin_block_data["rst"]
|
|
||||||
if (
|
|
||||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
|
||||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
|
||||||
or check_type == "all"
|
|
||||||
):
|
|
||||||
block_type_ = event.user_id
|
|
||||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
|
||||||
block_type_ = event.group_id
|
|
||||||
if plugins2block_manager.check(block_type_, module):
|
|
||||||
if rst:
|
|
||||||
rst = await init_rst(rst, event)
|
|
||||||
await send_msg(rst, bot, event)
|
|
||||||
raise IgnoredException(f"{event.user_id}正在调用{module}....")
|
|
||||||
else:
|
|
||||||
plugins2block_manager.set_true(block_type_, module)
|
|
||||||
|
|
||||||
|
|
||||||
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
|
|
||||||
"""
|
|
||||||
发送信息
|
|
||||||
:param rst: pass
|
|
||||||
:param bot: pass
|
|
||||||
:param event: pass
|
|
||||||
"""
|
|
||||||
rst = await init_rst(rst, event)
|
|
||||||
try:
|
|
||||||
if isinstance(event, GroupMessageEvent):
|
|
||||||
status_message_manager.add(event.group_id)
|
|
||||||
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
|
|
||||||
else:
|
|
||||||
status_message_manager.add(event.user_id)
|
|
||||||
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
|
|
||||||
except ActionFailed:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# 解除命令block阻塞
|
|
||||||
@run_postprocessor
|
|
||||||
async def _(
|
|
||||||
matcher: Matcher,
|
|
||||||
exception: Optional[Exception],
|
|
||||||
bot: Bot,
|
|
||||||
event: Event,
|
|
||||||
state: T_State,
|
|
||||||
):
|
|
||||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
|
||||||
return
|
|
||||||
module = matcher.module
|
|
||||||
set_block_limit_false(event, module)
|
|
||||||
|
|
||||||
|
|
||||||
async def init_rst(rst: str, event: MessageEvent):
|
|
||||||
if "[uname]" in rst:
|
|
||||||
uname = event.sender.card if event.sender.card else event.sender.nickname
|
|
||||||
rst = rst.replace("[uname]", uname)
|
|
||||||
if "[nickname]" in rst:
|
|
||||||
if isinstance(event, GroupMessageEvent):
|
|
||||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
|
||||||
event.user_id, event.group_id
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
|
||||||
rst = rst.replace("[nickname]", nickname)
|
|
||||||
if "[at]" in rst and isinstance(event, GroupMessageEvent):
|
|
||||||
rst = rst.replace("[at]", str(at(event.user_id)))
|
|
||||||
return rst
|
|
||||||
@@ -11,7 +11,6 @@ from .init_plugins_limit import (
|
|||||||
)
|
)
|
||||||
from .init import init
|
from .init import init
|
||||||
from .check_plugin_status import check_plugin_status
|
from .check_plugin_status import check_plugin_status
|
||||||
from utils.manager import admin_manager
|
|
||||||
from nonebot.adapters.cqhttp import Bot
|
from nonebot.adapters.cqhttp import Bot
|
||||||
from configs.path_config import DATA_PATH
|
from configs.path_config import DATA_PATH
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ def init_plugins_settings(data_path: str):
|
|||||||
plugin_settings = _module.__getattribute__(
|
plugin_settings = _module.__getattribute__(
|
||||||
"__plugin_settings__"
|
"__plugin_settings__"
|
||||||
)
|
)
|
||||||
|
if plugin_settings.get('cost_gold') is None:
|
||||||
|
plugin_settings['cost_gold'] = 0
|
||||||
if (
|
if (
|
||||||
plugin_settings["cmd"] is not None
|
plugin_settings["cmd"] is not None
|
||||||
and plugin_name not in plugin_settings["cmd"]
|
and plugin_name not in plugin_settings["cmd"]
|
||||||
@@ -97,7 +99,7 @@ def init_plugins_settings(data_path: str):
|
|||||||
plugins2settings_manager.add_plugin_settings(
|
plugins2settings_manager.add_plugin_settings(
|
||||||
matcher.module,
|
matcher.module,
|
||||||
plugin_type=plugin_type,
|
plugin_type=plugin_type,
|
||||||
data_dict=plugin_settings,
|
**plugin_settings,
|
||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
+130
-25
@@ -1,12 +1,19 @@
|
|||||||
|
from asyncpg.exceptions import (
|
||||||
|
DuplicateColumnError,
|
||||||
|
UndefinedColumnError,
|
||||||
|
PostgresSyntaxError,
|
||||||
|
)
|
||||||
from nonebot import Driver
|
from nonebot import Driver
|
||||||
from services.db_context import db
|
from services.db_context import db
|
||||||
from asyncpg.exceptions import DuplicateColumnError
|
|
||||||
from models.group_info import GroupInfo
|
from models.group_info import GroupInfo
|
||||||
|
from models.bag_user import BagUser
|
||||||
from nonebot.adapters.cqhttp import Bot
|
from nonebot.adapters.cqhttp import Bot
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from configs.path_config import TEXT_PATH
|
from configs.path_config import TEXT_PATH
|
||||||
from asyncio.exceptions import TimeoutError
|
from asyncio.exceptions import TimeoutError
|
||||||
|
from typing import List
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
|
from utils.utils import scheduler
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import nonebot
|
import nonebot
|
||||||
|
|
||||||
@@ -27,31 +34,32 @@ async def update_city():
|
|||||||
"""
|
"""
|
||||||
china_city = Path(TEXT_PATH) / "china_city.json"
|
china_city = Path(TEXT_PATH) / "china_city.json"
|
||||||
data = {}
|
data = {}
|
||||||
try:
|
if not china_city.exists():
|
||||||
res = await AsyncHttpx.get(
|
try:
|
||||||
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
|
|
||||||
)
|
|
||||||
res.encoding = "utf8"
|
|
||||||
provinces_data = json.loads(res.text)
|
|
||||||
for province in provinces_data.keys():
|
|
||||||
data[provinces_data[province]] = []
|
|
||||||
res = await AsyncHttpx.get(
|
res = await AsyncHttpx.get(
|
||||||
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
|
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
|
||||||
timeout=5,
|
|
||||||
)
|
)
|
||||||
res.encoding = "utf8"
|
res.encoding = "utf8"
|
||||||
city_data = json.loads(res.text)
|
provinces_data = json.loads(res.text)
|
||||||
for city in city_data.keys():
|
for province in provinces_data.keys():
|
||||||
data[provinces_data[province]].append(city_data[city])
|
data[provinces_data[province]] = []
|
||||||
with open(china_city, "w", encoding="utf8") as f:
|
res = await AsyncHttpx.get(
|
||||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
|
||||||
logger.info("自动更新城市列表完成.....")
|
timeout=5,
|
||||||
except TimeoutError:
|
)
|
||||||
logger.warning("自动更新城市列表超时.....")
|
res.encoding = "utf8"
|
||||||
except ValueError:
|
city_data = json.loads(res.text)
|
||||||
logger.warning("自动城市列表失败.....")
|
for city in city_data.keys():
|
||||||
except Exception as e:
|
data[provinces_data[province]].append(city_data[city])
|
||||||
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
|
with open(china_city, "w", encoding="utf8") as f:
|
||||||
|
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||||
|
logger.info("自动更新城市列表完成.....")
|
||||||
|
except TimeoutError:
|
||||||
|
logger.warning("自动更新城市列表超时.....")
|
||||||
|
except ValueError:
|
||||||
|
logger.warning("自动城市列表失败.....")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
|
||||||
|
|
||||||
|
|
||||||
@driver.on_startup
|
@driver.on_startup
|
||||||
@@ -59,15 +67,82 @@ async def _():
|
|||||||
"""
|
"""
|
||||||
数据库表结构变换
|
数据库表结构变换
|
||||||
"""
|
"""
|
||||||
|
_flag = []
|
||||||
sql_str = [
|
sql_str = [
|
||||||
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;" # group_info表添加一个group_flag
|
(
|
||||||
|
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;",
|
||||||
|
"group_info",
|
||||||
|
), # group_info表添加一个group_flag
|
||||||
|
(
|
||||||
|
"ALTER TABLE bag_users rename belonging_group To group_id;",
|
||||||
|
"bag_users",
|
||||||
|
), # 将 bag_users 的 belonging_group 改为 group_id
|
||||||
|
(
|
||||||
|
"ALTER TABLE group_info_users rename belonging_group To group_id;",
|
||||||
|
"group_info_users",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"ALTER TABLE sign_group_users rename belonging_group To group_id;",
|
||||||
|
"sign_group_users",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"ALTER TABLE open_cases_users rename belonging_group To group_id;",
|
||||||
|
"open_cases_users",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"ALTER TABLE bag_users ADD property json NOT NULL DEFAULT '{}';",
|
||||||
|
"bag_users",
|
||||||
|
), # bag_users 新增字段 property 替代 props
|
||||||
|
(
|
||||||
|
"ALTER TABLE genshin ADD auto_sign_time timestamp with time zone;",
|
||||||
|
"genshin"
|
||||||
|
), # 新增原神自动签到字段
|
||||||
|
(
|
||||||
|
"ALTER TABLE genshin ADD resin_remind boolean DEFAULT False;",
|
||||||
|
"genshin"
|
||||||
|
), # 新增原神自动签到字段
|
||||||
|
(
|
||||||
|
"ALTER TABLE genshin ADD resin_recovery_time timestamp with time zone;",
|
||||||
|
"genshin"
|
||||||
|
), # 新增原神自动签到字段
|
||||||
]
|
]
|
||||||
for sql in sql_str:
|
for sql in sql_str:
|
||||||
try:
|
try:
|
||||||
|
flag = sql[1]
|
||||||
|
sql = sql[0]
|
||||||
query = db.text(sql)
|
query = db.text(sql)
|
||||||
await db.first(query)
|
await db.first(query)
|
||||||
except DuplicateColumnError:
|
logger.info(f"完成sql操作:{sql}")
|
||||||
|
_flag.append(flag)
|
||||||
|
except (DuplicateColumnError, UndefinedColumnError):
|
||||||
pass
|
pass
|
||||||
|
except PostgresSyntaxError:
|
||||||
|
logger.error(f"语法错误:执行sql失败:{sql}")
|
||||||
|
# bag_user 将文本转为字典格式
|
||||||
|
await __database_script(_flag)
|
||||||
|
|
||||||
|
# 完成后
|
||||||
|
end_sql_str = [
|
||||||
|
# "ALTER TABLE bag_users DROP COLUMN props;" # 删除 bag_users 的 props 字段(还不到时候)
|
||||||
|
]
|
||||||
|
for sql in end_sql_str:
|
||||||
|
try:
|
||||||
|
query = db.text(sql)
|
||||||
|
await db.first(query)
|
||||||
|
logger.info(f"完成执行sql操作:{sql}")
|
||||||
|
except (DuplicateColumnError, UndefinedColumnError):
|
||||||
|
pass
|
||||||
|
except PostgresSyntaxError:
|
||||||
|
logger.error(f"语法错误:执行sql失败:{sql}")
|
||||||
|
|
||||||
|
# str2json_sql = ["alter table bag_users alter COLUMN props type json USING props::json;"] # 字段类型替换
|
||||||
|
# rename_sql = 'alter table {} rename {} to {};' # 字段更名
|
||||||
|
# for sql in str2json_sql:
|
||||||
|
# try:
|
||||||
|
# query = db.text(sql)
|
||||||
|
# await db.first(query)
|
||||||
|
# except DuplicateColumnError:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
|
||||||
@driver.on_bot_connect
|
@driver.on_bot_connect
|
||||||
@@ -101,3 +176,33 @@ async def _(bot: Bot):
|
|||||||
else:
|
else:
|
||||||
await GroupInfo.delete_group_info(group_id)
|
await GroupInfo.delete_group_info(group_id)
|
||||||
logger.info(f"移除不存在的群聊信息:{group_id}")
|
logger.info(f"移除不存在的群聊信息:{group_id}")
|
||||||
|
|
||||||
|
|
||||||
|
async def __database_script(_flag: List[str]):
|
||||||
|
# bag_user 将文本转为字典格式
|
||||||
|
if "bag_users" in _flag:
|
||||||
|
for x in await BagUser.get_all_users():
|
||||||
|
props = {}
|
||||||
|
if x.props:
|
||||||
|
for prop in [p for p in x.props.split(",") if p]:
|
||||||
|
if props.get(prop):
|
||||||
|
props[prop] += 1
|
||||||
|
else:
|
||||||
|
props[prop] = 1
|
||||||
|
logger.info(
|
||||||
|
f"__database_script USER {x.user_qq} GROUP {x.group_id} 更新数据 {props}"
|
||||||
|
)
|
||||||
|
await x.update(
|
||||||
|
property=props,
|
||||||
|
props="",
|
||||||
|
).apply()
|
||||||
|
|
||||||
|
|
||||||
|
# 自动更新城市列表
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
"cron",
|
||||||
|
hour=6,
|
||||||
|
minute=1,
|
||||||
|
)
|
||||||
|
async def _():
|
||||||
|
await update_city()
|
||||||
|
|||||||
Executable → Regular
+1
-1
@@ -11,4 +11,4 @@ Config.add_plugin_config(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
nonebot.load_plugins("plugins/shop")
|
nonebot.load_plugins("basic_plugins/shop")
|
||||||
Executable → Regular
+94
-89
@@ -1,89 +1,94 @@
|
|||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from utils.utils import get_message_text, is_number
|
from utils.utils import get_message_text, is_number
|
||||||
from models.bag_user import BagUser
|
from models.bag_user import BagUser
|
||||||
from services.db_context import db
|
from services.db_context import db
|
||||||
from nonebot.adapters.cqhttp.permission import GROUP
|
from nonebot.adapters.cqhttp.permission import GROUP
|
||||||
from .models.goods_info import GoodsInfo
|
from models.goods_info import GoodsInfo
|
||||||
|
import time
|
||||||
|
|
||||||
__zx_plugin_name__ = "商店 - 购买道具"
|
|
||||||
__plugin_usage__ = """
|
__zx_plugin_name__ = "商店 - 购买道具"
|
||||||
usage:
|
__plugin_usage__ = """
|
||||||
购买道具
|
usage:
|
||||||
指令:
|
购买道具
|
||||||
购买 [序号或名称] ?[数量=1]
|
指令:
|
||||||
示例:购买 好感双倍加持卡Ⅰ
|
购买 [序号或名称] ?[数量=1]
|
||||||
示例:购买 1 4
|
示例:购买 好感双倍加持卡Ⅰ
|
||||||
""".strip()
|
示例:购买 1 4
|
||||||
__plugin_des__ = "商店 - 购买道具"
|
""".strip()
|
||||||
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
__plugin_des__ = "商店 - 购买道具"
|
||||||
__plugin_type__ = ('商店',)
|
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
||||||
__plugin_version__ = 0.1
|
__plugin_type__ = ("商店",)
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_version__ = 0.1
|
||||||
__plugin_settings__ = {
|
__plugin_author__ = "HibiKier"
|
||||||
"level": 5,
|
__plugin_settings__ = {
|
||||||
"default_status": True,
|
"level": 5,
|
||||||
"limit_superuser": False,
|
"default_status": True,
|
||||||
"cmd": ["商店", "购买道具"],
|
"limit_superuser": False,
|
||||||
}
|
"cmd": ["商店", "购买道具"],
|
||||||
|
}
|
||||||
|
__plugin_cd_limit__ = {"cd": 3}
|
||||||
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
|
|
||||||
|
|
||||||
|
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
|
||||||
@buy.handle()
|
|
||||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|
||||||
if get_message_text(event.json()) in ["神秘药水"]:
|
@buy.handle()
|
||||||
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||||
goods_lst = await GoodsInfo.get_all_goods()
|
goods = None
|
||||||
goods_name_lst = [x.goods_name for x in goods_lst]
|
if get_message_text(event.json()) in ["神秘药水"]:
|
||||||
msg = get_message_text(event.json()).strip().split(" ")
|
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
||||||
num = 1
|
goods_list = [
|
||||||
if len(msg) > 1:
|
x
|
||||||
if is_number(msg[1]) and int(msg[1]) > 0:
|
for x in await GoodsInfo.get_all_goods()
|
||||||
num = int(msg[1])
|
if x.goods_limit_time > time.time() or x.goods_limit_time == 0
|
||||||
else:
|
]
|
||||||
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
|
goods_name_list = [
|
||||||
# print(msg, num)
|
x.goods_name
|
||||||
if is_number(msg[0]):
|
for x in goods_list
|
||||||
msg = int(msg[0])
|
]
|
||||||
if msg > len(goods_lst) or msg < 1:
|
msg = get_message_text(event.json()).split()
|
||||||
await buy.finish("请输入正确的商品id!", at_sender=True)
|
num = 1
|
||||||
goods = goods_lst[msg - 1]
|
if len(msg) > 1:
|
||||||
else:
|
if is_number(msg[1]) and int(msg[1]) > 0:
|
||||||
if msg[0] in goods_name_lst:
|
num = int(msg[1])
|
||||||
for i in range(len(goods_name_lst)):
|
else:
|
||||||
if msg[0] == goods_name_lst[i]:
|
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
|
||||||
goods = goods_lst[i]
|
if is_number(msg[0]):
|
||||||
break
|
msg = int(msg[0])
|
||||||
else:
|
if msg > len(goods_name_list) or msg < 1:
|
||||||
await buy.finish("请输入正确的商品名称!")
|
await buy.finish("请输入正确的商品id!", at_sender=True)
|
||||||
else:
|
goods = goods_list[msg - 1]
|
||||||
await buy.finish("请输入正确的商品名称!", at_sender=True)
|
else:
|
||||||
async with db.transaction():
|
if msg[0] in goods_name_list:
|
||||||
if (
|
for i in range(len(goods_name_list)):
|
||||||
await BagUser.get_gold(event.user_id, event.group_id)
|
if msg[0] == goods_name_list[i]:
|
||||||
) < goods.goods_price * num:
|
goods = goods_list[i]
|
||||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
break
|
||||||
if await BagUser.spend_gold(
|
else:
|
||||||
event.user_id, event.group_id, goods.goods_price * num
|
await buy.finish("请输入正确的商品名称!")
|
||||||
):
|
else:
|
||||||
for _ in range(num):
|
await buy.finish("请输入正确的商品名称!", at_sender=True)
|
||||||
await BagUser.add_props(event.user_id, event.group_id, goods.goods_name)
|
async with db.transaction():
|
||||||
await buy.send(
|
if (
|
||||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!",
|
await BagUser.get_gold(event.user_id, event.group_id)
|
||||||
at_sender=True,
|
) < goods.goods_price * num * goods.goods_discount:
|
||||||
)
|
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||||
logger.info(
|
if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
|
||||||
f"USER {event.user_id} GROUP {event.group_id} "
|
await buy.send(
|
||||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||||
)
|
at_sender=True,
|
||||||
else:
|
)
|
||||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
logger.info(
|
||||||
logger.info(
|
f"USER {event.user_id} GROUP {event.group_id} "
|
||||||
f"USER {event.user_id} GROUP {event.group_id} "
|
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 失败!"
|
)
|
||||||
)
|
else:
|
||||||
|
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||||
|
logger.info(
|
||||||
|
f"USER {event.user_id} GROUP {event.group_id} "
|
||||||
|
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 失败!"
|
||||||
|
)
|
||||||
Executable → Regular
+1
-1
@@ -34,7 +34,7 @@ gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP)
|
|||||||
|
|
||||||
@my_gold.handle()
|
@my_gold.handle()
|
||||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||||
await my_gold.finish(await BagUser.get_my_total_gold(event.user_id, event.group_id))
|
await my_gold.finish(await BagUser.get_user_total_gold(event.user_id, event.group_id))
|
||||||
|
|
||||||
|
|
||||||
@gold_rank.handle()
|
@gold_rank.handle()
|
||||||
Executable → Regular
+42
-52
@@ -1,52 +1,42 @@
|
|||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from models.bag_user import BagUser
|
from models.bag_user import BagUser
|
||||||
from nonebot.adapters.cqhttp.permission import GROUP
|
from nonebot.adapters.cqhttp.permission import GROUP
|
||||||
|
|
||||||
|
|
||||||
__zx_plugin_name__ = "商店 - 我的道具"
|
__zx_plugin_name__ = "商店 - 我的道具"
|
||||||
__plugin_usage__ = """
|
__plugin_usage__ = """
|
||||||
usage:
|
usage:
|
||||||
我的道具
|
我的道具
|
||||||
指令:
|
指令:
|
||||||
我的道具
|
我的道具
|
||||||
""".strip()
|
""".strip()
|
||||||
__plugin_des__ = "商店 - 我的道具"
|
__plugin_des__ = "商店 - 我的道具"
|
||||||
__plugin_cmd__ = ["我的道具"]
|
__plugin_cmd__ = ["我的道具"]
|
||||||
__plugin_type__ = ('商店',)
|
__plugin_type__ = ('商店',)
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier"
|
||||||
__plugin_settings__ = {
|
__plugin_settings__ = {
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"default_status": True,
|
"default_status": True,
|
||||||
"limit_superuser": False,
|
"limit_superuser": False,
|
||||||
"cmd": ["商店", "我的道具"],
|
"cmd": ["商店", "我的道具"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||||
|
|
||||||
|
|
||||||
@my_props.handle()
|
@my_props.handle()
|
||||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
props = await BagUser.get_property(event.user_id, event.group_id)
|
||||||
if props:
|
if props:
|
||||||
pname_list = []
|
rst = ""
|
||||||
pnum_list = []
|
for i, p in enumerate(props.keys()):
|
||||||
rst = ""
|
rst += f"{i+1}.{p}\t×{props[p]}\n"
|
||||||
props = props[:-1].split(",")
|
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||||
for p in props:
|
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||||
if p != "":
|
else:
|
||||||
if p in pname_list:
|
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||||
pnum_list[pname_list.index(p)] += 1
|
|
||||||
else:
|
|
||||||
pname_list.append(p)
|
|
||||||
pnum_list.append(1)
|
|
||||||
for i in range(len(pname_list)):
|
|
||||||
rst += f"{i+1}.{pname_list[i]}\t×{pnum_list[i]}\n"
|
|
||||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
|
||||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
|
||||||
else:
|
|
||||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
|
||||||
Executable → Regular
+26
-26
@@ -1,26 +1,26 @@
|
|||||||
from utils.utils import scheduler
|
from utils.utils import scheduler
|
||||||
from models.bag_user import BagUser
|
from models.bag_user import BagUser
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
|
|
||||||
|
|
||||||
__zx_plugin_name__ = "每日金币重置 [Hidden]"
|
__zx_plugin_name__ = "每日金币重置 [Hidden]"
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier"
|
||||||
|
|
||||||
|
|
||||||
# 重置每日金币
|
# 重置每日金币
|
||||||
@scheduler.scheduled_job(
|
@scheduler.scheduled_job(
|
||||||
"cron",
|
"cron",
|
||||||
hour=0,
|
hour=0,
|
||||||
minute=1,
|
minute=1,
|
||||||
)
|
)
|
||||||
async def _():
|
async def _():
|
||||||
try:
|
try:
|
||||||
user_list = await BagUser.get_all_users()
|
user_list = await BagUser.get_all_users()
|
||||||
for user in user_list:
|
for user in user_list:
|
||||||
await user.update(
|
await user.update(
|
||||||
get_today_gold=0,
|
get_today_gold=0,
|
||||||
spend_today_gold=0,
|
spend_today_gold=0,
|
||||||
).apply()
|
).apply()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"重置每日金币错误 e:{e}")
|
logger.error(f"重置每日金币错误 e:{e}")
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
from nonebot import on_command
|
||||||
|
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||||
|
from nonebot.typing import T_State
|
||||||
|
from configs.path_config import IMAGE_PATH
|
||||||
|
from utils.message_builder import image
|
||||||
|
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from utils.utils import get_message_text, is_number
|
||||||
|
from nonebot.plugin import export
|
||||||
|
from services.log import logger
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
__zx_plugin_name__ = "商店"
|
||||||
|
__plugin_usage__ = """
|
||||||
|
usage:
|
||||||
|
商店项目,这可不是奸商
|
||||||
|
指令:
|
||||||
|
商店
|
||||||
|
""".strip()
|
||||||
|
__plugin_superuser_usage__ = """
|
||||||
|
usage:
|
||||||
|
商品操作
|
||||||
|
指令:
|
||||||
|
添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)
|
||||||
|
删除商品 [名称或序号]
|
||||||
|
修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时]
|
||||||
|
示例:添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
|
||||||
|
示例:添加商品 name:可疑的药 price:5 des:效果未知
|
||||||
|
示例:删除商品 2
|
||||||
|
示例:修改商品 name:1 price:900 修改序号为1的商品的价格为900
|
||||||
|
* 修改商品只需添加需要值即可 *
|
||||||
|
""".strip()
|
||||||
|
__plugin_des__ = "商店系统[金币回收计划]"
|
||||||
|
__plugin_cmd__ = [
|
||||||
|
"商店",
|
||||||
|
"添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)) [_superuser]",
|
||||||
|
"删除商品 [名称或序号] [_superuser]",
|
||||||
|
"修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时] [_superuser]",
|
||||||
|
]
|
||||||
|
__plugin_type__ = ('商店',)
|
||||||
|
__plugin_version__ = 0.1
|
||||||
|
__plugin_author__ = "HibiKier"
|
||||||
|
__plugin_settings__ = {
|
||||||
|
"level": 5,
|
||||||
|
"default_status": True,
|
||||||
|
"limit_superuser": False,
|
||||||
|
"cmd": ["商店"],
|
||||||
|
}
|
||||||
|
__plugin_block_limit__ = {
|
||||||
|
"limit_type": "group"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 导出方法供其他插件使用
|
||||||
|
export = export()
|
||||||
|
export.register_goods = register_goods
|
||||||
|
export.delete_goods = delete_goods
|
||||||
|
export.update_goods = update_goods
|
||||||
|
|
||||||
|
shop_help = on_command("商店", priority=5, block=True)
|
||||||
|
|
||||||
|
shop_add_goods = on_command("添加商品", priority=5, permission=SUPERUSER, block=True)
|
||||||
|
|
||||||
|
shop_del_goods = on_command("删除商品", priority=5, permission=SUPERUSER, block=True)
|
||||||
|
|
||||||
|
shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER, block=True)
|
||||||
|
|
||||||
|
|
||||||
|
@shop_help.handle()
|
||||||
|
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||||
|
await shop_help.send(image(b64=await create_shop_help()))
|
||||||
|
|
||||||
|
|
||||||
|
@shop_add_goods.handle()
|
||||||
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
|
msg = get_message_text(event.json())
|
||||||
|
if msg:
|
||||||
|
data = parse_goods_info(msg)
|
||||||
|
if isinstance(data, str):
|
||||||
|
await shop_add_goods.finish(data)
|
||||||
|
if not data.get("name") or not data.get("price") or not data.get("des"):
|
||||||
|
await shop_add_goods.finish("name:price:des 参数不可缺少!")
|
||||||
|
if await register_goods(**data):
|
||||||
|
await shop_add_goods.send(f"添加商品 {data['name']} 成功!\n"
|
||||||
|
f"名称:{data['name']}\n"
|
||||||
|
f"价格:{data['price']}金币\n"
|
||||||
|
f"简介:{data['des']}\n"
|
||||||
|
f"折扣:{data.get('discount')}\n"
|
||||||
|
f"限时:{data.get('limit_time')}", at_sender=True)
|
||||||
|
logger.info(f"USER {event.user_id} 添加商品 {msg} 成功")
|
||||||
|
else:
|
||||||
|
await shop_add_goods.send(f"添加商品 {msg} 失败了...", at_sender=True)
|
||||||
|
logger.warning(f"USER {event.user_id} 添加商品 {msg} 失败")
|
||||||
|
|
||||||
|
|
||||||
|
@shop_del_goods.handle()
|
||||||
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
|
msg = get_message_text(event.json())
|
||||||
|
if msg:
|
||||||
|
name = ""
|
||||||
|
id_ = 0
|
||||||
|
if is_number(msg):
|
||||||
|
id_ = int(msg)
|
||||||
|
else:
|
||||||
|
name = msg
|
||||||
|
rst, goods_name, code = await delete_goods(name, id_)
|
||||||
|
if code == 200:
|
||||||
|
await shop_del_goods.send(f"删除商品 {goods_name} 成功了...", at_sender=True)
|
||||||
|
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
||||||
|
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
||||||
|
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 成功")
|
||||||
|
else:
|
||||||
|
await shop_del_goods.send(f"删除商品 {goods_name} 失败了...", at_sender=True)
|
||||||
|
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 失败")
|
||||||
|
|
||||||
|
|
||||||
|
@shop_update_goods.handle()
|
||||||
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
|
msg = get_message_text(event.json())
|
||||||
|
if msg:
|
||||||
|
data = parse_goods_info(msg)
|
||||||
|
if isinstance(data, str):
|
||||||
|
await shop_add_goods.finish(data)
|
||||||
|
if not data.get("name"):
|
||||||
|
await shop_add_goods.finish("name 参数不可缺少!")
|
||||||
|
flag, name, text = await update_goods(**data)
|
||||||
|
if flag:
|
||||||
|
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
|
||||||
|
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功")
|
||||||
|
else:
|
||||||
|
await shop_update_goods.send(f"修改商品 {name} 失败了...", at_sender=True)
|
||||||
|
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败")
|
||||||
|
|
||||||
@@ -0,0 +1,269 @@
|
|||||||
|
from models.goods_info import GoodsInfo
|
||||||
|
from utils.image_utils import BuildImage
|
||||||
|
from models.sign_group_user import SignGroupUser
|
||||||
|
from utils.utils import is_number
|
||||||
|
from configs.path_config import IMAGE_PATH
|
||||||
|
from typing import Optional, Union
|
||||||
|
from configs.config import Config
|
||||||
|
from nonebot import Driver
|
||||||
|
from nonebot.plugin import require
|
||||||
|
import nonebot
|
||||||
|
import time
|
||||||
|
|
||||||
|
driver: Driver = nonebot.get_driver()
|
||||||
|
|
||||||
|
use = require("use")
|
||||||
|
|
||||||
|
|
||||||
|
@driver.on_startup
|
||||||
|
async def init_default_shop_goods():
|
||||||
|
"""
|
||||||
|
导入内置的三个商品
|
||||||
|
"""
|
||||||
|
async def sign_card(**kwargs):
|
||||||
|
user_id = kwargs['user_id']
|
||||||
|
group_id = kwargs['group_id']
|
||||||
|
prob = kwargs["prob"]
|
||||||
|
user = await SignGroupUser.ensure(user_id, group_id)
|
||||||
|
await user.update(add_probability=prob).apply()
|
||||||
|
|
||||||
|
if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
|
||||||
|
await register_goods(
|
||||||
|
"好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"
|
||||||
|
)
|
||||||
|
use.register_use("好感度双倍加持卡Ⅰ", sign_card, **{"prob": 0.1})
|
||||||
|
await register_goods("好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)")
|
||||||
|
use.register_use("好感度双倍加持卡Ⅱ", sign_card, **{"prob": 0.2})
|
||||||
|
await register_goods(
|
||||||
|
"好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"
|
||||||
|
)
|
||||||
|
use.register_use("好感度双倍加持卡Ⅲ", sign_card, **{"prob": 0.3})
|
||||||
|
|
||||||
|
|
||||||
|
# 创建商店界面
|
||||||
|
async def create_shop_help() -> str:
|
||||||
|
"""
|
||||||
|
制作商店图片
|
||||||
|
:return: 图片base64
|
||||||
|
"""
|
||||||
|
goods_lst = await GoodsInfo.get_all_goods()
|
||||||
|
idx = 1
|
||||||
|
_dc = {}
|
||||||
|
font_h = BuildImage(0, 0).getsize("正")[1]
|
||||||
|
h = 10
|
||||||
|
_list = []
|
||||||
|
for goods in goods_lst:
|
||||||
|
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time:
|
||||||
|
h += len(goods.goods_description.strip().split("\n")) * font_h + 80
|
||||||
|
_list.append(goods)
|
||||||
|
A = BuildImage(1000, h, color="#f9f6f2")
|
||||||
|
current_h = 0
|
||||||
|
for goods in _list:
|
||||||
|
bk = BuildImage(
|
||||||
|
700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf"
|
||||||
|
)
|
||||||
|
goods_image = BuildImage(
|
||||||
|
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
|
||||||
|
)
|
||||||
|
name_image = BuildImage(
|
||||||
|
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
|
||||||
|
)
|
||||||
|
await name_image.atext(
|
||||||
|
(15, 0), f"{idx}.{goods.goods_name}", center_type="by_height"
|
||||||
|
)
|
||||||
|
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
|
||||||
|
await name_image.atext((390, 0), "售价:", center_type="by_height")
|
||||||
|
await name_image.atext(
|
||||||
|
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
|
||||||
|
)
|
||||||
|
await name_image.atext(
|
||||||
|
(
|
||||||
|
440
|
||||||
|
+ BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
" 金币",
|
||||||
|
center_type="by_height",
|
||||||
|
)
|
||||||
|
await name_image.acircle_corner(5)
|
||||||
|
await goods_image.apaste(name_image, (0, 5), True, center_type="by_width")
|
||||||
|
await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
|
||||||
|
await goods_image.acircle_corner(20)
|
||||||
|
await bk.apaste(goods_image, alpha=True)
|
||||||
|
# 添加限时图标和时间
|
||||||
|
if goods.goods_limit_time > 0:
|
||||||
|
_limit_time_logo = BuildImage(40, 40, background=f"{IMAGE_PATH}/other/time.png")
|
||||||
|
await bk.apaste(_limit_time_logo, (600, 0), True)
|
||||||
|
await bk.apaste(BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"), (640, 10), True)
|
||||||
|
limit_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)).split()
|
||||||
|
y_m_d = limit_time[0]
|
||||||
|
_h_m = limit_time[1].split(":")
|
||||||
|
h_m = _h_m[0] + "时 " + _h_m[1] + "分"
|
||||||
|
await bk.atext((605, 38), str(y_m_d))
|
||||||
|
await bk.atext((615, 57), str(h_m))
|
||||||
|
await bk.aline((550, -1, 710, -1), "#a29ad6", 5)
|
||||||
|
await bk.aline((550, 80, 710, 80), "#a29ad6", 5)
|
||||||
|
idx += 1
|
||||||
|
await A.apaste(bk, (0, current_h), True)
|
||||||
|
current_h += 90
|
||||||
|
w = 1000
|
||||||
|
h = A.h + 230 + 100
|
||||||
|
h = 1000 if h < 1000 else h
|
||||||
|
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
|
||||||
|
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
|
||||||
|
shop.paste(A, (20, 230))
|
||||||
|
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan.png")
|
||||||
|
zx_img.replace_color_tran(((240, 240, 240), (255, 255, 255)), (249, 246, 242))
|
||||||
|
await shop.apaste(zx_img, (780, 100))
|
||||||
|
await shop.apaste(shop_logo, (450, 30), True)
|
||||||
|
shop.text(
|
||||||
|
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
|
||||||
|
"注【通过 序号 或者 商品名称 购买】",
|
||||||
|
)
|
||||||
|
shop.text((20, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
|
||||||
|
return shop.pic2bs4()
|
||||||
|
|
||||||
|
|
||||||
|
async def register_goods(
|
||||||
|
name: str,
|
||||||
|
price: int,
|
||||||
|
des: str,
|
||||||
|
discount: Optional[float] = 1,
|
||||||
|
limit_time: Optional[int] = 0,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
添加商品
|
||||||
|
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
|
||||||
|
添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
|
||||||
|
添加商品 name:可疑的药 price:5 des:效果未知
|
||||||
|
:param name: 商品名称
|
||||||
|
:param price: 商品价格
|
||||||
|
:param des: 商品简介
|
||||||
|
:param discount: 商品折扣
|
||||||
|
:param limit_time: 商品限时销售时间,单位为小时
|
||||||
|
:param kwargs: kwargs
|
||||||
|
:return: 是否添加成功
|
||||||
|
"""
|
||||||
|
if kwargs:
|
||||||
|
name = kwargs.get("name")
|
||||||
|
price = kwargs.get("price")
|
||||||
|
des = kwargs.get("des")
|
||||||
|
discount = kwargs.get("discount")
|
||||||
|
limit_time = kwargs.get("time_limit")
|
||||||
|
limit_time = float(limit_time) if limit_time else limit_time
|
||||||
|
discount = discount if discount is None else 1
|
||||||
|
limit_time = int(time.time() + limit_time * 60 * 60) if limit_time is not None and limit_time != 0 else 0
|
||||||
|
return await GoodsInfo.add_goods(
|
||||||
|
name, int(price), des, float(discount), limit_time
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# 删除商品
|
||||||
|
async def delete_goods(name: str, id_: int) -> "str, str, int":
|
||||||
|
"""
|
||||||
|
删除商品
|
||||||
|
:param name: 商品名称
|
||||||
|
:param id_: 商品id
|
||||||
|
:return: 删除状况
|
||||||
|
"""
|
||||||
|
goods_lst = await GoodsInfo.get_all_goods()
|
||||||
|
if id_:
|
||||||
|
if id_ < 1 or id_ > len(goods_lst):
|
||||||
|
return "序号错误,没有该序号商品...", "", 999
|
||||||
|
goods_name = goods_lst[id_ - 1].goods_name
|
||||||
|
if await GoodsInfo.delete_goods(goods_name):
|
||||||
|
return f"删除商品 {goods_name} 成功!", goods_name, 200
|
||||||
|
else:
|
||||||
|
return f"删除商品 {goods_name} 失败!", goods_name, 999
|
||||||
|
if name:
|
||||||
|
if await GoodsInfo.delete_goods(name):
|
||||||
|
return f"删除商品 {name} 成功!", name, 200
|
||||||
|
else:
|
||||||
|
return f"删除商品 {name} 失败!", name, 999
|
||||||
|
|
||||||
|
|
||||||
|
# 更新商品信息
|
||||||
|
async def update_goods(**kwargs) -> "str, str, int":
|
||||||
|
"""
|
||||||
|
更新商品信息
|
||||||
|
:param kwargs: kwargs
|
||||||
|
:return: 更新状况
|
||||||
|
"""
|
||||||
|
if kwargs:
|
||||||
|
goods_lst = await GoodsInfo.get_all_goods()
|
||||||
|
if is_number(kwargs["name"]):
|
||||||
|
if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst):
|
||||||
|
return "序号错误,没有该序号的商品...", "", 999
|
||||||
|
goods = goods_lst[int(kwargs["name"]) - 1]
|
||||||
|
else:
|
||||||
|
goods = await GoodsInfo.get_goods_info(kwargs["name"])
|
||||||
|
if not goods:
|
||||||
|
return "名称错误,没有该名称的商品...", "", 999
|
||||||
|
name = goods.goods_name
|
||||||
|
price = goods.goods_price
|
||||||
|
des = goods.goods_description
|
||||||
|
discount = goods.goods_discount
|
||||||
|
limit_time = goods.goods_limit_time
|
||||||
|
new_time = 0
|
||||||
|
tmp = ""
|
||||||
|
if kwargs.get("price"):
|
||||||
|
tmp += f'价格:{price} --> {kwargs["price"]}\n'
|
||||||
|
price = kwargs["price"]
|
||||||
|
if kwargs.get("des"):
|
||||||
|
tmp += f'描述:{des} --> {kwargs["des"]}\n'
|
||||||
|
des = kwargs["des"]
|
||||||
|
if kwargs.get("discount"):
|
||||||
|
tmp += f'折扣:{discount} --> {kwargs["discount"]}\n'
|
||||||
|
discount = kwargs["discount"]
|
||||||
|
if kwargs.get("limit_time"):
|
||||||
|
kwargs["limit_time"] = float(kwargs["limit_time"])
|
||||||
|
new_time = time.strftime(
|
||||||
|
"%Y-%m-%d %H:%M:%S",
|
||||||
|
time.localtime(time.time() + kwargs["limit_time"] * 60 * 60),
|
||||||
|
)
|
||||||
|
tmp += f"限时至: {new_time}\n"
|
||||||
|
limit_time = kwargs["limit_time"]
|
||||||
|
return (
|
||||||
|
await GoodsInfo.update_goods(
|
||||||
|
name,
|
||||||
|
int(price),
|
||||||
|
des,
|
||||||
|
float(discount),
|
||||||
|
int(time.time() + limit_time * 60 * 60 if limit_time != 0 and new_time else 0),
|
||||||
|
),
|
||||||
|
name,
|
||||||
|
tmp[:-1],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_goods_info(msg: str) -> Union[dict, str]:
|
||||||
|
"""
|
||||||
|
解析格式数据
|
||||||
|
:param msg: 消息
|
||||||
|
:return: 解析完毕的数据data
|
||||||
|
"""
|
||||||
|
if "name:" not in msg:
|
||||||
|
return "必须指定修改的商品名称或序号!"
|
||||||
|
data = {}
|
||||||
|
for x in msg.split():
|
||||||
|
sp = x.split(":", maxsplit=1)
|
||||||
|
if str(sp[1]).strip():
|
||||||
|
sp[1] = sp[1].strip()
|
||||||
|
if sp[0] == "name":
|
||||||
|
data["name"] = sp[1]
|
||||||
|
elif sp[0] == "price":
|
||||||
|
if not is_number(sp[1]) or int(sp[1]) < 0:
|
||||||
|
return "price参数不合法,必须大于等于0!"
|
||||||
|
data["price"] = sp[1]
|
||||||
|
elif sp[0] == "des":
|
||||||
|
data["des"] = sp[1]
|
||||||
|
elif sp[0] == "discount":
|
||||||
|
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||||
|
return "discount参数不合法,必须大于0!"
|
||||||
|
data["discount"] = sp[1]
|
||||||
|
elif sp[0] == "limit_time":
|
||||||
|
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||||
|
return "limit_time参数不合法,必须大于0!"
|
||||||
|
data["limit_time"] = sp[1]
|
||||||
|
return data
|
||||||
Executable → Regular
+83
-71
@@ -1,71 +1,83 @@
|
|||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from utils.utils import is_number, get_message_text
|
from utils.utils import is_number, get_message_text
|
||||||
from models.bag_user import BagUser
|
from models.bag_user import BagUser
|
||||||
from nonebot.adapters.cqhttp.permission import GROUP
|
from nonebot.adapters.cqhttp.permission import GROUP
|
||||||
from services.db_context import db
|
from services.db_context import db
|
||||||
from .data_source import effect
|
from nonebot.plugin import export
|
||||||
|
from .data_source import effect, register_use, func_manager
|
||||||
|
|
||||||
__zx_plugin_name__ = "商店 - 使用道具"
|
|
||||||
__plugin_usage__ = """
|
__zx_plugin_name__ = "商店 - 使用道具"
|
||||||
usage:
|
__plugin_usage__ = """
|
||||||
普通的使用道具
|
usage:
|
||||||
指令:
|
普通的使用道具
|
||||||
使用道具 [序号或道具名称]
|
指令:
|
||||||
* 序号以 ”我的道具“ 为准 *
|
使用道具 [序号或道具名称] ?[数量]=1
|
||||||
""".strip()
|
* 序号以 ”我的道具“ 为准 *
|
||||||
__plugin_des__ = "商店 - 使用道具"
|
""".strip()
|
||||||
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
|
__plugin_des__ = "商店 - 使用道具"
|
||||||
__plugin_type__ = ('商店',)
|
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
|
||||||
__plugin_version__ = 0.1
|
__plugin_type__ = ('商店',)
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_version__ = 0.1
|
||||||
__plugin_settings__ = {
|
__plugin_author__ = "HibiKier"
|
||||||
"level": 5,
|
__plugin_settings__ = {
|
||||||
"default_status": True,
|
"level": 5,
|
||||||
"limit_superuser": False,
|
"default_status": True,
|
||||||
"cmd": ["商店", "使用道具"],
|
"limit_superuser": False,
|
||||||
}
|
"cmd": ["商店", "使用道具"],
|
||||||
|
}
|
||||||
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
|
||||||
|
# 导出方法供其他插件使用
|
||||||
|
export = export()
|
||||||
@use_props.handle()
|
export.register_use = register_use
|
||||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|
||||||
msg = get_message_text(event.json())
|
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
||||||
if msg in ["", "帮助"]:
|
|
||||||
await use_props.finish(__plugin_usage__)
|
|
||||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
@use_props.handle()
|
||||||
if props:
|
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||||
async with db.transaction():
|
msg = get_message_text(event.json())
|
||||||
pname_list = []
|
if msg in ["", "帮助"]:
|
||||||
props = props[:-1].split(",")
|
await use_props.finish(__plugin_usage__)
|
||||||
for p in props:
|
num = 1
|
||||||
if p != "":
|
msg_sp = msg.split()
|
||||||
if p not in pname_list:
|
if len(msg_sp) > 1 and is_number(msg_sp[-1]) and int(msg_sp[-1]) > 0:
|
||||||
pname_list.append(p)
|
num = int(msg.split()[-1])
|
||||||
if is_number(msg):
|
msg = " ".join(msg.split()[:-1])
|
||||||
if 0 < int(msg) <= len(pname_list):
|
property_ = await BagUser.get_property(event.user_id, event.group_id)
|
||||||
name = pname_list[int(msg) - 1]
|
if property_:
|
||||||
else:
|
async with db.transaction():
|
||||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
if is_number(msg):
|
||||||
else:
|
if 0 < int(msg) <= len(property_):
|
||||||
if msg not in pname_list:
|
name = list(property_.keys())[int(msg) - 1]
|
||||||
await use_props.finish("道具名称错误!", at_sender=True)
|
else:
|
||||||
name = msg
|
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||||
if await BagUser.del_props(
|
else:
|
||||||
event.user_id, event.group_id, name
|
if msg not in property_.keys():
|
||||||
) and await effect(event.user_id, event.group_id, name):
|
await use_props.finish("道具名称错误!", at_sender=True)
|
||||||
await use_props.send(f"使用道具 {name} 成功!", at_sender=True)
|
name = msg
|
||||||
logger.info(
|
_user_prop_count = property_[name]
|
||||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 成功"
|
if num > _user_prop_count:
|
||||||
)
|
await use_props.finish(f"道具数量不足,无法使用{num}次!")
|
||||||
else:
|
if num > (n := func_manager.get_max_num_limit(name)):
|
||||||
await use_props.send(f"使用道具 {name} 失败!", at_sender=True)
|
await use_props.finish(f"该道具单次只能使用 {n} 个!")
|
||||||
logger.info(
|
if await BagUser.delete_property(
|
||||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 失败"
|
event.user_id, event.group_id, name, num
|
||||||
)
|
):
|
||||||
else:
|
if func_manager.check_send_success_message(name):
|
||||||
await use_props.send("您的背包里没有任何的道具噢~", at_sender=True)
|
await use_props.send(f"使用道具 {name} {num} 次成功!", at_sender=True)
|
||||||
|
if msg := await effect(bot, event, name, num):
|
||||||
|
await use_props.send(msg, at_sender=True)
|
||||||
|
logger.info(
|
||||||
|
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次成功"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await use_props.send(f"使用道具 {name} {num} 次失败!", at_sender=True)
|
||||||
|
logger.info(
|
||||||
|
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次失败"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await use_props.send("您的背包里没有任何的道具噢", at_sender=True)
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
from nonebot.adapters.cqhttp import GroupMessageEvent, MessageSegment
|
||||||
|
from services.log import logger
|
||||||
|
from nonebot.adapters.cqhttp import Bot
|
||||||
|
from typing import Optional, Union
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
|
class GoodsUseFuncManager:
|
||||||
|
def __init__(self):
|
||||||
|
self._data = {}
|
||||||
|
|
||||||
|
def register_use(self, goods_name: str, **kwargs):
|
||||||
|
"""
|
||||||
|
注册商品使用方法
|
||||||
|
:param goods_name: 商品名称
|
||||||
|
:param kwargs: kwargs
|
||||||
|
"""
|
||||||
|
self._data[goods_name] = kwargs
|
||||||
|
|
||||||
|
def exists(self, goods_name: str) -> bool:
|
||||||
|
"""
|
||||||
|
判断商品使用方法是否被注册
|
||||||
|
:param goods_name: 商品名称
|
||||||
|
"""
|
||||||
|
return bool(self._data.get(goods_name))
|
||||||
|
|
||||||
|
def get_max_num_limit(self, goods_name: str) -> int:
|
||||||
|
"""
|
||||||
|
获取单次商品使用数量
|
||||||
|
:param goods_name: 商品名称
|
||||||
|
"""
|
||||||
|
if self.exists(goods_name):
|
||||||
|
return self._data[goods_name]["kwargs"]["_max_num_limit"]
|
||||||
|
return 1
|
||||||
|
|
||||||
|
async def use(self, **kwargs) -> Optional[Union[str, MessageSegment]]:
|
||||||
|
"""
|
||||||
|
使用道具
|
||||||
|
:param kwargs: kwargs
|
||||||
|
"""
|
||||||
|
goods_name = kwargs.get("goods_name")
|
||||||
|
if self.exists(goods_name):
|
||||||
|
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
|
||||||
|
return await self._data[goods_name]["func"](
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return self._data[goods_name]["func"](
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
def check_send_success_message(self, goods_name: str) -> bool:
|
||||||
|
"""
|
||||||
|
检查是否发送使用成功信息
|
||||||
|
:param goods_name: 商品名称
|
||||||
|
"""
|
||||||
|
if self.exists(goods_name):
|
||||||
|
return bool(self._data[goods_name]["kwargs"]["send_success_msg"])
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_kwargs(self, goods_name: str) -> dict:
|
||||||
|
"""
|
||||||
|
获取商品使用方法的kwargs
|
||||||
|
:param goods_name: 商品名称
|
||||||
|
"""
|
||||||
|
if self.exists(goods_name):
|
||||||
|
return self._data[goods_name]["kwargs"]
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
func_manager = GoodsUseFuncManager()
|
||||||
|
|
||||||
|
|
||||||
|
async def effect(
|
||||||
|
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int
|
||||||
|
) -> Optional[Union[str, MessageSegment]]:
|
||||||
|
"""
|
||||||
|
商品生效
|
||||||
|
:param bot: Bot
|
||||||
|
:param event: GroupMessageEvent
|
||||||
|
:param goods_name: 商品名称
|
||||||
|
:param num: 使用数量
|
||||||
|
:return: 使用是否成功
|
||||||
|
"""
|
||||||
|
# 优先使用注册的商品插件
|
||||||
|
try:
|
||||||
|
if func_manager.exists(goods_name):
|
||||||
|
_kwargs = func_manager.get_kwargs(goods_name)
|
||||||
|
return await func_manager.use(
|
||||||
|
**{
|
||||||
|
**_kwargs,
|
||||||
|
"_bot": bot,
|
||||||
|
"event": event,
|
||||||
|
"group_id": event.group_id,
|
||||||
|
"user_id": event.user_id,
|
||||||
|
"num": num,
|
||||||
|
"goods_name": goods_name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def register_use(goods_name: str, func, **kwargs):
|
||||||
|
"""
|
||||||
|
注册商品使用方法
|
||||||
|
:param goods_name: 商品名称
|
||||||
|
:param func: 使用函数
|
||||||
|
:param kwargs: kwargs
|
||||||
|
"""
|
||||||
|
if func_manager.exists(goods_name):
|
||||||
|
raise ValueError("该商品使用函数已被注册!")
|
||||||
|
# 发送使用成功信息
|
||||||
|
if kwargs.get("send_success_msg") is None:
|
||||||
|
kwargs["send_success_msg"] = True
|
||||||
|
kwargs["_max_num_limit"] = (
|
||||||
|
kwargs.get("_max_num_limit") if kwargs.get("_max_num_limit") else 1
|
||||||
|
)
|
||||||
|
func_manager.register_use(goods_name, **{"func": func, "kwargs": kwargs})
|
||||||
|
logger.info(f"register_use 成功注册商品:{goods_name} 的使用函数")
|
||||||
@@ -8,7 +8,10 @@ from utils.manager import (
|
|||||||
group_manager,
|
group_manager,
|
||||||
)
|
)
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
|
from configs.config import Config
|
||||||
|
from services.log import logger
|
||||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||||
|
from utils.utils import scheduler
|
||||||
|
|
||||||
|
|
||||||
__zx_plugin_name__ = "重载插件配置 [Superuser]"
|
__zx_plugin_name__ = "重载插件配置 [Superuser]"
|
||||||
@@ -28,6 +31,18 @@ __plugin_cmd__ = [
|
|||||||
]
|
]
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier"
|
||||||
|
__plugin_configs__ = {
|
||||||
|
"AUTO_RELOAD": {
|
||||||
|
"value": False,
|
||||||
|
"help": "自动重载配置文件",
|
||||||
|
"default_value": False
|
||||||
|
},
|
||||||
|
"AUTO_RELOAD_TIME": {
|
||||||
|
"value": 180,
|
||||||
|
"help": "控制自动重载配置文件时长",
|
||||||
|
"default_value": 180
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
reload_plugins_manager = on_command(
|
reload_plugins_manager = on_command(
|
||||||
@@ -41,4 +56,19 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
plugins2cd_manager.reload()
|
plugins2cd_manager.reload()
|
||||||
plugins2block_manager.reload()
|
plugins2block_manager.reload()
|
||||||
group_manager.reload()
|
group_manager.reload()
|
||||||
|
Config.reload()
|
||||||
await reload_plugins_manager.send("重载完成...")
|
await reload_plugins_manager.send("重载完成...")
|
||||||
|
|
||||||
|
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
'interval',
|
||||||
|
seconds=Config.get_config("reload_setting", "AUTO_RELOAD_TIME", 180),
|
||||||
|
)
|
||||||
|
async def _():
|
||||||
|
if Config.get_config("reload_setting", "AUTO_RELOAD"):
|
||||||
|
plugins2settings_manager.reload()
|
||||||
|
plugins2cd_manager.reload()
|
||||||
|
plugins2block_manager.reload()
|
||||||
|
group_manager.reload()
|
||||||
|
Config.reload()
|
||||||
|
logger.debug("已自动重载所有配置文件...")
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
at_sender=True,
|
at_sender=True,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
if not is_number(args[0]):
|
||||||
|
await super_cmd.finish("所有参数必须是数字!", at_sender=True)
|
||||||
|
level = int(args[0])
|
||||||
qq = qq[0]
|
qq = qq[0]
|
||||||
group_id = event.group_id
|
group_id = event.group_id
|
||||||
flag = 2
|
flag = 2
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 772 KiB |
+105
-110
@@ -1,38 +1,39 @@
|
|||||||
from services.db_context import db
|
from services.db_context import db
|
||||||
|
from typing import Dict
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
from services.log import logger
|
||||||
|
|
||||||
|
|
||||||
class BagUser(db.Model):
|
class BagUser(db.Model):
|
||||||
__tablename__ = "bag_users"
|
__tablename__ = "bag_users"
|
||||||
id = db.Column(db.Integer(), primary_key=True)
|
id = db.Column(db.Integer(), primary_key=True)
|
||||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||||
gold = db.Column(db.Integer(), default=100)
|
gold = db.Column(db.Integer(), default=100)
|
||||||
props = db.Column(db.TEXT(), nullable=False, default="")
|
props = db.Column(db.TEXT(), nullable=False, default="") # 旧道具字段(废弃)
|
||||||
spend_total_gold = db.Column(db.Integer(), default=0)
|
spend_total_gold = db.Column(db.Integer(), default=0)
|
||||||
get_total_gold = db.Column(db.Integer(), default=0)
|
get_total_gold = db.Column(db.Integer(), default=0)
|
||||||
get_today_gold = db.Column(db.Integer(), default=0)
|
get_today_gold = db.Column(db.Integer(), default=0)
|
||||||
spend_today_gold = db.Column(db.Integer(), default=0)
|
spend_today_gold = db.Column(db.Integer(), default=0)
|
||||||
|
property = db.Column(db.JSON(), nullable=False, default={}) # 新道具字段
|
||||||
|
|
||||||
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_my_total_gold(cls, user_qq: int, belonging_group: int) -> str:
|
async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
获取金币概况
|
获取金币概况
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 所在群号
|
:param group_id: 所在群号
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
|
||||||
)
|
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
if not user:
|
if not user:
|
||||||
user = await cls.create(
|
user = await cls.create(
|
||||||
user_qq=user_qq,
|
user_qq=user_qq,
|
||||||
belonging_group=belonging_group,
|
group_id=group_id,
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}"
|
f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}"
|
||||||
@@ -41,179 +42,173 @@ class BagUser(db.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_gold(cls, user_qq: int, belonging_group: int) -> int:
|
async def get_gold(cls, user_qq: int, group_id: int) -> int:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
获取当前金币
|
获取当前金币
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 所在群号
|
:param group_id: 所在群号
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
|
||||||
)
|
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
if user:
|
if user:
|
||||||
return user.gold
|
return user.gold
|
||||||
else:
|
else:
|
||||||
await cls.create(
|
await cls.create(
|
||||||
user_qq=user_qq,
|
user_qq=user_qq,
|
||||||
belonging_group=belonging_group,
|
group_id=group_id,
|
||||||
)
|
)
|
||||||
return 100
|
return 100
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_props(cls, user_qq: int, belonging_group: int) -> str:
|
async def get_property(cls, user_qq: int, group_id: int) -> Dict[str, int]:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
获取当前道具
|
获取当前道具
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 所在群号
|
:param group_id: 所在群号
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
|
||||||
)
|
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
if user:
|
if user:
|
||||||
return user.props
|
return user.property
|
||||||
else:
|
else:
|
||||||
await cls.create(
|
await cls.create(
|
||||||
user_qq=user_qq,
|
user_qq=user_qq,
|
||||||
belonging_group=belonging_group,
|
group_id=group_id,
|
||||||
)
|
)
|
||||||
return ""
|
return {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
async def add_gold(cls, user_qq: int, group_id: int, num: int):
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
增加金币
|
增加金币
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 所在群号
|
:param group_id: 所在群号
|
||||||
:param num: 金币数量
|
:param num: 金币数量
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
|
||||||
)
|
|
||||||
query = query.with_for_update()
|
query = query.with_for_update()
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
try:
|
if user:
|
||||||
if user:
|
await user.update(
|
||||||
await user.update(
|
gold=user.gold + num,
|
||||||
gold=user.gold + num,
|
get_total_gold=user.get_total_gold + num,
|
||||||
get_total_gold=user.get_total_gold + num,
|
get_today_gold=user.get_today_gold + num,
|
||||||
get_today_gold=user.get_today_gold + num,
|
).apply()
|
||||||
).apply()
|
else:
|
||||||
else:
|
await cls.create(
|
||||||
await cls.create(
|
user_qq=user_qq,
|
||||||
user_qq=user_qq,
|
group_id=group_id,
|
||||||
belonging_group=belonging_group,
|
gold=100 + num,
|
||||||
gold=100 + num,
|
get_total_gold=num,
|
||||||
get_total_gold=num,
|
get_today_gold=num,
|
||||||
get_today_gold=num,
|
)
|
||||||
)
|
|
||||||
return True
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
async def spend_gold(cls, user_qq: int, group_id: int, num: int):
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
花费金币
|
花费金币
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 所在群号
|
:param group_id: 所在群号
|
||||||
:param num: 金币数量
|
:param num: 金币数量
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
|
||||||
)
|
|
||||||
query = query.with_for_update()
|
query = query.with_for_update()
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
try:
|
if user:
|
||||||
if user:
|
await user.update(
|
||||||
await user.update(
|
gold=user.gold - num,
|
||||||
gold=user.gold - num,
|
spend_total_gold=user.spend_total_gold + num,
|
||||||
spend_total_gold=user.spend_total_gold + num,
|
spend_today_gold=user.spend_today_gold + num,
|
||||||
spend_today_gold=user.spend_today_gold + num,
|
).apply()
|
||||||
).apply()
|
else:
|
||||||
else:
|
await cls.create(
|
||||||
await cls.create(
|
user_qq=user_qq,
|
||||||
user_qq=user_qq,
|
group_id=group_id,
|
||||||
belonging_group=belonging_group,
|
gold=100 - num,
|
||||||
gold=100 - num,
|
spend_total_gold=num,
|
||||||
spend_total_gold=num,
|
spend_today_gold=num,
|
||||||
spend_today_gold=num,
|
)
|
||||||
)
|
|
||||||
return True
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
async def add_property(cls, user_qq: int, group_id: int, name: str):
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
增加道具
|
增加道具
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 所在群号
|
:param group_id: 所在群号
|
||||||
:param name: 道具名称
|
:param name: 道具名称
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
|
||||||
)
|
|
||||||
query = query.with_for_update()
|
query = query.with_for_update()
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
try:
|
if user:
|
||||||
if user:
|
p = user.property
|
||||||
await user.update(props=user.props + f"{name},").apply()
|
if p.get(name) is None:
|
||||||
|
p[name] = 1
|
||||||
else:
|
else:
|
||||||
await cls.create(
|
p[name] += 1
|
||||||
user_qq=user_qq, belonging_group=belonging_group, props=f"{name},"
|
await user.update(property=p).apply()
|
||||||
)
|
else:
|
||||||
return True
|
await cls.create(user_qq=user_qq, group_id=group_id, property={name: 1})
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def del_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
async def delete_property(
|
||||||
|
cls, user_qq: int, group_id: int, name: str, num: int = 1
|
||||||
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
使用道具
|
使用/删除 道具
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 所在群号
|
:param group_id: 所在群号
|
||||||
:param name: 道具名称
|
:param name: 道具名称
|
||||||
|
:param num: 使用个数
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
|
||||||
)
|
|
||||||
query = query.with_for_update()
|
query = query.with_for_update()
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
try:
|
if user:
|
||||||
if user:
|
property_ = user.property
|
||||||
rst = ""
|
if name in property_:
|
||||||
props = user.props
|
if property_.get(name) == num:
|
||||||
if props.find(name) != -1:
|
del property_[name]
|
||||||
props = props.split(",")
|
|
||||||
try:
|
|
||||||
index = props.index(name)
|
|
||||||
except ValueError:
|
|
||||||
return False
|
|
||||||
props = props[:index] + props[index + 1 :]
|
|
||||||
for p in props:
|
|
||||||
if p != "":
|
|
||||||
rst += p + ","
|
|
||||||
await user.update(props=rst).apply()
|
|
||||||
return True
|
|
||||||
else:
|
else:
|
||||||
return False
|
property_[name] -= num
|
||||||
else:
|
await user.update(property=property_).apply()
|
||||||
return False
|
return True
|
||||||
except Exception:
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def buy_property(
|
||||||
|
cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
购买道具
|
||||||
|
参数:
|
||||||
|
:param user_qq: 用户qq
|
||||||
|
:param group_id: 所在群聊
|
||||||
|
:param goods: 商品
|
||||||
|
:param goods_num: 商品数量
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 折扣后金币
|
||||||
|
spend_gold = goods.goods_discount * goods.goods_price * goods_num
|
||||||
|
await BagUser.spend_gold(user_qq, group_id, spend_gold)
|
||||||
|
for _ in range(goods_num):
|
||||||
|
await BagUser.add_property(user_qq, group_id, goods.goods_name)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"buy_property 发生错误 {type(e)}:{e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -227,5 +222,5 @@ class BagUser(db.Model):
|
|||||||
if not group_id:
|
if not group_id:
|
||||||
query = await cls.query.gino.all()
|
query = await cls.query.gino.all()
|
||||||
else:
|
else:
|
||||||
query = await cls.query.where((cls.belonging_group == group_id)).gino.all()
|
query = await cls.query.where((cls.group_id == group_id)).gino.all()
|
||||||
return query
|
return query
|
||||||
|
|||||||
Executable → Regular
+15
-11
@@ -1,5 +1,6 @@
|
|||||||
from services.db_context import db
|
from services.db_context import db
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
from services.log import logger
|
||||||
|
|
||||||
|
|
||||||
class GoodsInfo(db.Model):
|
class GoodsInfo(db.Model):
|
||||||
@@ -34,16 +35,18 @@ class GoodsInfo(db.Model):
|
|||||||
:param goods_limit_time: 商品限时
|
:param goods_limit_time: 商品限时
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await cls.create(
|
if not await cls.get_goods_info(goods_name):
|
||||||
goods_name=goods_name,
|
await cls.create(
|
||||||
goods_price=goods_price,
|
goods_name=goods_name,
|
||||||
goods_description=goods_description,
|
goods_price=goods_price,
|
||||||
goods_discount=goods_discount,
|
goods_description=goods_description,
|
||||||
goods_limit_time=goods_limit_time,
|
goods_discount=goods_discount,
|
||||||
)
|
goods_limit_time=goods_limit_time,
|
||||||
return True
|
)
|
||||||
except Exception:
|
return True
|
||||||
return False
|
except Exception as e:
|
||||||
|
logger.error(f"GoodsInfo add_goods 发生错误 {type(e)}:{e}")
|
||||||
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_goods(cls, goods_name: str) -> bool:
|
async def delete_goods(cls, goods_name: str) -> bool:
|
||||||
@@ -99,7 +102,8 @@ class GoodsInfo(db.Model):
|
|||||||
if goods_limit_time:
|
if goods_limit_time:
|
||||||
await query.update(goods_limit_time=goods_limit_time).apply()
|
await query.update(goods_limit_time=goods_limit_time).apply()
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception as e:
|
||||||
|
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
+32
-30
@@ -10,18 +10,18 @@ class GroupInfoUser(db.Model):
|
|||||||
id = db.Column(db.Integer(), primary_key=True)
|
id = db.Column(db.Integer(), primary_key=True)
|
||||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||||
user_name = db.Column(db.Unicode(), nullable=False)
|
user_name = db.Column(db.Unicode(), nullable=False)
|
||||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||||
user_join_time = db.Column(db.DateTime(), nullable=False)
|
user_join_time = db.Column(db.DateTime(), nullable=False)
|
||||||
nickname = db.Column(db.Unicode())
|
nickname = db.Column(db.Unicode())
|
||||||
uid = db.Column(db.BigInteger())
|
uid = db.Column(db.BigInteger())
|
||||||
|
|
||||||
_idx1 = db.Index("info_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
_idx1 = db.Index("info_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_member_info(
|
async def add_member_info(
|
||||||
cls,
|
cls,
|
||||||
user_qq: int,
|
user_qq: int,
|
||||||
belonging_group: int,
|
group_id: int,
|
||||||
user_name: str,
|
user_name: str,
|
||||||
user_join_time: datetime,
|
user_join_time: datetime,
|
||||||
uid: Optional[int] = None,
|
uid: Optional[int] = None,
|
||||||
@@ -31,20 +31,20 @@ class GroupInfoUser(db.Model):
|
|||||||
添加群内用户信息
|
添加群内用户信息
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 群号
|
:param group_id: 群号
|
||||||
:param user_name: 用户名称
|
:param user_name: 用户名称
|
||||||
:param user_join_time: 入群时间
|
:param user_join_time: 入群时间
|
||||||
:param uid: 用户唯一 id(自动生成)
|
:param uid: 用户唯一 id(自动生成)
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
if not await query.gino.first():
|
if not await query.gino.first():
|
||||||
await cls.create(
|
await cls.create(
|
||||||
user_qq=user_qq,
|
user_qq=user_qq,
|
||||||
user_name=user_name,
|
user_name=user_name,
|
||||||
belonging_group=belonging_group,
|
group_id=group_id,
|
||||||
user_join_time=user_join_time,
|
user_join_time=user_join_time,
|
||||||
uid=uid
|
uid=uid
|
||||||
)
|
)
|
||||||
@@ -54,31 +54,31 @@ class GroupInfoUser(db.Model):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_member_info(
|
async def get_member_info(
|
||||||
cls, user_qq: int, belonging_group: int
|
cls, user_qq: int, group_id: int
|
||||||
) -> "GroupInfoUser":
|
) -> "GroupInfoUser":
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
查询群员信息
|
查询群员信息
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 群号
|
:param group_id: 群号
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
)
|
)
|
||||||
return await query.gino.first()
|
return await query.gino.first()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_member_info(cls, user_qq: int, belonging_group: int) -> bool:
|
async def delete_member_info(cls, user_qq: int, group_id: int) -> bool:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
删除群员信息
|
删除群员信息
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 群号
|
:param group_id: 群号
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
)
|
)
|
||||||
query = query.with_for_update()
|
query = query.with_for_update()
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
@@ -87,40 +87,40 @@ class GroupInfoUser(db.Model):
|
|||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
await cls.delete.where(
|
await cls.delete.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
).gino.status()
|
).gino.status()
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_group_member_id_list(cls, belonging_group: int) -> List[int]:
|
async def get_group_member_id_list(cls, group_id: int) -> List[int]:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
获取该群所有用户qq
|
获取该群所有用户qq
|
||||||
参数:
|
参数:
|
||||||
:param belonging_group: 群号
|
:param group_id: 群号
|
||||||
"""
|
"""
|
||||||
member_list = []
|
member_list = []
|
||||||
query = cls.query.where((cls.belonging_group == belonging_group))
|
query = cls.query.where((cls.group_id == group_id))
|
||||||
for user in await query.gino.all():
|
for user in await query.gino.all():
|
||||||
member_list.append(user.user_qq)
|
member_list.append(user.user_qq)
|
||||||
return member_list
|
return member_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def set_group_member_nickname(
|
async def set_group_member_nickname(
|
||||||
cls, user_qq: int, belonging_group: int, nickname: str
|
cls, user_qq: int, group_id: int, nickname: str
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
设置群员在该群内的昵称
|
设置群员在该群内的昵称
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 群号
|
:param group_id: 群号
|
||||||
:param nickname: 昵称
|
:param nickname: 昵称
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
)
|
)
|
||||||
user = await query.with_for_update().gino.first()
|
user = await query.with_for_update().gino.first()
|
||||||
if user:
|
if user:
|
||||||
@@ -131,25 +131,27 @@ class GroupInfoUser(db.Model):
|
|||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_all_group(cls, user_qq: int) -> List[int]:
|
async def get_user_all_group(cls, user_qq: int) -> List[int]:
|
||||||
"""
|
"""
|
||||||
获取该用户所在的所有群聊
|
说明:
|
||||||
:param user_qq: 用户qq
|
获取该用户所在的所有群聊
|
||||||
|
参数:
|
||||||
|
:param user_qq: 用户qq
|
||||||
"""
|
"""
|
||||||
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
|
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
|
||||||
if query:
|
if query:
|
||||||
query = [x.belonging_group for x in query]
|
query = [x.group_id for x in query]
|
||||||
return query
|
return query
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_group_member_nickname(cls, user_qq: int, belonging_group: int) -> str:
|
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
获取用户在该群的昵称
|
获取用户在该群的昵称
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: qq号
|
:param user_qq: qq号
|
||||||
:param belonging_group: 群号
|
:param group_id: 群号
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
)
|
)
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
if user:
|
if user:
|
||||||
@@ -163,12 +165,12 @@ class GroupInfoUser(db.Model):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_group_member_uid(cls, user_qq: int, belonging_group: int) -> Optional[str]:
|
async def get_group_member_uid(cls, user_qq: int, group_id: int) -> Optional[str]:
|
||||||
query = cls.query.where(
|
query = cls.query.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
)
|
)
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.belonging_group == 114514)).with_for_update()
|
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.group_id == 114514)).with_for_update()
|
||||||
_max_uid_user = await _max_uid.gino.first()
|
_max_uid_user = await _max_uid.gino.first()
|
||||||
_max_uid = _max_uid_user.uid
|
_max_uid = _max_uid_user.uid
|
||||||
if not user or not user.uid:
|
if not user or not user.uid:
|
||||||
@@ -178,9 +180,9 @@ class GroupInfoUser(db.Model):
|
|||||||
return x.uid
|
return x.uid
|
||||||
else:
|
else:
|
||||||
if not user:
|
if not user:
|
||||||
await GroupInfoUser.add_member_info(user_qq, belonging_group, '', datetime.min)
|
await GroupInfoUser.add_member_info(user_qq, group_id, '', datetime.min)
|
||||||
user = await cls.query.where(
|
user = await cls.query.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
).gino.first()
|
).gino.first()
|
||||||
await user.update(
|
await user.update(
|
||||||
uid=_max_uid + 1,
|
uid=_max_uid + 1,
|
||||||
|
|||||||
+11
-12
@@ -8,8 +8,7 @@ class SignGroupUser(db.Model):
|
|||||||
|
|
||||||
id = db.Column(db.Integer(), primary_key=True)
|
id = db.Column(db.Integer(), primary_key=True)
|
||||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||||
|
|
||||||
checkin_count = db.Column(db.Integer(), nullable=False)
|
checkin_count = db.Column(db.Integer(), nullable=False)
|
||||||
checkin_time_last = db.Column(db.DateTime(timezone=True), nullable=False)
|
checkin_time_last = db.Column(db.DateTime(timezone=True), nullable=False)
|
||||||
impression = db.Column(db.Numeric(scale=3, asdecimal=False), nullable=False)
|
impression = db.Column(db.Numeric(scale=3, asdecimal=False), nullable=False)
|
||||||
@@ -20,29 +19,29 @@ class SignGroupUser(db.Model):
|
|||||||
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
|
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
|
||||||
)
|
)
|
||||||
|
|
||||||
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "belonging_group", unique=True)
|
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "group_id", unique=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def ensure(
|
async def ensure(
|
||||||
cls, user_qq: int, belonging_group: int, for_update: bool = False
|
cls, user_qq: int, group_id: int, for_update: bool = False
|
||||||
) -> "SignGroupUser":
|
) -> "SignGroupUser":
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
获取签到用户
|
获取签到用户
|
||||||
参数:
|
参数:
|
||||||
:param user_qq: 用户qq
|
:param user_qq: 用户qq
|
||||||
:param belonging_group: 所在群聊
|
:param group_id: 所在群聊
|
||||||
:param for_update: 是否存在修改数据
|
:param for_update: 是否存在修改数据
|
||||||
"""
|
"""
|
||||||
query = cls.query.where(
|
query = cls.query.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
)
|
)
|
||||||
if for_update:
|
if for_update:
|
||||||
query = query.with_for_update()
|
query = query.with_for_update()
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
return user or await cls.create(
|
return user or await cls.create(
|
||||||
user_qq=user_qq,
|
user_qq=user_qq,
|
||||||
belonging_group=belonging_group,
|
group_id=group_id,
|
||||||
checkin_count=0,
|
checkin_count=0,
|
||||||
checkin_time_last=datetime.min, # 从未签到过
|
checkin_time_last=datetime.min, # 从未签到过
|
||||||
impression=0,
|
impression=0,
|
||||||
@@ -79,22 +78,22 @@ class SignGroupUser(db.Model):
|
|||||||
).apply()
|
).apply()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_all_impression(cls, belonging_group: int) -> "list, list, list":
|
async def get_all_impression(cls, group_id: int) -> "list, list, list":
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
获取该群所有用户 id 及对应 好感度
|
获取该群所有用户 id 及对应 好感度
|
||||||
参数:
|
参数:
|
||||||
:param belonging_group: 群号
|
:param group_id: 群号
|
||||||
"""
|
"""
|
||||||
impression_list = []
|
impression_list = []
|
||||||
user_qq_list = []
|
user_qq_list = []
|
||||||
user_group = []
|
user_group = []
|
||||||
if belonging_group:
|
if group_id:
|
||||||
query = cls.query.where(cls.belonging_group == belonging_group)
|
query = cls.query.where(cls.group_id == group_id)
|
||||||
else:
|
else:
|
||||||
query = cls.query
|
query = cls.query
|
||||||
for user in await query.gino.all():
|
for user in await query.gino.all():
|
||||||
impression_list.append(user.impression)
|
impression_list.append(user.impression)
|
||||||
user_qq_list.append(user.user_qq)
|
user_qq_list.append(user.user_qq)
|
||||||
user_group.append(user.belonging_group)
|
user_group.append(user.group_id)
|
||||||
return user_qq_list, impression_list, user_group
|
return user_qq_list, impression_list, user_group
|
||||||
|
|||||||
+14
-17
@@ -11,7 +11,7 @@ from nonebot.typing import T_State
|
|||||||
from models.friend_user import FriendUser
|
from models.friend_user import FriendUser
|
||||||
from models.group_member_info import GroupInfoUser
|
from models.group_member_info import GroupInfoUser
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from utils.utils import get_message_text, get_message_imgs
|
from utils.utils import get_message_text, get_message_img
|
||||||
from .data_source import get_chat_result, hello, no_result
|
from .data_source import get_chat_result, hello, no_result
|
||||||
from configs.config import NICKNAME, Config
|
from configs.config import NICKNAME, Config
|
||||||
|
|
||||||
@@ -21,27 +21,22 @@ usage:
|
|||||||
与{NICKNAME}普普通通的对话吧!
|
与{NICKNAME}普普通通的对话吧!
|
||||||
"""
|
"""
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
__plugin_author__ = 'HibiKier'
|
__plugin_author__ = "HibiKier"
|
||||||
__plugin_settings__ = {
|
__plugin_settings__ = {
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"cmd": ["Ai", "ai", "AI", "aI"],
|
"cmd": ["Ai", "ai", "AI", "aI"],
|
||||||
}
|
}
|
||||||
__plugin_configs__ = {
|
__plugin_configs__ = {
|
||||||
"TL_KEY": {
|
"TL_KEY": {"value": [], "help": "图灵Key"},
|
||||||
"value": [],
|
"ALAPI_AI_CHECK": {"value": False, "help": "是否检测青云客骂娘回复", "default_value": False},
|
||||||
"help": "图灵Key"
|
"TEXT_FILTER": {
|
||||||
|
"value": ["鸡", "口交"],
|
||||||
|
"help": "文本过滤器,将敏感词更改为*",
|
||||||
|
"default_value": [],
|
||||||
},
|
},
|
||||||
"ALAPI_AI_CHECK": {
|
|
||||||
"value": False,
|
|
||||||
"help": "是否检测青云客骂娘回复",
|
|
||||||
"default_value": False
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Config.add_plugin_config(
|
Config.add_plugin_config(
|
||||||
"alapi",
|
"alapi", "ALAPI_TOKEN", None, help_="在https://admin.alapi.cn/user/login登录后获取token"
|
||||||
"ALAPI_TOKEN",
|
|
||||||
None,
|
|
||||||
help_="在https://admin.alapi.cn/user/login登录后获取token"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ai = on_message(rule=to_me(), priority=8)
|
ai = on_message(rule=to_me(), priority=8)
|
||||||
@@ -50,11 +45,11 @@ ai = on_message(rule=to_me(), priority=8)
|
|||||||
@ai.handle()
|
@ai.handle()
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
imgs = get_message_imgs(event.json())
|
img = get_message_img(event.json())
|
||||||
if "CQ:xml" in str(event.get_message()):
|
if "CQ:xml" in str(event.get_message()):
|
||||||
return
|
return
|
||||||
# 打招呼
|
# 打招呼
|
||||||
if (not msg and not imgs) or msg in [
|
if (not msg and not img) or msg in [
|
||||||
"你好啊",
|
"你好啊",
|
||||||
"你好",
|
"你好",
|
||||||
"在吗",
|
"在吗",
|
||||||
@@ -65,7 +60,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
"在",
|
"在",
|
||||||
]:
|
]:
|
||||||
await ai.finish(hello())
|
await ai.finish(hello())
|
||||||
img = imgs[0] if imgs else ""
|
img = img[0] if img else ""
|
||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||||
event.user_id, event.group_id
|
event.user_id, event.group_id
|
||||||
@@ -83,6 +78,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
f"问题:{msg} ---- 回答:{result}"
|
f"问题:{msg} ---- 回答:{result}"
|
||||||
)
|
)
|
||||||
if result:
|
if result:
|
||||||
|
for t in Config.get_config("ai", "TEXT_FILTER"):
|
||||||
|
result = result.replace(t, "*")
|
||||||
await ai.finish(Message(result))
|
await ai.finish(Message(result))
|
||||||
else:
|
else:
|
||||||
await ai.finish(no_result())
|
await ai.finish(no_result())
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from .data_source import (
|
|||||||
get_media_id,
|
get_media_id,
|
||||||
get_sub_status,
|
get_sub_status,
|
||||||
SubManager,
|
SubManager,
|
||||||
BilibiliSub
|
BilibiliSub,
|
||||||
)
|
)
|
||||||
from models.level_user import LevelUser
|
from models.level_user import LevelUser
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
@@ -163,11 +163,10 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
|
|
||||||
@show_sub_info.handle()
|
@show_sub_info.handle()
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
id_ = (
|
if isinstance(event, GroupMessageEvent):
|
||||||
f"{event.user_id}:{event.group_id}"
|
id_ = f"{event.group_id}"
|
||||||
if isinstance(event, GroupMessageEvent)
|
else:
|
||||||
else f"{event.user_id}"
|
id_ = f"{event.user_id}"
|
||||||
)
|
|
||||||
data = await BilibiliSub.get_sub_data(id_)
|
data = await BilibiliSub.get_sub_data(id_)
|
||||||
live_rst = ""
|
live_rst = ""
|
||||||
up_rst = ""
|
up_rst = ""
|
||||||
@@ -181,6 +180,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
up_rst += f"\tUP:{x.uname}\n" f"\tuid:{x.uid}\n" f"------------------\n"
|
up_rst += f"\tUP:{x.uname}\n" f"\tuid:{x.uid}\n" f"------------------\n"
|
||||||
if x.sub_type == "season":
|
if x.sub_type == "season":
|
||||||
season_rst += (
|
season_rst += (
|
||||||
|
f"\t番剧id:{x.sub_id}\n"
|
||||||
f"\t番名:{x.season_name}\n"
|
f"\t番名:{x.season_name}\n"
|
||||||
f"\t当前集数:{x.season_current_episode}\n"
|
f"\t当前集数:{x.season_current_episode}\n"
|
||||||
f"------------------\n"
|
f"------------------\n"
|
||||||
@@ -189,7 +189,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
up_rst = "当前订阅的UP:\n" + up_rst if up_rst else up_rst
|
up_rst = "当前订阅的UP:\n" + up_rst if up_rst else up_rst
|
||||||
season_rst = "当前订阅的番剧:\n" + season_rst if season_rst else season_rst
|
season_rst = "当前订阅的番剧:\n" + season_rst if season_rst else season_rst
|
||||||
if not live_rst and not up_rst and not season_rst:
|
if not live_rst and not up_rst and not season_rst:
|
||||||
live_rst = "您目前没有任何订阅..."
|
live_rst = (
|
||||||
|
"该群目前没有任何订阅..." if isinstance(event, GroupMessageEvent) else "您目前没有任何订阅..."
|
||||||
|
)
|
||||||
await show_sub_info.send(live_rst + up_rst + season_rst)
|
await show_sub_info.send(live_rst + up_rst + season_rst)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,9 @@ async def get_media_id(keyword: str) -> dict:
|
|||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
try:
|
try:
|
||||||
_season_data = {}
|
_season_data = {}
|
||||||
response = await AsyncHttpx.get(bilibili_search_url, params=params, timeout=5)
|
response = await AsyncHttpx.get(
|
||||||
|
bilibili_search_url, params=params, timeout=5
|
||||||
|
)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
if data.get("data"):
|
if data.get("data"):
|
||||||
@@ -191,7 +193,6 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
|||||||
获取订阅状态
|
获取订阅状态
|
||||||
:param id_: 订阅 id
|
:param id_: 订阅 id
|
||||||
:param sub_type: 订阅类型
|
:param sub_type: 订阅类型
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if sub_type == "live":
|
if sub_type == "live":
|
||||||
@@ -201,7 +202,7 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
|||||||
elif sub_type == "season":
|
elif sub_type == "season":
|
||||||
return await _get_season_status(id_)
|
return await _get_season_status(id_)
|
||||||
except ResponseCodeException:
|
except ResponseCodeException:
|
||||||
return "获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||||
# except Exception as e:
|
# except Exception as e:
|
||||||
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
|
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
|
||||||
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
|
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
|
||||||
@@ -254,7 +255,12 @@ async def _get_up_status(id_: int) -> Optional[str]:
|
|||||||
if dynamic_img:
|
if dynamic_img:
|
||||||
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
|
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
|
||||||
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n"
|
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n"
|
||||||
if _user.latest_video_created != latest_video_created and video:
|
if (
|
||||||
|
latest_video_created
|
||||||
|
and _user.latest_video_created
|
||||||
|
and video
|
||||||
|
and _user.latest_video_created < latest_video_created
|
||||||
|
):
|
||||||
rst = rst + "-------------\n" if rst else rst
|
rst = rst + "-------------\n" if rst else rst
|
||||||
await BilibiliSub.update_sub_info(
|
await BilibiliSub.update_sub_info(
|
||||||
id_, latest_video_created=latest_video_created
|
id_, latest_video_created=latest_video_created
|
||||||
@@ -304,7 +310,7 @@ async def get_user_dynamic(
|
|||||||
browser = await get_browser()
|
browser = await get_browser()
|
||||||
if dynamic_info.get("cards") and browser:
|
if dynamic_info.get("cards") and browser:
|
||||||
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
||||||
if local_user.dynamic_upload_time != dynamic_upload_time:
|
if local_user.dynamic_upload_time < dynamic_upload_time:
|
||||||
page = await browser.new_page()
|
page = await browser.new_page()
|
||||||
await page.goto(
|
await page.goto(
|
||||||
f"https://space.bilibili.com/{local_user.uid}/dynamic",
|
f"https://space.bilibili.com/{local_user.uid}/dynamic",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from nonebot import on_command
|
|||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
|
||||||
from nonebot.permission import SUPERUSER
|
from nonebot.permission import SUPERUSER
|
||||||
from utils.utils import get_message_text, is_number, get_message_imgs
|
from utils.utils import get_message_text, is_number, get_message_img
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from utils.message_builder import text as _text
|
from utils.message_builder import text as _text
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
@@ -63,7 +63,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
coffee = int(list(bot.config.superusers)[0])
|
coffee = int(list(bot.config.superusers)[0])
|
||||||
text = get_message_text(event.json())
|
text = get_message_text(event.json())
|
||||||
img_msg = _text("")
|
img_msg = _text("")
|
||||||
for img in get_message_imgs(event.json()):
|
for img in get_message_img(event.json()):
|
||||||
img_msg += image(img)
|
img_msg += image(img)
|
||||||
if not text and not img_msg:
|
if not text and not img_msg:
|
||||||
await dialogue.send("请发送[滴滴滴]+您要说的内容~", at_sender=True)
|
await dialogue.send("请发送[滴滴滴]+您要说的内容~", at_sender=True)
|
||||||
@@ -127,26 +127,26 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
id_ = msg[0]
|
id_ = msg[0]
|
||||||
user_id = dialogue_data[id_]["user_id"]
|
user_id = dialogue_data[id_]["user_id"]
|
||||||
group_id = dialogue_data[id_]["group_id"]
|
group_id = dialogue_data[id_]["group_id"]
|
||||||
text = msg[1]
|
text = " ".join(msg[1:])
|
||||||
dialogue_data.pop(id_)
|
dialogue_data.pop(id_)
|
||||||
else:
|
else:
|
||||||
user_id = 0
|
user_id = 0
|
||||||
if is_number(msg[1]):
|
if is_number(msg[1]):
|
||||||
group_id = int(msg[1])
|
group_id = int(msg[1])
|
||||||
text = msg[2]
|
text = " ".join(msg[2:])
|
||||||
else:
|
else:
|
||||||
await reply.finish("群号错误...", at_sender=True)
|
await reply.finish("群号错误...", at_sender=True)
|
||||||
else:
|
else:
|
||||||
user_id = int(msg[0])
|
user_id = int(msg[0])
|
||||||
if is_number(msg[1]) and len(msg[1]) > 5:
|
if is_number(msg[1]) and len(msg[1]) > 5:
|
||||||
group_id = int(msg[1])
|
group_id = int(msg[1])
|
||||||
text = msg[2]
|
text = " ".join(msg[2:])
|
||||||
else:
|
else:
|
||||||
group_id = 0
|
group_id = 0
|
||||||
text = msg[1]
|
text = " ".join(msg[1:])
|
||||||
else:
|
else:
|
||||||
await reply.finish("第一参数,请输入数字.....", at_sender=True)
|
await reply.finish("第一参数,请输入数字.....", at_sender=True)
|
||||||
for img in get_message_imgs(event.json()):
|
for img in get_message_img(event.json()):
|
||||||
text += image(img)
|
text += image(img)
|
||||||
if group_id:
|
if group_id:
|
||||||
if user_id:
|
if user_id:
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ def is_expired(data: dict):
|
|||||||
now = datetime.now().date()
|
now = datetime.now().date()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
return start_date <= now <= end_date
|
return not start_date <= now <= end_date
|
||||||
|
|
||||||
|
|
||||||
# 检查写入
|
# 检查写入
|
||||||
def check_write(data: dict, up_char_file):
|
def check_write(data: dict, up_char_file):
|
||||||
if not is_expired(data['char']):
|
if is_expired(data['char']):
|
||||||
for x in list(data.keys()):
|
for x in list(data.keys()):
|
||||||
data[x]['title'] = ''
|
data[x]['title'] = ''
|
||||||
else:
|
else:
|
||||||
@@ -175,7 +175,7 @@ class GenshinAnnouncement:
|
|||||||
data[itype]['time'] = data[itype]['time'][:-1]
|
data[itype]['time'] = data[itype]['time'][:-1]
|
||||||
if '版本更新后' in data[itype]['time']:
|
if '版本更新后' in data[itype]['time']:
|
||||||
sp = data[itype]['time'].split('~')
|
sp = data[itype]['time'].split('~')
|
||||||
end_time = datetime.strptime(sp[1].strip(), "%Y/%m/%d %H:%M:%S")
|
end_time = datetime.strptime(sp[1].strip(), "%Y/%m/%d %H:%M")
|
||||||
start_time = end_time - timedelta(days=20)
|
start_time = end_time - timedelta(days=20)
|
||||||
data[itype]['time'] = start_time.strftime('%Y/%m/%d') + ' ~ ' + end_time.strftime('%Y/%m/%d')
|
data[itype]['time'] = start_time.strftime('%Y/%m/%d') + ' ~ ' + end_time.strftime('%Y/%m/%d')
|
||||||
tmp = ''
|
tmp = ''
|
||||||
|
|||||||
@@ -2,9 +2,24 @@ import os
|
|||||||
from nonebot.adapters.cqhttp import MessageSegment, Message
|
from nonebot.adapters.cqhttp import MessageSegment, Message
|
||||||
import random
|
import random
|
||||||
from .update_game_info import update_info
|
from .update_game_info import update_info
|
||||||
from .util import generate_img, init_star_rst, BaseData, set_list, get_star, init_up_char
|
from .util import (
|
||||||
from .config import GENSHIN_FIVE_P, GENSHIN_FOUR_P, GENSHIN_G_FIVE_P, GENSHIN_G_FOUR_P, GENSHIN_THREE_P, I72_ADD, \
|
generate_img,
|
||||||
DRAW_PATH, GENSHIN_FLAG
|
init_star_rst,
|
||||||
|
BaseData,
|
||||||
|
set_list,
|
||||||
|
get_star,
|
||||||
|
init_up_char,
|
||||||
|
)
|
||||||
|
from .config import (
|
||||||
|
GENSHIN_FIVE_P,
|
||||||
|
GENSHIN_FOUR_P,
|
||||||
|
GENSHIN_G_FIVE_P,
|
||||||
|
GENSHIN_G_FOUR_P,
|
||||||
|
GENSHIN_THREE_P,
|
||||||
|
I72_ADD,
|
||||||
|
DRAW_PATH,
|
||||||
|
GENSHIN_FLAG,
|
||||||
|
)
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from .init_card_pool import init_game_pool
|
from .init_card_pool import init_game_pool
|
||||||
from .announcement import GenshinAnnouncement
|
from .announcement import GenshinAnnouncement
|
||||||
@@ -27,9 +42,9 @@ ALL_ARMS = []
|
|||||||
UP_CHAR = []
|
UP_CHAR = []
|
||||||
UP_ARMS = []
|
UP_ARMS = []
|
||||||
|
|
||||||
_CURRENT_CHAR_POOL_TITLE = ''
|
_CURRENT_CHAR_POOL_TITLE = ""
|
||||||
_CURRENT_ARMS_POOL_TITLE = ''
|
_CURRENT_ARMS_POOL_TITLE = ""
|
||||||
POOL_IMG = ''
|
POOL_IMG = ""
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -39,19 +54,25 @@ class GenshinChar(BaseData):
|
|||||||
|
|
||||||
async def genshin_draw(user_id: int, count: int, pool_name: str):
|
async def genshin_draw(user_id: int, count: int, pool_name: str):
|
||||||
# 0 1 2
|
# 0 1 2
|
||||||
cnlist = ['★★★★★', '★★★★', '★★★']
|
cnlist = ["★★★★★", "★★★★", "★★★"]
|
||||||
char_list, five_list, five_index_list, char_dict, star_list = _format_card_information(count, user_id, pool_name)
|
(
|
||||||
temp = ''
|
char_list,
|
||||||
title = ''
|
five_list,
|
||||||
|
five_index_list,
|
||||||
|
char_dict,
|
||||||
|
star_list,
|
||||||
|
) = _format_card_information(count, user_id, pool_name)
|
||||||
|
temp = ""
|
||||||
|
title = ""
|
||||||
up_type = []
|
up_type = []
|
||||||
up_list = []
|
up_list = []
|
||||||
if pool_name == 'char' and _CURRENT_CHAR_POOL_TITLE:
|
if pool_name == "char" and _CURRENT_CHAR_POOL_TITLE:
|
||||||
up_type = UP_CHAR
|
up_type = UP_CHAR
|
||||||
title = _CURRENT_CHAR_POOL_TITLE
|
title = _CURRENT_CHAR_POOL_TITLE
|
||||||
elif pool_name == 'arms' and _CURRENT_ARMS_POOL_TITLE:
|
elif pool_name == "arms" and _CURRENT_ARMS_POOL_TITLE:
|
||||||
up_type = UP_ARMS
|
up_type = UP_ARMS
|
||||||
title = _CURRENT_ARMS_POOL_TITLE
|
title = _CURRENT_ARMS_POOL_TITLE
|
||||||
tmp = ''
|
tmp = ""
|
||||||
if up_type:
|
if up_type:
|
||||||
for x in up_type:
|
for x in up_type:
|
||||||
for operator in x.operators:
|
for operator in x.operators:
|
||||||
@@ -61,80 +82,105 @@ async def genshin_draw(user_id: int, count: int, pool_name: str):
|
|||||||
elif x.star == 4:
|
elif x.star == 4:
|
||||||
tmp += f'四星UP:{" ".join(x.operators)}'
|
tmp += f'四星UP:{" ".join(x.operators)}'
|
||||||
rst = init_star_rst(star_list, cnlist, five_list, five_index_list, up_list)
|
rst = init_star_rst(star_list, cnlist, five_list, five_index_list, up_list)
|
||||||
pool_info = f'当前up池:{title}\n{tmp}' if title else ''
|
pool_info = f"当前up池:{title}\n{tmp}" if title else ""
|
||||||
if count > 90:
|
if count > 90:
|
||||||
char_list = set_list(char_list)
|
char_list = set_list(char_list)
|
||||||
return pool_info + '\n' + MessageSegment.image(
|
return (
|
||||||
"base64://" + await generate_img(char_list, 'genshin', star_list)) + '\n' + rst[:-1] + \
|
pool_info
|
||||||
temp[:-1] + f'\n距离保底发还剩 {90 - genshin_count[user_id] if genshin_count.get(user_id) else "^"} 抽' \
|
+ "\n"
|
||||||
+ "\n【五星:0.6%,四星:5.1%\n第72抽开始五星概率每抽加0.585%】"
|
+ MessageSegment.image(
|
||||||
|
"base64://" + await generate_img(char_list, "genshin", star_list)
|
||||||
|
)
|
||||||
|
+ "\n"
|
||||||
|
+ rst[:-1]
|
||||||
|
+ temp[:-1]
|
||||||
|
+ f'\n距离保底发还剩 {90 - genshin_count[user_id] if genshin_count.get(user_id) else "^"} 抽'
|
||||||
|
+ "\n【五星:0.6%,四星:5.1%\n第72抽开始五星概率每抽加0.585%】"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def update_genshin_info():
|
async def update_genshin_info():
|
||||||
global ALL_CHAR, ALL_ARMS
|
global ALL_CHAR, ALL_ARMS
|
||||||
url = 'https://wiki.biligame.com/ys/角色筛选'
|
url = "https://wiki.biligame.com/ys/角色筛选"
|
||||||
data, code = await update_info(url, 'genshin')
|
data, code = await update_info(url, "genshin")
|
||||||
if code == 200:
|
if code == 200:
|
||||||
ALL_CHAR = init_game_pool('genshin', data, GenshinChar)
|
ALL_CHAR = init_game_pool("genshin", data, GenshinChar)
|
||||||
url = 'https://wiki.biligame.com/ys/武器图鉴'
|
url = "https://wiki.biligame.com/ys/武器图鉴"
|
||||||
data, code = await update_info(url, 'genshin_arms', ['头像', '名称', '类型', '稀有度.alt',
|
data, code = await update_info(
|
||||||
'获取途径', '初始基础属性1', '初始基础属性2',
|
url,
|
||||||
'攻击力(MAX)', '副属性(MAX)', '技能'])
|
"genshin_arms",
|
||||||
|
)
|
||||||
if code == 200:
|
if code == 200:
|
||||||
ALL_ARMS = init_game_pool('genshin_arms', data, GenshinChar)
|
ALL_ARMS = init_game_pool("genshin_arms", data, GenshinChar)
|
||||||
await _genshin_init_up_char()
|
await _genshin_init_up_char()
|
||||||
|
|
||||||
|
|
||||||
async def init_genshin_data():
|
async def init_genshin_data():
|
||||||
global ALL_CHAR, ALL_ARMS
|
global ALL_CHAR, ALL_ARMS
|
||||||
if GENSHIN_FLAG:
|
if GENSHIN_FLAG:
|
||||||
if not os.path.exists(DRAW_PATH + 'genshin.json') or not os.path.exists(DRAW_PATH + 'genshin_arms.json'):
|
if not os.path.exists(DRAW_PATH + "genshin.json") or not os.path.exists(
|
||||||
|
DRAW_PATH + "genshin_arms.json"
|
||||||
|
):
|
||||||
await update_genshin_info()
|
await update_genshin_info()
|
||||||
else:
|
else:
|
||||||
with open(DRAW_PATH + 'genshin.json', 'r', encoding='utf8') as f:
|
with open(DRAW_PATH + "genshin.json", "r", encoding="utf8") as f:
|
||||||
genshin_dict = json.load(f)
|
genshin_dict = json.load(f)
|
||||||
with open(DRAW_PATH + 'genshin_arms.json', 'r', encoding='utf8') as f:
|
with open(DRAW_PATH + "genshin_arms.json", "r", encoding="utf8") as f:
|
||||||
genshin_ARMS_dict = json.load(f)
|
genshin_ARMS_dict = json.load(f)
|
||||||
ALL_CHAR = init_game_pool('genshin', genshin_dict, GenshinChar)
|
ALL_CHAR = init_game_pool("genshin", genshin_dict, GenshinChar)
|
||||||
ALL_ARMS = init_game_pool('genshin_arms', genshin_ARMS_dict, GenshinChar)
|
ALL_ARMS = init_game_pool("genshin_arms", genshin_ARMS_dict, GenshinChar)
|
||||||
await _genshin_init_up_char()
|
await _genshin_init_up_char()
|
||||||
|
|
||||||
|
|
||||||
# 抽取卡池
|
# 抽取卡池
|
||||||
def _get_genshin_card(mode: int = 1, pool_name: str = '', add: float = 0.0):
|
def _get_genshin_card(mode: int = 1, pool_name: str = "", add: float = 0.0):
|
||||||
global ALL_ARMS, ALL_CHAR, UP_ARMS, UP_CHAR, _CURRENT_ARMS_POOL_TITLE, _CURRENT_CHAR_POOL_TITLE
|
global ALL_ARMS, ALL_CHAR, UP_ARMS, UP_CHAR, _CURRENT_ARMS_POOL_TITLE, _CURRENT_CHAR_POOL_TITLE
|
||||||
if mode == 1:
|
if mode == 1:
|
||||||
star = get_star([5, 4, 3], [GENSHIN_FIVE_P + add, GENSHIN_FOUR_P, GENSHIN_THREE_P])
|
star = get_star(
|
||||||
|
[5, 4, 3], [GENSHIN_FIVE_P + add, GENSHIN_FOUR_P, GENSHIN_THREE_P]
|
||||||
|
)
|
||||||
elif mode == 2:
|
elif mode == 2:
|
||||||
star = get_star([5, 4], [GENSHIN_G_FIVE_P + add, GENSHIN_G_FOUR_P])
|
star = get_star([5, 4], [GENSHIN_G_FIVE_P + add, GENSHIN_G_FOUR_P])
|
||||||
else:
|
else:
|
||||||
star = 5
|
star = 5
|
||||||
if pool_name == 'char':
|
if pool_name == "char":
|
||||||
data_lst = UP_CHAR
|
data_lst = UP_CHAR
|
||||||
flag = _CURRENT_CHAR_POOL_TITLE
|
flag = _CURRENT_CHAR_POOL_TITLE
|
||||||
itype_all_lst = ALL_CHAR + [x for x in ALL_ARMS if x.star == star and x.star < 5]
|
itype_all_lst = ALL_CHAR + [
|
||||||
elif pool_name == 'arms':
|
x for x in ALL_ARMS if x.star == star and x.star < 5
|
||||||
|
]
|
||||||
|
elif pool_name == "arms":
|
||||||
data_lst = UP_ARMS
|
data_lst = UP_ARMS
|
||||||
flag = _CURRENT_ARMS_POOL_TITLE
|
flag = _CURRENT_ARMS_POOL_TITLE
|
||||||
itype_all_lst = ALL_ARMS + [x for x in ALL_CHAR if x.star == star and x.star < 5]
|
itype_all_lst = ALL_ARMS + [
|
||||||
|
x for x in ALL_CHAR if x.star == star and x.star < 5
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
data_lst = ''
|
data_lst = ""
|
||||||
flag = ''
|
flag = ""
|
||||||
itype_all_lst = ''
|
itype_all_lst = ""
|
||||||
all_lst = ALL_ARMS + ALL_CHAR
|
all_lst = ALL_ARMS + ALL_CHAR
|
||||||
# 是否UP
|
# 是否UP
|
||||||
if flag and star > 3 and pool_name:
|
try:
|
||||||
# 获取up角色列表
|
if flag and star > 3 and pool_name:
|
||||||
up_char_lst = [x.operators for x in data_lst if x.star == star][0]
|
# 获取up角色列表
|
||||||
# 成功获取up角色
|
up_char_lst = [x.operators for x in data_lst if x.star == star][0]
|
||||||
if random.random() < 0.5:
|
# 成功获取up角色
|
||||||
up_char_name = random.choice(up_char_lst)
|
if random.random() < 0.5:
|
||||||
acquire_char = [x for x in all_lst if x.name == up_char_name][0]
|
up_char_name = random.choice(up_char_lst)
|
||||||
|
acquire_char = [x for x in all_lst if x.name == up_char_name][0]
|
||||||
|
else:
|
||||||
|
# 无up
|
||||||
|
all_char_lst = [
|
||||||
|
x
|
||||||
|
for x in itype_all_lst
|
||||||
|
if x.star == star and x.name not in up_char_lst and not x.limited
|
||||||
|
]
|
||||||
|
acquire_char = random.choice(all_char_lst)
|
||||||
else:
|
else:
|
||||||
# 无up
|
chars = [x for x in all_lst if x.star == star and not x.limited]
|
||||||
all_char_lst = [x for x in itype_all_lst if x.star == star and x.name not in up_char_lst and not x.limited]
|
acquire_char = random.choice(chars)
|
||||||
acquire_char = random.choice(all_char_lst)
|
except IndexError:
|
||||||
else:
|
|
||||||
chars = [x for x in all_lst if x.star == star and not x.limited]
|
chars = [x for x in all_lst if x.star == star and not x.limited]
|
||||||
acquire_char = random.choice(chars)
|
acquire_char = random.choice(chars)
|
||||||
return acquire_char, 5 - star
|
return acquire_char, 5 - star
|
||||||
@@ -146,12 +192,14 @@ def _format_card_information(_count: int, user_id, pool_name):
|
|||||||
five_index_list = []
|
five_index_list = []
|
||||||
five_list = []
|
five_list = []
|
||||||
five_dict = {}
|
five_dict = {}
|
||||||
|
_start_add_count = 72 if pool_name == "char" else 62
|
||||||
|
_x = 90 if pool_name == "char" else 80 # 保底
|
||||||
add = 0.0
|
add = 0.0
|
||||||
if genshin_count.get(user_id) and _count <= 90:
|
if genshin_count.get(user_id) and _count <= _x:
|
||||||
f_count = genshin_count[user_id]
|
f_count = genshin_count[user_id]
|
||||||
else:
|
else:
|
||||||
f_count = 0
|
f_count = 0
|
||||||
if genshin_pl_count.get(user_id) and _count <= 90:
|
if genshin_pl_count.get(user_id) and _count <= _x:
|
||||||
count = genshin_pl_count[user_id]
|
count = genshin_pl_count[user_id]
|
||||||
else:
|
else:
|
||||||
count = 0
|
count = 0
|
||||||
@@ -159,23 +207,23 @@ def _format_card_information(_count: int, user_id, pool_name):
|
|||||||
count += 1
|
count += 1
|
||||||
f_count += 1
|
f_count += 1
|
||||||
# 十连保底
|
# 十连保底
|
||||||
if count == 10 and f_count != 90:
|
if count == 10 and f_count != _x:
|
||||||
if f_count >= 72:
|
if f_count >= _start_add_count:
|
||||||
add += I72_ADD
|
add += I72_ADD
|
||||||
char, code = _get_genshin_card(2, pool_name, add=add)
|
char, code = _get_genshin_card(2, pool_name, add=add)
|
||||||
count = 0
|
count = 0
|
||||||
# 大保底
|
# 大保底
|
||||||
elif f_count == 90:
|
elif f_count == _x:
|
||||||
char, code = _get_genshin_card(3, pool_name)
|
char, code = _get_genshin_card(3, pool_name)
|
||||||
else:
|
else:
|
||||||
if f_count >= 72:
|
if f_count >= _start_add_count:
|
||||||
add += I72_ADD
|
add += I72_ADD
|
||||||
char, code = _get_genshin_card(pool_name=pool_name, add=add)
|
char, code = _get_genshin_card(pool_name=pool_name, add=add)
|
||||||
if code == 1:
|
if code == 1:
|
||||||
count = 0
|
count = 0
|
||||||
star_list[code] += 1
|
star_list[code] += 1
|
||||||
if code == 0:
|
if code == 0:
|
||||||
if _count <= 90:
|
if _count <= _x:
|
||||||
genshin_five[user_id] = f_count
|
genshin_five[user_id] = f_count
|
||||||
add = 0.0
|
add = 0.0
|
||||||
f_count = 0
|
f_count = 0
|
||||||
@@ -186,7 +234,7 @@ def _format_card_information(_count: int, user_id, pool_name):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
five_dict[char.name] = 1
|
five_dict[char.name] = 1
|
||||||
char_list.append(char)
|
char_list.append(char)
|
||||||
if _count <= 90:
|
if _count <= _x:
|
||||||
genshin_count[user_id] = f_count
|
genshin_count[user_id] = f_count
|
||||||
genshin_pl_count[user_id] = count
|
genshin_pl_count[user_id] = count
|
||||||
return char_list, five_list, five_index_list, five_dict, star_list
|
return char_list, five_list, five_index_list, five_dict, star_list
|
||||||
@@ -200,9 +248,17 @@ def reset_count(user_id: int):
|
|||||||
# 获取up和概率
|
# 获取up和概率
|
||||||
async def _genshin_init_up_char():
|
async def _genshin_init_up_char():
|
||||||
global _CURRENT_CHAR_POOL_TITLE, _CURRENT_ARMS_POOL_TITLE, UP_CHAR, UP_ARMS, POOL_IMG
|
global _CURRENT_CHAR_POOL_TITLE, _CURRENT_ARMS_POOL_TITLE, UP_CHAR, UP_ARMS, POOL_IMG
|
||||||
_CURRENT_CHAR_POOL_TITLE, _CURRENT_ARMS_POOL_TITLE, POOL_IMG, UP_CHAR, UP_ARMS = await init_up_char(announcement)
|
(
|
||||||
|
_CURRENT_CHAR_POOL_TITLE,
|
||||||
|
_CURRENT_ARMS_POOL_TITLE,
|
||||||
|
POOL_IMG,
|
||||||
|
UP_CHAR,
|
||||||
|
UP_ARMS,
|
||||||
|
) = await init_up_char(announcement)
|
||||||
|
|
||||||
|
|
||||||
async def reload_genshin_pool():
|
async def reload_genshin_pool():
|
||||||
await _genshin_init_up_char()
|
await _genshin_init_up_char()
|
||||||
return Message(f'当前UP池子:{_CURRENT_CHAR_POOL_TITLE} & {_CURRENT_ARMS_POOL_TITLE} {POOL_IMG}')
|
return Message(
|
||||||
|
f"当前UP池子:{_CURRENT_CHAR_POOL_TITLE} & {_CURRENT_ARMS_POOL_TITLE} {POOL_IMG}"
|
||||||
|
)
|
||||||
|
|||||||
@@ -179,10 +179,13 @@ async def _last_check(data: dict, game_name: str):
|
|||||||
|
|
||||||
# 对抓取每行数据是否需要额外处理?
|
# 对抓取每行数据是否需要额外处理?
|
||||||
def intermediate_check(member_dict: dict, key: str, game_name: str, td: bs4.element.Tag):
|
def intermediate_check(member_dict: dict, key: str, game_name: str, td: bs4.element.Tag):
|
||||||
|
if game_name == "genshin_arms":
|
||||||
|
if key == "稀有度":
|
||||||
|
member_dict["稀有度"] = td.find("img")["alt"].split('.')[0]
|
||||||
if game_name == 'prts':
|
if game_name == 'prts':
|
||||||
if key == '获取途径':
|
if key == '获取途径':
|
||||||
msg = re.search('<td.*?>([\\s\\S]*)</td>', str(td)).group(1).strip()
|
msg = re.search('<td.*?>([\\s\\S]*)</td>', str(td)).group(1).strip()
|
||||||
msg = msg[:-1] if msg[-1] == '\n' else msg
|
msg = msg[:-1] if msg and msg[-1] == '\n' else msg
|
||||||
if msg.find('<a') != -1:
|
if msg.find('<a') != -1:
|
||||||
for a in td.find_all('a'):
|
for a in td.find_all('a'):
|
||||||
msg = msg.replace(str(a), a.text)
|
msg = msg.replace(str(a), a.text)
|
||||||
|
|||||||
@@ -131,8 +131,9 @@ async def retrieve_char_data(char: bs4.element.Tag, game_name: str, data: dict,
|
|||||||
'名称': remove_prohibited_str(char.find('a')['title']),
|
'名称': remove_prohibited_str(char.find('a')['title']),
|
||||||
'星级': 3 - index}
|
'星级': 3 - index}
|
||||||
if game_name == 'azur':
|
if game_name == 'azur':
|
||||||
char = char.find('div').find('div').find('div').find('div')
|
char = char.find('div').find('div').find('div')
|
||||||
avatar_img = char.find('a').find('img')
|
avatar_img = char.find('a').find('img')
|
||||||
|
char = char.find('div')
|
||||||
try:
|
try:
|
||||||
member_dict['名称'] = remove_prohibited_str(char.find('a')['title'])
|
member_dict['名称'] = remove_prohibited_str(char.find('a')['title'])
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from utils.utils import get_message_imgs, get_message_text
|
from utils.utils import get_message_img, get_message_text
|
||||||
from utils.message_builder import share
|
from utils.message_builder import share
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ fake_msg = on_command("假消息", priority=5, block=True)
|
|||||||
@fake_msg.handle()
|
@fake_msg.handle()
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
msg = get_message_text(event.json()).split(" ")
|
msg = get_message_text(event.json()).split(" ")
|
||||||
img = get_message_imgs(event.json())
|
img = get_message_img(event.json())
|
||||||
if len(msg) > 1:
|
if len(msg) > 1:
|
||||||
if len(msg) == 2:
|
if len(msg) == 2:
|
||||||
url = msg[0]
|
url = msg[0]
|
||||||
|
|||||||
+9
-7
@@ -4,7 +4,7 @@ from utils.image_utils import get_img_hash
|
|||||||
import random
|
import random
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from nonebot import on_message
|
from nonebot import on_message
|
||||||
from utils.utils import get_message_text, get_message_imgs
|
from utils.utils import get_message_text, get_message_img
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
@@ -90,12 +90,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
if get_message_text(event.json()):
|
if get_message_text(event.json()):
|
||||||
if get_message_text(event.json()).find("@可爱的小真寻") != -1:
|
if get_message_text(event.json()).find("@可爱的小真寻") != -1:
|
||||||
await fudu.finish("复制粘贴的虚空艾特?", at_sender=True)
|
await fudu.finish("复制粘贴的虚空艾特?", at_sender=True)
|
||||||
imgs = get_message_imgs(event.json())
|
img = get_message_img(event.json())
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
if not imgs and not msg:
|
if not img and not msg:
|
||||||
return
|
return
|
||||||
if imgs:
|
if img:
|
||||||
img_hash = await get_fudu_img_hash(imgs[0], event.group_id)
|
img_hash = await get_fudu_img_hash(img[0], event.group_id)
|
||||||
else:
|
else:
|
||||||
img_hash = ""
|
img_hash = ""
|
||||||
add_msg = msg + "|-|" + img_hash
|
add_msg = msg + "|-|" + img_hash
|
||||||
@@ -113,15 +113,17 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
if random.random() < 0.2:
|
if random.random() < 0.2:
|
||||||
await fudu.finish("打断施法!")
|
await fudu.finish("打断施法!")
|
||||||
_fudu_list.set_repeater(event.group_id)
|
_fudu_list.set_repeater(event.group_id)
|
||||||
if imgs and msg:
|
if img and msg:
|
||||||
rst = msg + image(f"compare_{event.group_id}_img.jpg", "temp")
|
rst = msg + image(f"compare_{event.group_id}_img.jpg", "temp")
|
||||||
elif imgs:
|
elif img:
|
||||||
rst = image(f"compare_{event.group_id}_img.jpg", "temp")
|
rst = image(f"compare_{event.group_id}_img.jpg", "temp")
|
||||||
elif msg:
|
elif msg:
|
||||||
rst = msg
|
rst = msg
|
||||||
else:
|
else:
|
||||||
rst = ""
|
rst = ""
|
||||||
if rst:
|
if rst:
|
||||||
|
if rst.endswith("打断施法!"):
|
||||||
|
rst = "打断" + rst
|
||||||
await fudu.send(rst)
|
await fudu.send(rst)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ from utils.browser import get_browser
|
|||||||
from configs.path_config import IMAGE_PATH
|
from configs.path_config import IMAGE_PATH
|
||||||
import nonebot
|
import nonebot
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from utils.utils import scheduler
|
|
||||||
from nonebot.permission import SUPERUSER
|
from nonebot.permission import SUPERUSER
|
||||||
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from datetime import datetime, timedelta
|
||||||
import os
|
import os
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
@@ -52,9 +53,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
if time.strftime("%w") == "0":
|
if time.strftime("%w") == "0":
|
||||||
await material.send("今天是周日,所有材料副本都开放了。")
|
await material.send("今天是周日,所有材料副本都开放了。")
|
||||||
return
|
return
|
||||||
|
file_name = str((datetime.now() - timedelta(hours=4)).date())
|
||||||
|
if not (Path(IMAGE_PATH) / "genshin" / "material" / f"{file_name}.png").exists():
|
||||||
|
await update_image()
|
||||||
await material.send(
|
await material.send(
|
||||||
Message(
|
Message(
|
||||||
image("daily_material.png", "genshin/material")
|
image(f"{file_name}.png", "genshin/material")
|
||||||
+ "\n※ 每日素材数据来源于 genshin.pub"
|
+ "\n※ 每日素材数据来源于 genshin.pub"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -73,7 +77,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
await super_cmd.send(f"更新失败...")
|
await super_cmd.send(f"更新失败...")
|
||||||
|
|
||||||
|
|
||||||
@driver.on_startup
|
|
||||||
async def update_image():
|
async def update_image():
|
||||||
page = None
|
page = None
|
||||||
try:
|
try:
|
||||||
@@ -140,7 +143,8 @@ async def update_image():
|
|||||||
background_img.paste(x, (current_width, current_height))
|
background_img.paste(x, (current_width, current_height))
|
||||||
current_height += x.size[1]
|
current_height += x.size[1]
|
||||||
current_width += 600
|
current_width += 600
|
||||||
background_img.save(f"{IMAGE_PATH}/genshin/material/daily_material.png")
|
file_name = str((datetime.now() - timedelta(hours=4)).date())
|
||||||
|
background_img.save(f"{IMAGE_PATH}/genshin/material/{file_name}.png")
|
||||||
await page.close()
|
await page.close()
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -163,16 +167,3 @@ def get_background_height(weapons_imgs: List[str]) -> int:
|
|||||||
return height
|
return height
|
||||||
|
|
||||||
|
|
||||||
@scheduler.scheduled_job(
|
|
||||||
"cron",
|
|
||||||
hour=4,
|
|
||||||
minute=1,
|
|
||||||
)
|
|
||||||
async def _():
|
|
||||||
for _ in range(5):
|
|
||||||
try:
|
|
||||||
await update_image()
|
|
||||||
logger.info(f"更新每日天赋素材成功...")
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"更新每日天赋素材出错 e:{e}")
|
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ __plugin_settings__ = {
|
|||||||
"limit_superuser": False,
|
"limit_superuser": False,
|
||||||
"cmd": ["原神资源查询", "原神资源列表"],
|
"cmd": ["原神资源查询", "原神资源列表"],
|
||||||
}
|
}
|
||||||
|
__plugin_block_limit__ = {
|
||||||
|
"rst": "您有资源正在查询!"
|
||||||
|
}
|
||||||
|
|
||||||
qr = on_command("原神资源查询", aliases={"原神资源查找"}, priority=5, block=True)
|
qr = on_command("原神资源查询", aliases={"原神资源查找"}, priority=5, block=True)
|
||||||
qr_lst = on_command("原神资源列表", priority=5, block=True)
|
qr_lst = on_command("原神资源列表", priority=5, block=True)
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ async def init(flag: bool = False):
|
|||||||
resource_name_list.append(x["name"])
|
resource_name_list.append(x["name"])
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
logger.warning('原神资源查询信息初始化超时....')
|
logger.warning('原神资源查询信息初始化超时....')
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# 图标及位置资源
|
# 图标及位置资源
|
||||||
@@ -185,12 +184,13 @@ async def download_map_init(
|
|||||||
semaphore,
|
semaphore,
|
||||||
force_flag=flag,
|
force_flag=flag,
|
||||||
)
|
)
|
||||||
|
BuildImage(0, 0, background=f"{map_path}/{idx}.png", ratio=MAP_RATIO).save()
|
||||||
idx += 1
|
idx += 1
|
||||||
_w, h = BuildImage(0, 0, background=f"{map_path}/0.png", ratio=MAP_RATIO).size
|
_w, h = BuildImage(0, 0, background=f"{map_path}/0.png").size
|
||||||
w = _w * len(os.listdir(map_path))
|
w = _w * len(os.listdir(map_path))
|
||||||
map_file = BuildImage(w, h, _w, h, ratio=MAP_RATIO)
|
map_file = BuildImage(w, h, _w, h, ratio=MAP_RATIO)
|
||||||
for i in range(idx):
|
for i in range(idx):
|
||||||
map_file.paste(BuildImage(0, 0, background=f"{map_path}/{i}.png", ratio=MAP_RATIO))
|
map_file.paste(BuildImage(0, 0, background=f"{map_path}/{i}.png"))
|
||||||
map_file.save(f"{map_path}/map.png")
|
map_file.save(f"{map_path}/map.png")
|
||||||
else:
|
else:
|
||||||
logger.warning(f'获取原神地图失败 msg: {data["message"]}')
|
logger.warning(f'获取原神地图失败 msg: {data["message"]}')
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ Config.add_plugin_config(
|
|||||||
"xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs"
|
"xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"genshin",
|
||||||
|
"n",
|
||||||
|
"h8w582wxwgqvahcdkpvdhbh2w9casgfl"
|
||||||
|
)
|
||||||
|
|
||||||
Config.add_plugin_config(
|
Config.add_plugin_config(
|
||||||
"genshin",
|
"genshin",
|
||||||
"client_type",
|
"client_type",
|
||||||
@@ -24,3 +30,4 @@ nonebot.load_plugins("plugins/genshin/query_user")
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ usage:
|
|||||||
原神绑定uid [uid]
|
原神绑定uid [uid]
|
||||||
原神绑定米游社id [mys_id]
|
原神绑定米游社id [mys_id]
|
||||||
原神绑定cookie [cookie] # 该绑定请私聊
|
原神绑定cookie [cookie] # 该绑定请私聊
|
||||||
原神解绑 [uid]
|
原神解绑
|
||||||
示例:原神绑定uid 92342233
|
示例:原神绑定uid 92342233
|
||||||
如果不明白怎么获取cookie请输入“原神绑定cookie”。
|
如果不明白怎么获取cookie请输入“原神绑定cookie”。
|
||||||
""".strip()
|
""".strip()
|
||||||
@@ -63,16 +63,16 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
else:
|
else:
|
||||||
if not msg:
|
if not msg:
|
||||||
await bind.finish(
|
await bind.finish(
|
||||||
"私聊发送!!\n打开https://bbs.mihoyo.com/ys/登录后按F12点击控制台输入document.cookie复制输出的内容即可"
|
"私聊发送!!\n打开https://bbs.mihoyo.com/ys/\n登录后按F12点击控制台输入document.cookie复制输出的内容即可"
|
||||||
)
|
)
|
||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
await bind.finish("请立即撤回你的消息并私聊发送!")
|
await bind.finish("请立即撤回你的消息并私聊发送!")
|
||||||
uid = await Genshin.get_user_uid(event.user_id)
|
uid = await Genshin.get_user_uid(event.user_id)
|
||||||
if not uid:
|
if not uid:
|
||||||
await bind.finish("请先绑定原神uid..")
|
await bind.finish("请先绑定原神uid..")
|
||||||
if msg.startswith('"'):
|
if msg.startswith('"') or msg.startswith("'"):
|
||||||
msg = msg[1:]
|
msg = msg[1:]
|
||||||
if msg.endswith('"'):
|
if msg.endswith('"') or msg.endswith("'"):
|
||||||
msg = msg[:-1]
|
msg = msg[:-1]
|
||||||
await Genshin.set_cookie(uid, msg)
|
await Genshin.set_cookie(uid, msg)
|
||||||
_x = f"已成功为uid:{uid} 设置cookie"
|
_x = f"已成功为uid:{uid} 设置cookie"
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
from .data_source import get_sign_reward_list, genshin_sign
|
||||||
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||||
|
from nonebot import on_command
|
||||||
|
from nonebot.typing import T_State
|
||||||
|
from services.log import logger
|
||||||
|
from .init_task import add_job, scheduler, _sign
|
||||||
|
from apscheduler.jobstores.base import JobLookupError
|
||||||
|
from ..models import Genshin
|
||||||
|
|
||||||
|
|
||||||
|
__zx_plugin_name__ = "原神自动签到"
|
||||||
|
__plugin_usage__ = """
|
||||||
|
usage:
|
||||||
|
米游社原神签到,需要uid以及cookie
|
||||||
|
且在第二天自动排序签到时间
|
||||||
|
# 不听,就要手动签到!(使用命令 “原神我硬签 or 米游社我硬签”
|
||||||
|
指令:
|
||||||
|
开/关原神自动签到
|
||||||
|
原神我硬签
|
||||||
|
""".strip()
|
||||||
|
__plugin_des__ = "原神懒人签到"
|
||||||
|
__plugin_cmd__ = ["开/关原神自动签到", "原神我硬签"]
|
||||||
|
__plugin_type__ = ("原神相关",)
|
||||||
|
__plugin_version__ = 0.1
|
||||||
|
__plugin_author__ = "HibiKier"
|
||||||
|
__plugin_settings__ = {
|
||||||
|
"level": 5,
|
||||||
|
"default_status": True,
|
||||||
|
"limit_superuser": False,
|
||||||
|
"cmd": ["原神签到"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
genshin_matcher = on_command(
|
||||||
|
"开原神自动签到", aliases={"关原神自动签到", "原神我硬签"}, priority=5, block=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@genshin_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 genshin_matcher.finish("请先绑定uid和cookie!")
|
||||||
|
if "account_id" not in await Genshin.get_user_cookie(uid, True):
|
||||||
|
await genshin_matcher.finish("请更新cookie!")
|
||||||
|
if state["_prefix"]["raw_command"] == "原神我硬签":
|
||||||
|
try:
|
||||||
|
msg = await genshin_sign(uid)
|
||||||
|
logger.info(
|
||||||
|
f"(USER {event.user_id}, "
|
||||||
|
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{uid} 原神签到"
|
||||||
|
)
|
||||||
|
# 硬签,移除定时任务
|
||||||
|
try:
|
||||||
|
for i in range(3):
|
||||||
|
scheduler.remove_job(f"genshin_auto_sign_{uid}_{event.user_id}_{i}",)
|
||||||
|
except JobLookupError:
|
||||||
|
pass
|
||||||
|
u = await Genshin.get_user_by_uid(uid)
|
||||||
|
if u and u.auto_sign:
|
||||||
|
await u.clear_sign_time(uid)
|
||||||
|
next_date = await Genshin.random_sign_time(uid)
|
||||||
|
add_job(event.user_id, uid, next_date)
|
||||||
|
msg += f"因开启自动签到\n下一次签到时间为:{next_date.replace(microsecond=0)}"
|
||||||
|
except Exception as e:
|
||||||
|
msg = "原神签到失败..请尝试检查cookie或报告至管理员!"
|
||||||
|
logger.info(
|
||||||
|
f"(USER {event.user_id}, "
|
||||||
|
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{uid} 原神签到发生错误 "
|
||||||
|
f"{type(e)}:{e}"
|
||||||
|
)
|
||||||
|
msg = msg or "请检查cookie是否更新!"
|
||||||
|
await genshin_matcher.send(msg, at_sender=True)
|
||||||
|
else:
|
||||||
|
for i in range(3):
|
||||||
|
try:
|
||||||
|
scheduler.remove_job(f"genshin_auto_sign_{uid}_{event.user_id}_{i}")
|
||||||
|
except JobLookupError:
|
||||||
|
pass
|
||||||
|
if state["_prefix"]["raw_command"][0] == "开":
|
||||||
|
await Genshin.set_auto_sign(uid, True)
|
||||||
|
next_date = await Genshin.random_sign_time(uid)
|
||||||
|
add_job(event.user_id, uid, next_date)
|
||||||
|
await genshin_matcher.send(
|
||||||
|
f"已开启原神自动签到!\n下一次签到时间为:{next_date.replace(microsecond=0)}",
|
||||||
|
at_sender=True,
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
f"(USER {event.user_id}, GROUP "
|
||||||
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
|
f" 开启原神自动签到"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await Genshin.set_auto_sign(uid, False)
|
||||||
|
await Genshin.clear_sign_time(uid)
|
||||||
|
await genshin_matcher.send(f"已关闭原神自动签到!", at_sender=True)
|
||||||
|
logger.info(
|
||||||
|
f"(USER {event.user_id}, GROUP "
|
||||||
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
|
f" 关闭原神自动签到"
|
||||||
|
)
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
from utils.http_utils import AsyncHttpx
|
||||||
|
from configs.config import Config
|
||||||
|
from services.log import logger
|
||||||
|
from ..utils import random_hex, get_old_ds
|
||||||
|
from ..models import Genshin
|
||||||
|
from typing import Optional, Dict
|
||||||
|
|
||||||
|
|
||||||
|
async def genshin_sign(uid: int) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
原神签到信息
|
||||||
|
:param uid: uid
|
||||||
|
"""
|
||||||
|
data = await _sign(uid)
|
||||||
|
if not data:
|
||||||
|
return "签到失败..."
|
||||||
|
status = data["message"]
|
||||||
|
if status == "OK":
|
||||||
|
sign_info = await _get_sign_info(uid)
|
||||||
|
if sign_info:
|
||||||
|
sign_info = sign_info["data"]
|
||||||
|
sign_list = await get_sign_reward_list()
|
||||||
|
get_reward = sign_list["data"]["awards"][
|
||||||
|
int(sign_info["total_sign_day"]) - 1
|
||||||
|
]["name"]
|
||||||
|
reward_num = sign_list["data"]["awards"][
|
||||||
|
int(sign_info["total_sign_day"]) - 1
|
||||||
|
]["cnt"]
|
||||||
|
get_im = f"本次签到获得:{get_reward}x{reward_num}"
|
||||||
|
if status == "OK" and sign_info["is_sign"]:
|
||||||
|
return f"\n原神签到成功!\n{get_im}\n本月漏签次数:{sign_info['sign_cnt_missed']}"
|
||||||
|
else:
|
||||||
|
return status
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def _sign(uid: int, server_id: str = "cn_gf01") -> Optional[Dict[str, str]]:
|
||||||
|
"""
|
||||||
|
米游社签到
|
||||||
|
:param uid: uid
|
||||||
|
:param server_id: 服务器id
|
||||||
|
"""
|
||||||
|
if str(uid)[0] == "5":
|
||||||
|
server_id = "cn_qd01"
|
||||||
|
try:
|
||||||
|
req = await AsyncHttpx.post(
|
||||||
|
url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign",
|
||||||
|
headers={
|
||||||
|
"User_Agent": "Mozilla/5.0 (Linux; Android 10; MIX 2 Build/QKQ1.190825.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.101 Mobile Safari/537.36 miHoYoBBS/2.3.0",
|
||||||
|
"Cookie": await Genshin.get_user_cookie(int(uid), True),
|
||||||
|
"x-rpc-device_id": random_hex(32),
|
||||||
|
"Origin": "https://webstatic.mihoyo.com",
|
||||||
|
"X_Requested_With": "com.mihoyo.hyperion",
|
||||||
|
"DS": get_old_ds(),
|
||||||
|
"x-rpc-client_type": "5",
|
||||||
|
"Referer": "https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=e202009291139501&utm_source=bbs&utm_medium=mys&utm_campaign=icon",
|
||||||
|
"x-rpc-app_version": "2.3.0",
|
||||||
|
},
|
||||||
|
json={"act_id": "e202009291139501", "uid": uid, "region": server_id},
|
||||||
|
)
|
||||||
|
return req.json()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"米游社签到发生错误 UID:{uid} {type(e)}:{e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def get_sign_reward_list():
|
||||||
|
"""
|
||||||
|
获取签到奖励列表
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
req = await AsyncHttpx.get(
|
||||||
|
url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/home?act_id=e202009291139501",
|
||||||
|
headers={
|
||||||
|
"x-rpc-app_version": str(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": str(Config.get_config("genshin", "client_type")),
|
||||||
|
"Referer": "https://webstatic.mihoyo.com/",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return req.json()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取签到奖励列表发生错误 {type(e)}:{e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def _get_sign_info(uid: int, server_id: str = "cn_gf01"):
|
||||||
|
if str(uid)[0] == "5":
|
||||||
|
server_id = "cn_qd01"
|
||||||
|
try:
|
||||||
|
req = await AsyncHttpx.get(
|
||||||
|
url=f"https://api-takumi.mihoyo.com/event/bbs_sign_reward/info?act_id=e202009291139501®ion={server_id}&uid={uid}",
|
||||||
|
headers={
|
||||||
|
"x-rpc-app_version": str(Config.get_config("genshin", "mhyVersion")),
|
||||||
|
"Cookie": await Genshin.get_user_cookie(int(uid), True),
|
||||||
|
"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": str(Config.get_config("genshin", "client_type")),
|
||||||
|
"Referer": "https://webstatic.mihoyo.com/",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return req.json()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取签到信息发生错误 UID:{uid} {type(e)}:{e}")
|
||||||
|
return None
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
from .data_source import genshin_sign
|
||||||
|
from models.group_member_info import GroupInfoUser
|
||||||
|
from utils.message_builder import at
|
||||||
|
from services.log import logger
|
||||||
|
from utils.utils import scheduler, get_bot
|
||||||
|
from apscheduler.jobstores.base import ConflictingIdError
|
||||||
|
from ..models import Genshin
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from nonebot import Driver
|
||||||
|
import nonebot
|
||||||
|
import random
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
|
||||||
|
driver: Driver = nonebot.get_driver()
|
||||||
|
|
||||||
|
|
||||||
|
@driver.on_startup
|
||||||
|
async def _():
|
||||||
|
"""
|
||||||
|
启动时分配定时任务
|
||||||
|
"""
|
||||||
|
g_list = await Genshin.get_all_auto_sign_user()
|
||||||
|
for u in g_list:
|
||||||
|
if u.auto_sign_time:
|
||||||
|
date = await Genshin.random_sign_time(u.uid)
|
||||||
|
scheduler.add_job(
|
||||||
|
_sign,
|
||||||
|
"date",
|
||||||
|
run_date=date.replace(microsecond=0),
|
||||||
|
id=f"genshin_auto_sign_{u.uid}_{u.user_qq}_0",
|
||||||
|
args=[u.user_qq, u.uid, 0],
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
f"genshin_sign add_job:USER:{u.user_qq} UID:{u.uid} " f"{date} 原神自动签到"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def add_job(user_id: int, uid: int, date: datetime):
|
||||||
|
try:
|
||||||
|
scheduler.add_job(
|
||||||
|
_sign,
|
||||||
|
"date",
|
||||||
|
run_date=date.replace(microsecond=0),
|
||||||
|
id=f"genshin_auto_sign_{uid}_{user_id}_0",
|
||||||
|
args=[user_id, uid, 0],
|
||||||
|
)
|
||||||
|
logger.debug(f"genshin_sign add_job:{date.replace(microsecond=0)} 原神自动签到")
|
||||||
|
except ConflictingIdError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
async def _sign(user_id: int, uid: int, count: int):
|
||||||
|
"""
|
||||||
|
执行签到任务
|
||||||
|
:param user_id: 用户id
|
||||||
|
:param uid: uid
|
||||||
|
:param count: 执行次数
|
||||||
|
"""
|
||||||
|
if count < 3:
|
||||||
|
try:
|
||||||
|
msg = await genshin_sign(uid)
|
||||||
|
next_time = await Genshin.random_sign_time(uid)
|
||||||
|
msg += f"\n下一次签到时间为:{next_time.replace(microsecond=0)}"
|
||||||
|
logger.info(f"USER:{user_id} UID:{uid} 原神自动签到任务发生成功...")
|
||||||
|
try:
|
||||||
|
scheduler.add_job(
|
||||||
|
_sign,
|
||||||
|
"date",
|
||||||
|
run_date=next_time.replace(microsecond=0),
|
||||||
|
id=f"genshin_auto_sign_{uid}_{user_id}_0",
|
||||||
|
args=[user_id, uid, 0],
|
||||||
|
)
|
||||||
|
except ConflictingIdError:
|
||||||
|
msg += "\n定时任务设定失败..."
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"USER:{user_id} UID:{uid} 原神自动签到任务发生错误 {type(e)}:{e}")
|
||||||
|
msg = None
|
||||||
|
if not msg:
|
||||||
|
now = datetime.now(pytz.timezone("Asia/Shanghai"))
|
||||||
|
if now.hour < 23:
|
||||||
|
random_hours = random.randint(1, 23 - now.hour)
|
||||||
|
next_time = now + timedelta(hours=random_hours)
|
||||||
|
scheduler.add_job(
|
||||||
|
_sign,
|
||||||
|
"date",
|
||||||
|
run_date=next_time.replace(microsecond=0),
|
||||||
|
id=f"genshin_auto_sign_{uid}_{user_id}_{count}",
|
||||||
|
args=[user_id, uid, count + 1],
|
||||||
|
)
|
||||||
|
msg = (
|
||||||
|
f"{now.replace(microsecond=0)} 原神"
|
||||||
|
f"签到失败,将在 {next_time.replace(microsecond=0)} 时重试!"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
msg = "今日原神签到失败,请手动签到..."
|
||||||
|
logger.debug(f"USER:{user_id} UID:{uid} 原神今日签到失败...")
|
||||||
|
else:
|
||||||
|
msg = "今日原神自动签到重试次数已达到3次,请手动签到。"
|
||||||
|
logger.debug(f"USER:{user_id} UID:{uid} 原神今日签到失败次数打到 3 次...")
|
||||||
|
bot = get_bot()
|
||||||
|
if bot:
|
||||||
|
if user_id in [x["user_id"] for x in await bot.get_friend_list()]:
|
||||||
|
await bot.send_private_msg(user_id=user_id, message=msg)
|
||||||
|
else:
|
||||||
|
group_list = await GroupInfoUser.get_user_all_group(user_id)
|
||||||
|
if group_list:
|
||||||
|
await bot.send_group_msg(
|
||||||
|
group_id=group_list[0], message=at(user_id) + msg
|
||||||
|
)
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
from services.db_context import db
|
from services.db_context import db
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union, List
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import random
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
|
||||||
class Genshin(db.Model):
|
class Genshin(db.Model):
|
||||||
@@ -11,7 +14,10 @@ class Genshin(db.Model):
|
|||||||
mys_id = db.Column(db.BigInteger())
|
mys_id = db.Column(db.BigInteger())
|
||||||
cookie = db.Column(db.String(), default="")
|
cookie = db.Column(db.String(), default="")
|
||||||
today_query_uid = db.Column(db.String(), default="") # 该cookie今日查询的uid
|
today_query_uid = db.Column(db.String(), default="") # 该cookie今日查询的uid
|
||||||
auto_sign = db.Column(db.Boolean(), default=False) # 自动签到
|
auto_sign = db.Column(db.Boolean(), default=False)
|
||||||
|
auto_sign_time = db.Column(db.DateTime(timezone=True))
|
||||||
|
resin_remind = db.Column(db.Boolean(), default=False) # 树脂提醒
|
||||||
|
resin_recovery_time = db.Column(db.DateTime(timezone=True)) # 满树脂提醒日期
|
||||||
|
|
||||||
_idx1 = db.Index("genshin_uid_idx1", "user_qq", "uid", unique=True)
|
_idx1 = db.Index("genshin_uid_idx1", "user_qq", "uid", unique=True)
|
||||||
|
|
||||||
@@ -66,11 +72,75 @@ class Genshin(db.Model):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def set_resin_remind(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(resin_remind=flag).apply()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def set_user_resin_recovery_time(cls, uid: int, date: datetime):
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
设置体力完成时间
|
||||||
|
参数:
|
||||||
|
:param uid: uid
|
||||||
|
:param date: 提醒日期
|
||||||
|
"""
|
||||||
|
u = await cls.query.where(cls.uid == uid).gino.first()
|
||||||
|
if u:
|
||||||
|
await u.update(resin_recovery_time=date).apply()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_user_resin_recovery_time(cls, uid: int) -> Optional[datetime]:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
获取体力完成时间
|
||||||
|
参数:
|
||||||
|
:param uid: uid
|
||||||
|
"""
|
||||||
|
u = await cls.query.where(cls.uid == uid).gino.first()
|
||||||
|
if u:
|
||||||
|
return u.resin_recovery_time.astimezone(pytz.timezone("Asia/Shanghai"))
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_all_resin_remind_user(cls) -> List["Genshin"]:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
获取所有开启体力提醒的用户
|
||||||
|
"""
|
||||||
|
return await cls.query.where(cls.resin_remind == True).gino.all()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def clear_resin_remind_time(cls, uid: int) -> bool:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
清空提醒日期
|
||||||
|
参数:
|
||||||
|
:param uid: uid
|
||||||
|
"""
|
||||||
|
user = await cls.query.where(cls.uid == uid).gino.first()
|
||||||
|
if user:
|
||||||
|
await user.update(resin_recovery_time=None).apply()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
|
async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
设置米游社自动签到
|
设置米游社/原神自动签到
|
||||||
参数:
|
参数:
|
||||||
:param uid: 原神uid
|
:param uid: 原神uid
|
||||||
:param flag: 开关状态
|
:param flag: 开关状态
|
||||||
@@ -82,6 +152,66 @@ class Genshin(db.Model):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_all_auto_sign_user(cls) -> List["Genshin"]:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
获取所有开启自动签到的用户
|
||||||
|
"""
|
||||||
|
return await cls.query.where(cls.auto_sign == True).gino.all()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_all_sign_user(cls) -> List["Genshin"]:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
获取 原神 所有今日签到用户
|
||||||
|
"""
|
||||||
|
return await cls.query.where(cls.auto_sign_time != None).gino.all()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def clear_sign_time(cls, uid: int) -> bool:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
清空签到日期
|
||||||
|
参数:
|
||||||
|
:param uid: uid
|
||||||
|
"""
|
||||||
|
user = await cls.query.where(cls.uid == uid).gino.first()
|
||||||
|
if user:
|
||||||
|
await user.update(auto_sign_time=None).apply()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def random_sign_time(cls, uid: int) -> Optional[datetime]:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
随机签到时间
|
||||||
|
说明:
|
||||||
|
:param uid: uid
|
||||||
|
"""
|
||||||
|
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||||
|
user = await query.gino.first()
|
||||||
|
if user and user.cookie:
|
||||||
|
if user.auto_sign_time and user.auto_sign_time.astimezone(
|
||||||
|
pytz.timezone("Asia/Shanghai")
|
||||||
|
) - timedelta(seconds=2) >= datetime.now(pytz.timezone("Asia/Shanghai")):
|
||||||
|
return user.auto_sign_time.astimezone(pytz.timezone("Asia/Shanghai"))
|
||||||
|
hours = int(str(datetime.now()).split()[1].split(":")[0])
|
||||||
|
minutes = int(str(datetime.now()).split()[1].split(":")[1])
|
||||||
|
date = (
|
||||||
|
datetime.now()
|
||||||
|
+ timedelta(days=1)
|
||||||
|
- timedelta(hours=hours)
|
||||||
|
- timedelta(minutes=minutes - 1)
|
||||||
|
)
|
||||||
|
random_hours = random.randint(0, 22)
|
||||||
|
random_minutes = random.randint(1, 59)
|
||||||
|
date += timedelta(hours=random_hours) + timedelta(minutes=random_minutes)
|
||||||
|
await user.update(auto_sign_time=date).apply()
|
||||||
|
return date
|
||||||
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_query_cookie(cls, uid: int) -> Optional[str]:
|
async def get_query_cookie(cls, uid: int) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
@@ -95,7 +225,9 @@ class Genshin(db.Model):
|
|||||||
x = await query.gino.first()
|
x = await query.gino.first()
|
||||||
if x:
|
if x:
|
||||||
return x.cookie
|
return x.cookie
|
||||||
for u in [x for x in await cls.query.order_by(db.func.random()).gino.all() if 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:
|
if not u.today_query_uid or len(u.today_query_uid[:-1].split()) < 30:
|
||||||
await cls._add_query_uid(uid, u.uid)
|
await cls._add_query_uid(uid, u.uid)
|
||||||
return u.cookie
|
return u.cookie
|
||||||
@@ -111,12 +243,30 @@ class Genshin(db.Model):
|
|||||||
:param flag:必须使用自己的cookie
|
:param flag:必须使用自己的cookie
|
||||||
"""
|
"""
|
||||||
cookie = await cls._get_user_data(None, uid, "cookie")
|
cookie = await cls._get_user_data(None, uid, "cookie")
|
||||||
print(uid, cookie)
|
|
||||||
if not cookie and not flag:
|
if not cookie and not flag:
|
||||||
cookie = await cls.get_query_cookie(uid)
|
cookie = await cls.get_query_cookie(uid)
|
||||||
print(uid, cookie)
|
|
||||||
return cookie
|
return cookie
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_user_by_qq(cls, user_qq: int) -> Optional["Genshin"]:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
通过qq获取用户对象
|
||||||
|
参数:
|
||||||
|
:param user_qq: qq
|
||||||
|
"""
|
||||||
|
return await cls.query.where(cls.user_qq == user_qq).gino.first()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_user_by_uid(cls, uid: int) -> Optional["Genshin"]:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
通过uid获取用户对象
|
||||||
|
参数:
|
||||||
|
:param uid: qq
|
||||||
|
"""
|
||||||
|
return await cls.query.where(cls.uid == uid).gino.first()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_uid(cls, user_qq: int) -> Optional[int]:
|
async def get_user_uid(cls, user_qq: int) -> Optional[int]:
|
||||||
"""
|
"""
|
||||||
@@ -180,7 +330,7 @@ class Genshin(db.Model):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def _get_user_data(
|
async def _get_user_data(
|
||||||
cls, user_qq: Optional[int], uid: Optional[int], type_: str
|
cls, user_qq: Optional[int], uid: Optional[int], type_: str
|
||||||
) -> Optional[Union[int, str]]:
|
) -> Optional[Union[int, str]]:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
@@ -200,11 +350,10 @@ class Genshin(db.Model):
|
|||||||
return user.mys_id
|
return user.mys_id
|
||||||
elif type_ == "cookie":
|
elif type_ == "cookie":
|
||||||
return user.cookie
|
return user.cookie
|
||||||
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def reset_today_query_uid(cls):
|
async def reset_today_query_uid(cls):
|
||||||
for u in await cls.query.with_for_update().gino.all():
|
for u in await cls.query.with_for_update().gino.all():
|
||||||
if u.today_query_uid:
|
if u.today_query_uid:
|
||||||
await u.update(
|
await u.update(today_query_uid="").apply()
|
||||||
today_query_uid=""
|
|
||||||
).apply()
|
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ from nonebot import on_command
|
|||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from .data_source import get_user_memo
|
from .data_source import get_user_memo, get_memo
|
||||||
from ..models import Genshin
|
from ..models import Genshin
|
||||||
|
from nonebot.plugin import export
|
||||||
|
|
||||||
|
|
||||||
__zx_plugin_name__ = "原神便笺查询"
|
__zx_plugin_name__ = "原神便笺查询"
|
||||||
@@ -25,6 +26,12 @@ __plugin_settings__ = {
|
|||||||
"limit_superuser": False,
|
"limit_superuser": False,
|
||||||
"cmd": ["原神便笺查询"],
|
"cmd": ["原神便笺查询"],
|
||||||
}
|
}
|
||||||
|
__plugin_block_limit__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
export = export()
|
||||||
|
|
||||||
|
export.get_memo = get_memo
|
||||||
|
|
||||||
query_memo_matcher = on_command("原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True)
|
query_memo_matcher = on_command("原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True)
|
||||||
|
|
||||||
@@ -43,7 +50,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
await query_memo_matcher.send(data)
|
await query_memo_matcher.send(data)
|
||||||
logger.info(
|
logger.info(
|
||||||
f"(USER {event.user_id}, "
|
f"(USER {event.user_id}, "
|
||||||
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神便笺查询 uid:{uid}"
|
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
|
||||||
|
f"使用原神便笺查询 uid:{uid}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await query_memo_matcher.send("未查询到数据...")
|
await query_memo_matcher.send("未查询到数据...")
|
||||||
@@ -51,3 +59,4 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ async def _():
|
|||||||
|
|
||||||
async def get_user_memo(user_id: int, uid: int, uname: str) -> Optional[Union[str, MessageSegment]]:
|
async def get_user_memo(user_id: int, uid: int, uname: str) -> Optional[Union[str, MessageSegment]]:
|
||||||
uid = str(uid)
|
uid = str(uid)
|
||||||
if uid[0] == "1" or uid[0] == "2":
|
if uid[0] in ["1", "2"]:
|
||||||
server_id = "cn_gf01"
|
server_id = "cn_gf01"
|
||||||
elif uid[0] == "5":
|
elif uid[0] == "5":
|
||||||
server_id = "cn_qd01"
|
server_id = "cn_qd01"
|
||||||
@@ -55,7 +55,7 @@ async def get_user_memo(user_id: int, uid: int, uname: str) -> Optional[Union[st
|
|||||||
async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
|
async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
|
||||||
try:
|
try:
|
||||||
req = await AsyncHttpx.get(
|
req = await AsyncHttpx.get(
|
||||||
url=f"https://api-takumi.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
|
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
|
||||||
headers={
|
headers={
|
||||||
"DS": get_ds(f"role_id={uid}&server={server_id}"),
|
"DS": get_ds(f"role_id={uid}&server={server_id}"),
|
||||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||||
@@ -72,7 +72,7 @@ async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
|
|||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
return "访问超时,请稍后再试", 997
|
return "访问超时,请稍后再试", 997
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info(f"便签查询获取失败未知错误 {e}:{e}")
|
logger.error(f"便签查询获取失败未知错误 {e}:{e}")
|
||||||
return "发生了一些错误,请稍后再试", 998
|
return "发生了一些错误,请稍后再试", 998
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ __plugin_settings__ = {
|
|||||||
"limit_superuser": False,
|
"limit_superuser": False,
|
||||||
"cmd": ["原神玩家查询"],
|
"cmd": ["原神玩家查询"],
|
||||||
}
|
}
|
||||||
|
__plugin_block_limit__ = {}
|
||||||
|
|
||||||
|
|
||||||
query_role_info_matcher = on_command("原神玩家查询", aliases={"原神玩家查找", "ys"}, priority=5, block=True)
|
query_role_info_matcher = on_command("原神玩家查询", aliases={"原神玩家查找", "ys"}, priority=5, block=True)
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ async def get_image(
|
|||||||
"affix_level": char["weapon"]["affix_level"],
|
"affix_level": char["weapon"]["affix_level"],
|
||||||
}
|
}
|
||||||
|
|
||||||
await init_image(char_data_list, _x)
|
await init_image(world_data_dict, char_data_list, _x, home_data_list)
|
||||||
return await get_genshin_image(
|
return await get_genshin_image(
|
||||||
user_id,
|
user_id,
|
||||||
uid,
|
uid,
|
||||||
@@ -99,7 +99,7 @@ b=body q=query
|
|||||||
async def get_info(uid_: str, server_id: str) -> "Optional[Union[dict, str]], int":
|
async def get_info(uid_: str, server_id: str) -> "Optional[Union[dict, str]], int":
|
||||||
try:
|
try:
|
||||||
req = await AsyncHttpx.get(
|
req = await AsyncHttpx.get(
|
||||||
url=f"https://api-takumi.mihoyo.com/game_record/app/genshin/api/index?server={server_id}&role_id={uid_}",
|
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index?server={server_id}&role_id={uid_}",
|
||||||
headers={
|
headers={
|
||||||
"Accept": "application/json, text/plain, */*",
|
"Accept": "application/json, text/plain, */*",
|
||||||
"DS": get_ds(f"role_id={uid_}&server={server_id}"),
|
"DS": get_ds(f"role_id={uid_}&server={server_id}"),
|
||||||
@@ -204,6 +204,7 @@ def parsed_data(
|
|||||||
"image": world["icon"],
|
"image": world["icon"],
|
||||||
"name": world["name"],
|
"name": world["name"],
|
||||||
"offerings": world["offerings"],
|
"offerings": world["offerings"],
|
||||||
|
"icon": world["icon"]
|
||||||
}
|
}
|
||||||
world_data_dict[world["name"]] = _x
|
world_data_dict[world["name"]] = _x
|
||||||
home_data_list = []
|
home_data_list = []
|
||||||
|
|||||||
@@ -77,42 +77,38 @@ def _get_genshin_image(
|
|||||||
:param nickname: 用户昵称
|
:param nickname: 用户昵称
|
||||||
:param user_ava:用户头像
|
: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)
|
user_image = get_user_data_image(uid, role_data, mys_data, nickname, user_ava)
|
||||||
home_image = get_home_data_image(home_data_list)
|
home_image = get_home_data_image(home_data_list)
|
||||||
country_image = get_country_data_image(world_data_dict)
|
country_image = get_country_data_image(world_data_dict)
|
||||||
char_image, _h = get_char_data_image(char_data_list, char_detailed_dict)
|
char_image = 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 = BuildImage(user_image.w, user_image.h + max([home_image.h, country_image.h]) + 100, color="#F9F6F2")
|
||||||
top_bk.paste(user_image, alpha=True)
|
top_bk.paste(user_image, alpha=True)
|
||||||
top_bk.paste(home_image, (0, user_image.h + 50), 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)
|
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 = BuildImage(1600, 200, font_size=50, color="#F9F6F2", font="HYWenHei-85W.ttf")
|
||||||
bar.text((50, 10), "角色背包", (104, 103, 101))
|
bar.text((50, 10), "角色背包", (104, 103, 101))
|
||||||
bar.line((50, 90, 1550, 90), (227, 219, 209), width=10)
|
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
|
foot = BuildImage(1700, 87, background=image_path / "head.png")
|
||||||
|
head = BuildImage(1700, 87, background=image_path / "head.png")
|
||||||
|
head.rotate(180)
|
||||||
|
middle = BuildImage(
|
||||||
|
1700, top_bk.h + bar.h + char_image.h, 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))
|
||||||
|
if A.h - top_bk.h - bar.h - char_image.h > 200:
|
||||||
|
_h = A.h - top_bk.h - bar.h - char_image.h - 200
|
||||||
A.crop((0, 0, A.w, A.h - _h))
|
A.crop((0, 0, A.w, A.h - _h))
|
||||||
A.paste(foot, (0, A.h - 87))
|
A.paste(foot, (0, A.h - 87))
|
||||||
A.paste(top_bk, (0, 100), center_type="by_width")
|
A.paste(top_bk, (0, 100), center_type="by_width")
|
||||||
A.paste(bar, (50, top_bk.h + 80))
|
A.paste(bar, (50, top_bk.h + 80))
|
||||||
A.paste(char_image, (0, top_bk.h + bar.h + 10), center_type="by_width")
|
A.paste(char_image, (0, top_bk.h + bar.h + 10), center_type="by_width")
|
||||||
rand = random.randint(1, 10000)
|
rand = random.randint(1, 10000)
|
||||||
|
A.resize(0.8)
|
||||||
A.save(Path(IMAGE_PATH) / "temp" / f"genshin_user_card_{rand}.png")
|
A.save(Path(IMAGE_PATH) / "temp" / f"genshin_user_card_{rand}.png")
|
||||||
return image(f"genshin_user_card_{rand}.png", "temp")
|
return image(f"genshin_user_card_{rand}.png", "temp")
|
||||||
|
|
||||||
@@ -233,19 +229,20 @@ def get_home_data_image(home_data_list: List[Dict]) -> BuildImage:
|
|||||||
画出家园数据
|
画出家园数据
|
||||||
:param home_data_list: 家园列表
|
:param home_data_list: 家园列表
|
||||||
"""
|
"""
|
||||||
|
h = 130 + 300 * 4
|
||||||
region = BuildImage(
|
region = BuildImage(
|
||||||
550, 1050, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
550, h, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
region.text(
|
region.text(
|
||||||
(0, 30), f'尘歌壶 Lv.{home_data_list[0]["level"]}', center_type="by_width"
|
(0, 30), f'尘歌壶 Lv.{home_data_list[0]["level"]}', center_type="by_width"
|
||||||
)
|
)
|
||||||
region.text(
|
region.text(
|
||||||
(0, 980), f'仙力: {home_data_list[0]["comfort_num"]}', center_type="by_width"
|
(0, region.h - 70), f'仙力: {home_data_list[0]["comfort_num"]}', center_type="by_width"
|
||||||
)
|
)
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
region.text((0, 30), f"尘歌壶 Lv.0", center_type="by_width")
|
region.text((0, 30), f"尘歌壶 Lv.0", center_type="by_width")
|
||||||
region.text((0, 980), f"仙力: 0", center_type="by_width")
|
region.text((0, region.h - 70), f"仙力: 0", center_type="by_width")
|
||||||
region.circle_corner(30)
|
region.circle_corner(30)
|
||||||
height = 100
|
height = 100
|
||||||
homes = os.listdir(image_path / "homes")
|
homes = os.listdir(image_path / "homes")
|
||||||
@@ -300,9 +297,9 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
|||||||
画出国家探索供奉等图像
|
画出国家探索供奉等图像
|
||||||
:param world_data_dict: 国家数据字典
|
:param world_data_dict: 国家数据字典
|
||||||
"""
|
"""
|
||||||
region = BuildImage(790, 1050, color="#F9F6F2")
|
region = BuildImage(790, 267 * len(world_data_dict), color="#F9F6F2")
|
||||||
height = 0
|
height = 0
|
||||||
for country in ["蒙德", "龙脊雪山", "璃月", "稻妻"]:
|
for country in ["蒙德", "龙脊雪山", "璃月", "稻妻", "渊下宫"]:
|
||||||
x = BuildImage(790, 250, color="#3A4467")
|
x = BuildImage(790, 250, color="#3A4467")
|
||||||
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
|
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
|
||||||
tmp_bk = BuildImage(770, 230, color="#606779")
|
tmp_bk = BuildImage(770, 230, color="#606779")
|
||||||
@@ -356,6 +353,14 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
|||||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
|
elif country in ["渊下宫"]:
|
||||||
|
content_bk.text((300, 0), "探索", fill=(239, 211, 114), center_type="by_height")
|
||||||
|
content_bk.text(
|
||||||
|
(450, 20),
|
||||||
|
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||||
|
fill=(255, 255, 255),
|
||||||
|
center_type="by_height",
|
||||||
|
)
|
||||||
x.paste(tmp_bk, alpha=True, center_type="center")
|
x.paste(tmp_bk, alpha=True, center_type="center")
|
||||||
x.paste(content_bk, alpha=True, center_type="center")
|
x.paste(content_bk, alpha=True, center_type="center")
|
||||||
x.circle_corner(20)
|
x.circle_corner(20)
|
||||||
@@ -372,12 +377,9 @@ def get_char_data_image(
|
|||||||
:param char_data_list: 角色列表
|
:param char_data_list: 角色列表
|
||||||
:param char_detailed_dict: 角色武器
|
:param char_detailed_dict: 角色武器
|
||||||
"""
|
"""
|
||||||
x = 420 if char_detailed_dict else 350
|
lens = len(char_data_list) / 7 if len(char_data_list) % 7 == 0 else len(char_data_list) / 7 + 1
|
||||||
_h = x * int(
|
x = 500
|
||||||
len(char_data_list) / 7
|
_h = int(x * lens)
|
||||||
if len(char_data_list) % 7 == 0
|
|
||||||
else len(char_data_list) / 7 + 1
|
|
||||||
)
|
|
||||||
region = BuildImage(
|
region = BuildImage(
|
||||||
1600,
|
1600,
|
||||||
_h,
|
_h,
|
||||||
@@ -389,12 +391,12 @@ def get_char_data_image(
|
|||||||
for char in char_data_list:
|
for char in char_data_list:
|
||||||
if width + 230 > 1550:
|
if width + 230 > 1550:
|
||||||
width = 120
|
width = 120
|
||||||
height += x
|
height += 420
|
||||||
idx += 1
|
idx += 1
|
||||||
char_img = image_path / "chars" / f'{char["name"]}.png'
|
char_img = image_path / "chars" / f'{char["name"]}.png'
|
||||||
char_bk = BuildImage(
|
char_bk = BuildImage(
|
||||||
270,
|
270,
|
||||||
500 if char_detailed_dict else 400,
|
500,
|
||||||
background=image_path / "element.png",
|
background=image_path / "element.png",
|
||||||
font="HYWenHei-85W.ttf",
|
font="HYWenHei-85W.ttf",
|
||||||
font_size=35,
|
font_size=35,
|
||||||
@@ -507,15 +509,23 @@ def get_char_data_image(
|
|||||||
char_bk.resize(0.8)
|
char_bk.resize(0.8)
|
||||||
region.paste(char_bk, (width, height), True)
|
region.paste(char_bk, (width, height), True)
|
||||||
width += 230
|
width += 230
|
||||||
return region, _h
|
region.crop((0, 0, region.w, height + 430))
|
||||||
|
return region
|
||||||
|
|
||||||
|
|
||||||
async def init_image(char_data_list: List[Dict], char_detailed_dict: dict):
|
async def init_image(world_data_dict: Dict[str, Dict[str, str]], char_data_list: List[Dict[str, str]], char_detailed_dict: dict, home_data_list: List[Dict]):
|
||||||
"""
|
"""
|
||||||
下载头像
|
下载头像
|
||||||
|
:param world_data_dict: 地图标志
|
||||||
:param char_data_list: 角色列表
|
:param char_data_list: 角色列表
|
||||||
:param char_detailed_dict: 角色武器
|
:param char_detailed_dict: 角色武器
|
||||||
|
:param home_data_list: 家园列表
|
||||||
"""
|
"""
|
||||||
|
for world in world_data_dict:
|
||||||
|
file = image_path / "logo" / f'{world_data_dict[world]["name"]}.png'
|
||||||
|
file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
if not file.exists():
|
||||||
|
await AsyncHttpx.download_file(world_data_dict[world]["icon"], file)
|
||||||
for char in char_data_list:
|
for char in char_data_list:
|
||||||
file = image_path / "chars" / f'{char["name"]}.png'
|
file = image_path / "chars" / f'{char["name"]}.png'
|
||||||
file.parent.mkdir(parents=True, exist_ok=True)
|
file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -528,3 +538,10 @@ async def init_image(char_data_list: List[Dict], char_detailed_dict: dict):
|
|||||||
await AsyncHttpx.download_file(
|
await AsyncHttpx.download_file(
|
||||||
char_detailed_dict[char]["weapon_image"], file
|
char_detailed_dict[char]["weapon_image"], file
|
||||||
)
|
)
|
||||||
|
for home in home_data_list:
|
||||||
|
file = image_path / "homes" / f'{home["name"]}.png'
|
||||||
|
file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
if not file.exists():
|
||||||
|
await AsyncHttpx.download_file(
|
||||||
|
home["icon"], file
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
from nonebot import on_command
|
||||||
|
from nonebot.typing import T_State
|
||||||
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||||
|
from apscheduler.jobstores.base import JobLookupError
|
||||||
|
from services.log import logger
|
||||||
|
from .init_task import scheduler, add_job
|
||||||
|
from ..models import Genshin
|
||||||
|
from datetime import datetime
|
||||||
|
import random
|
||||||
|
import asyncio
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
|
||||||
|
__zx_plugin_name__ = "原神树脂提醒"
|
||||||
|
__plugin_usage__ = """
|
||||||
|
usage:
|
||||||
|
即将满树脂的提醒
|
||||||
|
指令:
|
||||||
|
开原神树脂提醒
|
||||||
|
关原神树脂提醒
|
||||||
|
""".strip()
|
||||||
|
__plugin_des__ = "时时刻刻警醒你!"
|
||||||
|
__plugin_cmd__ = ["开原神树脂提醒", "关原神树脂提醒"]
|
||||||
|
__plugin_type__ = ("原神相关",)
|
||||||
|
__plugin_version__ = 0.1
|
||||||
|
__plugin_author__ = "HibiKier"
|
||||||
|
__plugin_settings__ = {
|
||||||
|
"level": 5,
|
||||||
|
"default_status": True,
|
||||||
|
"limit_superuser": False,
|
||||||
|
"cmd": ["原神树脂提醒", "关原神树脂提醒", "开原神树脂提醒"],
|
||||||
|
}
|
||||||
|
|
||||||
|
resin_remind = on_command("开原神树脂提醒", aliases={"关原神树脂提醒"}, priority=5, block=True)
|
||||||
|
|
||||||
|
|
||||||
|
@resin_remind.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 resin_remind.finish("请先绑定uid和cookie!")
|
||||||
|
try:
|
||||||
|
scheduler.remove_job(f"genshin_resin_remind_{uid}_{event.user_id}")
|
||||||
|
except JobLookupError:
|
||||||
|
pass
|
||||||
|
if state["_prefix"]["raw_command"][0] == "开":
|
||||||
|
await Genshin.set_resin_remind(uid, True)
|
||||||
|
add_job(event.user_id, uid)
|
||||||
|
logger.info(
|
||||||
|
f"(USER {event.user_id}, GROUP "
|
||||||
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
|
f" 开启原神体力提醒"
|
||||||
|
)
|
||||||
|
await resin_remind.send("开启原神树脂提醒成功!", at_sender=True)
|
||||||
|
else:
|
||||||
|
await Genshin.set_resin_remind(uid, False)
|
||||||
|
await Genshin.clear_resin_remind_time(uid)
|
||||||
|
logger.info(
|
||||||
|
f"(USER {event.user_id}, GROUP "
|
||||||
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
|
f" 关闭原神体力提醒"
|
||||||
|
)
|
||||||
|
await resin_remind.send("已关闭原神树脂提醒..", at_sender=True)
|
||||||
|
|
||||||
|
|
||||||
|
@scheduler.scheduled_job(
|
||||||
|
"interval",
|
||||||
|
minutes=30,
|
||||||
|
)
|
||||||
|
async def _():
|
||||||
|
for u in await Genshin.get_all_resin_remind_user():
|
||||||
|
if u.resin_recovery_time:
|
||||||
|
if await Genshin.get_user_resin_recovery_time(u.uid) < datetime.now(
|
||||||
|
pytz.timezone("Asia/Shanghai")
|
||||||
|
):
|
||||||
|
await Genshin.clear_resin_remind_time(u.uid)
|
||||||
|
elif (
|
||||||
|
await Genshin.get_user_resin_recovery_time(u.uid)
|
||||||
|
- datetime.now(pytz.timezone("Asia/Shanghai"))
|
||||||
|
).seconds > 360:
|
||||||
|
continue
|
||||||
|
add_job(u.user_qq, u.uid)
|
||||||
|
await asyncio.sleep(random.randint(10, 30))
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
from utils.utils import get_bot, scheduler
|
||||||
|
from utils.message_builder import at
|
||||||
|
from models.group_member_info import GroupInfoUser
|
||||||
|
from apscheduler.jobstores.base import ConflictingIdError
|
||||||
|
from nonebot import Driver
|
||||||
|
from ..models import Genshin
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from services.log import logger
|
||||||
|
from nonebot.plugin import require
|
||||||
|
import time
|
||||||
|
import nonebot
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
|
||||||
|
driver: Driver = nonebot.get_driver()
|
||||||
|
|
||||||
|
|
||||||
|
get_memo = require('query_memo').get_memo
|
||||||
|
|
||||||
|
|
||||||
|
class UserManager:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._data = []
|
||||||
|
|
||||||
|
def append(self, o: str):
|
||||||
|
if o not in self._data:
|
||||||
|
self._data.append(o)
|
||||||
|
|
||||||
|
def remove(self, o: str):
|
||||||
|
if o in self._data:
|
||||||
|
self._data.remove(o)
|
||||||
|
|
||||||
|
def exists(self, o: str):
|
||||||
|
return o in self._data
|
||||||
|
|
||||||
|
|
||||||
|
user_manager = UserManager()
|
||||||
|
|
||||||
|
|
||||||
|
@driver.on_startup
|
||||||
|
async def _():
|
||||||
|
"""
|
||||||
|
启动时分配定时任务
|
||||||
|
"""
|
||||||
|
g_list = await Genshin.get_all_resin_remind_user()
|
||||||
|
for u in g_list:
|
||||||
|
if u.resin_recovery_time and await Genshin.get_user_resin_recovery_time(
|
||||||
|
u.uid
|
||||||
|
) > datetime.now(pytz.timezone("Asia/Shanghai")):
|
||||||
|
date = await Genshin.get_user_resin_recovery_time(u.uid)
|
||||||
|
scheduler.add_job(
|
||||||
|
_remind,
|
||||||
|
"date",
|
||||||
|
run_date=date.replace(microsecond=0),
|
||||||
|
id=f"genshin_resin_remind_{u.uid}_{u.user_qq}",
|
||||||
|
args=[u.user_qq, u.uid],
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
f"genshin_resin_remind add_job:USER:{u.user_qq} UID:{u.uid} "
|
||||||
|
f"{date} 原神树脂提醒"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def add_job(user_id: int, uid: int):
|
||||||
|
date = datetime.now(pytz.timezone("Asia/Shanghai")) + timedelta(seconds=30)
|
||||||
|
try:
|
||||||
|
scheduler.add_job(
|
||||||
|
_remind,
|
||||||
|
"date",
|
||||||
|
run_date=date.replace(microsecond=0),
|
||||||
|
id=f"genshin_resin_remind_{uid}_{user_id}",
|
||||||
|
args=[user_id, uid],
|
||||||
|
)
|
||||||
|
except ConflictingIdError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
async def _remind(user_id: int, uid: str):
|
||||||
|
uid = str(uid)
|
||||||
|
if uid[0] in ["1", "2"]:
|
||||||
|
server_id = "cn_gf01"
|
||||||
|
elif uid[0] == "5":
|
||||||
|
server_id = "cn_qd01"
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
data, code = await get_memo(uid, server_id)
|
||||||
|
if code == 200:
|
||||||
|
current_resin = data["current_resin"] # 当前树脂
|
||||||
|
max_resin = data["max_resin"] # 最大树脂
|
||||||
|
resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间
|
||||||
|
if max_resin - current_resin > 5:
|
||||||
|
user_manager.remove(uid)
|
||||||
|
next_time = datetime.strptime(time.strftime(
|
||||||
|
"%Y-%m-%d %H:%M:%S", time.localtime(time.time() + float(resin_recovery_time))
|
||||||
|
), "%Y-%m-%d %H:%M:%S")
|
||||||
|
await Genshin.set_user_resin_recovery_time(int(uid), next_time)
|
||||||
|
scheduler.add_job(
|
||||||
|
_remind,
|
||||||
|
"date",
|
||||||
|
run_date=next_time,
|
||||||
|
id=f"genshin_resin_remind_{uid}_{user_id}",
|
||||||
|
args=[user_id, uid],
|
||||||
|
)
|
||||||
|
logger.info(f"genshin_resin_remind add_job:{next_time.replace(microsecond=0)} 原神树脂提醒")
|
||||||
|
else:
|
||||||
|
if not user_manager.exists(uid):
|
||||||
|
user_manager.append(uid)
|
||||||
|
bot = get_bot()
|
||||||
|
if bot:
|
||||||
|
if user_id in [x["user_id"] for x in await bot.get_friend_list()]:
|
||||||
|
await bot.send_private_msg(
|
||||||
|
user_id=user_id,
|
||||||
|
message=f"树脂已经 {current_resin} 个啦" f",马上就要溢出了!快快刷掉刷掉!",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
group_list = await GroupInfoUser.get_user_all_group(user_id)
|
||||||
|
if group_list:
|
||||||
|
await bot.send_group_msg(
|
||||||
|
group_id=group_list[0],
|
||||||
|
message=at(user_id) + f"树脂已经 {current_resin} 个啦"
|
||||||
|
f",马上就要溢出了!快快刷掉刷掉!",
|
||||||
|
)
|
||||||
@@ -3,6 +3,7 @@ import json
|
|||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import string
|
||||||
|
|
||||||
|
|
||||||
def _md5(text):
|
def _md5(text):
|
||||||
@@ -11,7 +12,15 @@ def _md5(text):
|
|||||||
return md5.hexdigest()
|
return md5.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def get_ds(q: str = "", b: dict = None):
|
def get_old_ds() -> str:
|
||||||
|
n = Config.get_config("genshin", "n")
|
||||||
|
i = str(int(time.time()))
|
||||||
|
r = ''.join(random.sample(string.ascii_lowercase + string.digits, 6))
|
||||||
|
c = _md5("salt=" + n + "&t=" + i + "&r=" + r)
|
||||||
|
return i + "," + r + "," + c
|
||||||
|
|
||||||
|
|
||||||
|
def get_ds(q: str = "", b: dict = None) -> str:
|
||||||
if b:
|
if b:
|
||||||
br = json.dumps(b)
|
br = json.dumps(b)
|
||||||
else:
|
else:
|
||||||
@@ -23,6 +32,13 @@ def get_ds(q: str = "", b: dict = None):
|
|||||||
return t + "," + r + "," + c
|
return t + "," + r + "," + c
|
||||||
|
|
||||||
|
|
||||||
|
def random_hex(length: int) -> str:
|
||||||
|
result = hex(random.randint(0, 16 ** length)).replace("0x", "").upper()
|
||||||
|
if len(result) < length:
|
||||||
|
result = "0" * (length - len(result)) + result
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
element_mastery = {
|
element_mastery = {
|
||||||
"anemo": "风",
|
"anemo": "风",
|
||||||
"pyro": "火",
|
"pyro": "火",
|
||||||
|
|||||||
@@ -41,8 +41,19 @@ usage:
|
|||||||
示例:塞红包 1000
|
示例:塞红包 1000
|
||||||
示例:塞红包 1000 10
|
示例:塞红包 1000 10
|
||||||
""".strip()
|
""".strip()
|
||||||
|
__plugin_superuser_usage__ = """
|
||||||
|
usage:
|
||||||
|
节日全群红包指令
|
||||||
|
指令:
|
||||||
|
节日红包 [金额] [数量] ?[祝福语] ?[指定群]
|
||||||
|
""".strip()
|
||||||
__plugin_des__ = "运气项目又来了"
|
__plugin_des__ = "运气项目又来了"
|
||||||
__plugin_cmd__ = ["塞红包 [金币数] ?[红包数=5]", "开/抢", "退回"]
|
__plugin_cmd__ = [
|
||||||
|
"塞红包 [金币数] ?[红包数=5]",
|
||||||
|
"开/抢",
|
||||||
|
"退回",
|
||||||
|
"节日红包 [金额] [数量] ?[祝福语] ?[指定群] [_superuser]",
|
||||||
|
]
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier"
|
||||||
__plugin_settings__ = {
|
__plugin_settings__ = {
|
||||||
@@ -51,9 +62,7 @@ __plugin_settings__ = {
|
|||||||
"limit_superuser": False,
|
"limit_superuser": False,
|
||||||
"cmd": ["金币红包", "塞红包"],
|
"cmd": ["金币红包", "塞红包"],
|
||||||
}
|
}
|
||||||
__plugin_resources__ = {
|
__plugin_resources__ = {"prts": IMAGE_PATH}
|
||||||
"prts": IMAGE_PATH
|
|
||||||
}
|
|
||||||
|
|
||||||
gold_redbag = on_command(
|
gold_redbag = on_command(
|
||||||
"塞红包", aliases={"金币红包"}, priority=5, block=True, permission=GROUP
|
"塞红包", aliases={"金币红包"}, priority=5, block=True, permission=GROUP
|
||||||
@@ -143,10 +152,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
flag, amount = await check_gold(event.user_id, event.group_id, amount)
|
flag, amount = await check_gold(event.user_id, event.group_id, amount)
|
||||||
if not flag:
|
if not flag:
|
||||||
await gold_redbag.finish(amount, at_sender=True)
|
await gold_redbag.finish(amount, at_sender=True)
|
||||||
group_member_num = (await bot.get_group_info(group_id=event.group_id))['member_count']
|
group_member_num = (await bot.get_group_info(group_id=event.group_id))[
|
||||||
|
"member_count"
|
||||||
|
]
|
||||||
num = int(num)
|
num = int(num)
|
||||||
if num > group_member_num:
|
if num > group_member_num:
|
||||||
await gold_redbag.send('你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...')
|
await gold_redbag.send("你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...")
|
||||||
num = group_member_num
|
num = group_member_num
|
||||||
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
||||||
flag, result = init_redbag(
|
flag, result = init_redbag(
|
||||||
@@ -181,7 +192,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
.replace("。", "")
|
.replace("。", "")
|
||||||
)
|
)
|
||||||
if msg:
|
if msg:
|
||||||
if '红包' not in msg:
|
if "红包" not in msg:
|
||||||
return
|
return
|
||||||
flag1 = True
|
flag1 = True
|
||||||
flag2 = True
|
flag2 = True
|
||||||
@@ -306,11 +317,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
await end_festive_redbag(bot, g)
|
await end_festive_redbag(bot, g)
|
||||||
except JobLookupError:
|
except JobLookupError:
|
||||||
pass
|
pass
|
||||||
init_redbag(int(bot.self_id), g, f"{NICKNAME}", amount, num, int(bot.self_id), 1)
|
init_redbag(
|
||||||
|
int(bot.self_id), g, f"{NICKNAME}", amount, num, int(bot.self_id), 1
|
||||||
|
)
|
||||||
scheduler.add_job(
|
scheduler.add_job(
|
||||||
end_festive_redbag,
|
end_festive_redbag,
|
||||||
"date",
|
"date",
|
||||||
run_date=str(datetime.now() + timedelta(hours=24)).split(".")[0],
|
run_date=(datetime.now() + timedelta(hours=24)).replace(microsecond=0),
|
||||||
id=f"festive_redbag_{g}",
|
id=f"festive_redbag_{g}",
|
||||||
args=[bot, g],
|
args=[bot, g],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from nonebot import on_command, on_keyword, on_regex
|
from nonebot import on_message, on_keyword, on_regex
|
||||||
from configs.path_config import IMAGE_PATH
|
from configs.path_config import IMAGE_PATH
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from utils.utils import get_message_text, is_number
|
from utils.utils import get_message_text, is_number
|
||||||
@@ -9,6 +9,7 @@ from utils.utils import FreqLimiter, cn2py
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from utils.manager import group_manager, withdraw_message_manager
|
from utils.manager import group_manager, withdraw_message_manager
|
||||||
|
from .rule import rule
|
||||||
import random
|
import random
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ except ModuleNotFoundError:
|
|||||||
__zx_plugin_name__ = "本地图库"
|
__zx_plugin_name__ = "本地图库"
|
||||||
__plugin_usage__ = f"""
|
__plugin_usage__ = f"""
|
||||||
usage:
|
usage:
|
||||||
发送指定图库下的随机或指定id图片
|
发送指定图库下的随机或指定id图片genshin_memo
|
||||||
指令:
|
指令:
|
||||||
{Config.get_config("image_management", "IMAGE_DIR_LIST")} ?[id]
|
{Config.get_config("image_management", "IMAGE_DIR_LIST")} ?[id]
|
||||||
示例:美图
|
示例:美图
|
||||||
@@ -50,9 +51,8 @@ Config.add_plugin_config(
|
|||||||
|
|
||||||
_flmt = FreqLimiter(1)
|
_flmt = FreqLimiter(1)
|
||||||
|
|
||||||
cmd = set(Config.get_config("image_management", "IMAGE_DIR_LIST"))
|
|
||||||
|
|
||||||
send_img = on_command("img", aliases=cmd, priority=5, block=True)
|
send_img = on_message(priority=5, rule=rule, block=True)
|
||||||
pa = on_keyword({"丢人爬", "爪巴"}, priority=5, block=True)
|
pa = on_keyword({"丢人爬", "爪巴"}, priority=5, block=True)
|
||||||
pa_reg = on_regex("^爬$", priority=5, block=True)
|
pa_reg = on_regex("^爬$", priority=5, block=True)
|
||||||
|
|
||||||
@@ -62,18 +62,24 @@ _path = Path(IMAGE_PATH) / "image_management"
|
|||||||
|
|
||||||
@send_img.handle()
|
@send_img.handle()
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
img_id = get_message_text(event.json())
|
msg = get_message_text(event.json()).split()
|
||||||
path = _path / cn2py(state["_prefix"]["raw_command"])
|
gallery = msg[0]
|
||||||
if state["_prefix"]["raw_command"] in Config.get_config(
|
if gallery not in Config.get_config("image_management", "IMAGE_DIR_LIST"):
|
||||||
|
return
|
||||||
|
img_id = None
|
||||||
|
if len(msg) > 1:
|
||||||
|
img_id = msg[1]
|
||||||
|
path = _path / cn2py(gallery)
|
||||||
|
if gallery in Config.get_config(
|
||||||
"image_management", "IMAGE_DIR_LIST"
|
"image_management", "IMAGE_DIR_LIST"
|
||||||
):
|
):
|
||||||
if not path.exists() and (path.parent.parent / cn2py(state["_prefix"]["raw_command"])).exists():
|
if not path.exists() and (path.parent.parent / cn2py(gallery)).exists():
|
||||||
path = Path(IMAGE_PATH) / cn2py(state["_prefix"]["raw_command"])
|
path = Path(IMAGE_PATH) / cn2py(gallery)
|
||||||
else:
|
else:
|
||||||
path.mkdir(parents=True, exist_ok=True)
|
path.mkdir(parents=True, exist_ok=True)
|
||||||
length = len(os.listdir(path))
|
length = len(os.listdir(path))
|
||||||
if length == 0:
|
if length == 0:
|
||||||
logger.warning(f'图库 {cn2py(state["_prefix"]["raw_command"])} 为空,调用取消!')
|
logger.warning(f'图库 {cn2py(gallery)} 为空,调用取消!')
|
||||||
await send_img.finish("该图库中没有图片噢")
|
await send_img.finish("该图库中没有图片噢")
|
||||||
index = img_id if img_id else str(random.randint(0, length - 1))
|
index = img_id if img_id else str(random.randint(0, length - 1))
|
||||||
if not is_number(index):
|
if not is_number(index):
|
||||||
@@ -85,7 +91,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
logger.info(
|
logger.info(
|
||||||
f"(USER {event.user_id}, GROUP "
|
f"(USER {event.user_id}, GROUP "
|
||||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
|
||||||
f"发送{cn2py(state['_prefix']['raw_command'])}:"
|
f"发送{cn2py(gallery)}:"
|
||||||
+ result
|
+ result
|
||||||
)
|
)
|
||||||
msg_id = await send_img.send(
|
msg_id = await send_img.send(
|
||||||
@@ -102,7 +108,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
logger.info(
|
logger.info(
|
||||||
f"(USER {event.user_id}, GROUP "
|
f"(USER {event.user_id}, GROUP "
|
||||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
|
||||||
f"发送 {cn2py(state['_prefix']['raw_command'])} 失败"
|
f"发送 {cn2py(gallery)} 失败"
|
||||||
)
|
)
|
||||||
await send_img.finish(f"不想给你看Ov|")
|
await send_img.finish(f"不想给你看Ov|")
|
||||||
|
|
||||||
@@ -135,4 +141,4 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
return
|
return
|
||||||
if _flmt.check(event.user_id):
|
if _flmt.check(event.user_id):
|
||||||
_flmt.start_cd(event.user_id)
|
_flmt.start_cd(event.user_id)
|
||||||
await pa.finish(image(random.choice(os.listdir(IMAGE_PATH + "pa")), "pa"))
|
await pa_reg.finish(image(random.choice(os.listdir(IMAGE_PATH + "pa")), "pa"))
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
from nonebot.adapters.cqhttp import Bot, Event
|
||||||
|
from nonebot.typing import T_State
|
||||||
|
from utils.utils import get_message_text
|
||||||
|
from configs.config import Config
|
||||||
|
|
||||||
|
|
||||||
|
def rule(bot: Bot, event: Event, state: T_State) -> bool:
|
||||||
|
"""
|
||||||
|
检测文本是否是关闭功能命令
|
||||||
|
:param bot: pass
|
||||||
|
:param event: pass
|
||||||
|
:param state: pass
|
||||||
|
"""
|
||||||
|
msg = get_message_text(event.json())
|
||||||
|
for x in Config.get_config("image_management", "IMAGE_DIR_LIST"):
|
||||||
|
if msg.startswith(x):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
@@ -3,7 +3,7 @@ from nonebot.rule import to_me
|
|||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from utils.utils import get_message_imgs, get_message_text
|
from utils.utils import get_message_img, get_message_text
|
||||||
from .data_source import upload_image_to_local
|
from .data_source import upload_image_to_local
|
||||||
|
|
||||||
|
|
||||||
@@ -49,15 +49,15 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
await upload_img.reject("此目录不正确,请重新输入目录!")
|
await upload_img.reject("此目录不正确,请重新输入目录!")
|
||||||
state["path"] = msg
|
state["path"] = msg
|
||||||
if state["_current_key"] in ["imgs"]:
|
if state["_current_key"] in ["imgs"]:
|
||||||
if not get_message_imgs(event.json()):
|
if not get_message_img(event.json()):
|
||||||
await upload_img.reject("图呢图呢图呢图呢!GKD!")
|
await upload_img.reject("图呢图呢图呢图呢!GKD!")
|
||||||
state["imgs"] = get_message_imgs(event.json())
|
state["imgs"] = get_message_img(event.json())
|
||||||
|
|
||||||
|
|
||||||
@upload_img.handle()
|
@upload_img.handle()
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
raw_arg = get_message_text(event.json())
|
raw_arg = get_message_text(event.json())
|
||||||
img_list = get_message_imgs(event.json())
|
img_list = get_message_img(event.json())
|
||||||
if raw_arg:
|
if raw_arg:
|
||||||
if raw_arg in Config.get_config("image_management", "IMAGE_DIR_LIST"):
|
if raw_arg in Config.get_config("image_management", "IMAGE_DIR_LIST"):
|
||||||
state["path"] = raw_arg
|
state["path"] = raw_arg
|
||||||
@@ -92,7 +92,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
state[state["_current_key"]] = str(event.get_message())
|
state[state["_current_key"]] = str(event.get_message())
|
||||||
else:
|
else:
|
||||||
if get_message_text(event.json()) not in ["stop"]:
|
if get_message_text(event.json()) not in ["stop"]:
|
||||||
img = get_message_imgs(event.json())
|
img = get_message_img(event.json())
|
||||||
if img:
|
if img:
|
||||||
state["tmp"].extend(img)
|
state["tmp"].extend(img)
|
||||||
await continuous_upload_img.reject("图再来!!")
|
await continuous_upload_img.reject("图再来!!")
|
||||||
@@ -102,10 +102,10 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
|
|
||||||
@continuous_upload_img.handle()
|
@continuous_upload_img.handle()
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
path = get_message_imgs(event.json())
|
path = get_message_img(event.json())
|
||||||
if path in Config.get_config("image_management", "IMAGE_DIR_LIST"):
|
if path in Config.get_config("image_management", "IMAGE_DIR_LIST"):
|
||||||
state["path"] = path
|
state["path"] = path
|
||||||
await continuous_upload_img.send("图来!!")
|
await continuous_upload_img.send("图来!!【停止请发送 ‘stop’ 开始上传】")
|
||||||
state["tmp"] = []
|
state["tmp"] = []
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
from nonebot import on_message, on_command
|
from nonebot import on_message, on_command
|
||||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||||
from nonebot.adapters.cqhttp.permission import GROUP
|
from nonebot.adapters.cqhttp.permission import GROUP
|
||||||
from utils.utils import get_message_text, is_number, get_message_imgs
|
from utils.utils import get_message_text, is_number, get_message_img
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||||
from configs.path_config import DATA_PATH, TEMP_PATH
|
from configs.path_config import DATA_PATH, TEMP_PATH
|
||||||
@@ -87,7 +87,7 @@ mute_data = get_data()
|
|||||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||||
group_id = str(event.group_id)
|
group_id = str(event.group_id)
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
imgs = get_message_imgs(event.json())
|
imgs = get_message_img(event.json())
|
||||||
img_hash = ""
|
img_hash = ""
|
||||||
for img in imgs:
|
for img in imgs:
|
||||||
img_hash += await download_img_and_hash(img, event.group_id)
|
img_hash += await download_img_and_hash(img, event.group_id)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from nonebot.plugin import on_command, on_message
|
|||||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from utils.utils import get_message_text, get_message_imgs
|
from utils.utils import get_message_text, get_message_img
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from nonebot.rule import to_me
|
from nonebot.rule import to_me
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ setu = on_command("识图", aliases={"search"}, block=True, priority=5)
|
|||||||
@setu.handle()
|
@setu.handle()
|
||||||
async def handle_first_receive(bot: Bot, event: MessageEvent, state: T_State):
|
async def handle_first_receive(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
imgs = get_message_imgs(event.json())
|
imgs = get_message_img(event.json())
|
||||||
if imgs:
|
if imgs:
|
||||||
state["setu"] = imgs[0]
|
state["setu"] = imgs[0]
|
||||||
if msg:
|
if msg:
|
||||||
@@ -87,7 +87,7 @@ async def handle_first_receive(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
|
|
||||||
@setu.args_parser
|
@setu.args_parser
|
||||||
async def get_setu(bot: Bot, event: MessageEvent, state: T_State):
|
async def get_setu(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
imgs = get_message_imgs(event.json())
|
imgs = get_message_img(event.json())
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
if not imgs:
|
if not imgs:
|
||||||
await setu.reject()
|
await setu.reject()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class OpenCasesUser(db.Model):
|
|||||||
|
|
||||||
id = db.Column(db.Integer(), primary_key=True)
|
id = db.Column(db.Integer(), primary_key=True)
|
||||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||||
belonging_group = db.Column(db.BigInteger(), nullable=False)
|
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||||
total_count = db.Column(db.Integer(), nullable=False, default=0)
|
total_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||||
blue_count = db.Column(db.Integer(), nullable=False, default=0)
|
blue_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||||
blue_st_count = db.Column(db.Integer(), nullable=False, default=0)
|
blue_st_count = db.Column(db.Integer(), nullable=False, default=0)
|
||||||
@@ -27,19 +27,19 @@ class OpenCasesUser(db.Model):
|
|||||||
open_cases_time_last = db.Column(db.DateTime(timezone=True), nullable=False, default=datetime.now())
|
open_cases_time_last = db.Column(db.DateTime(timezone=True), nullable=False, default=datetime.now())
|
||||||
knifes_name = db.Column(db.Unicode(), nullable=False, default="")
|
knifes_name = db.Column(db.Unicode(), nullable=False, default="")
|
||||||
|
|
||||||
_idx1 = db.Index('open_cases_group_users_idx1', 'user_qq', 'belonging_group', unique=True)
|
_idx1 = db.Index('open_cases_group_users_idx1', 'user_qq', 'group_id', unique=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def ensure(cls, user_qq: int, belonging_group: int, for_update: bool = False) -> 'OpenCasesUser':
|
async def ensure(cls, user_qq: int, group_id: int, for_update: bool = False) -> 'OpenCasesUser':
|
||||||
query = cls.query.where(
|
query = cls.query.where(
|
||||||
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
|
(cls.user_qq == user_qq) & (cls.group_id == group_id)
|
||||||
)
|
)
|
||||||
if for_update:
|
if for_update:
|
||||||
query = query.with_for_update()
|
query = query.with_for_update()
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
return user or await cls.create(
|
return user or await cls.create(
|
||||||
user_qq=user_qq,
|
user_qq=user_qq,
|
||||||
belonging_group=belonging_group,
|
group_id=group_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -49,7 +49,7 @@ class OpenCasesUser(db.Model):
|
|||||||
query = await cls.query.gino.all()
|
query = await cls.query.gino.all()
|
||||||
else:
|
else:
|
||||||
query = await cls.query.where(
|
query = await cls.query.where(
|
||||||
(cls.belonging_group == group_id)
|
(cls.group_id == group_id)
|
||||||
).gino.all()
|
).gino.all()
|
||||||
for user in query:
|
for user in query:
|
||||||
user_list.append(user)
|
user_list.append(user)
|
||||||
|
|||||||
@@ -124,6 +124,27 @@ class Setu(db.Model):
|
|||||||
).gino.first()
|
).gino.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def delete_image(cls, pid: int) -> int:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
删除图片并替换
|
||||||
|
参数:
|
||||||
|
:param pid: 图片pid
|
||||||
|
"""
|
||||||
|
query = await cls.query.where(cls.pid == pid).gino.first()
|
||||||
|
if query:
|
||||||
|
is_r18 = query.is_r18
|
||||||
|
num = await cls.get_image_count(is_r18)
|
||||||
|
x = await cls.query.where((cls.is_r18 == is_r18) & (cls.local_id == num - 1)).gino.first()
|
||||||
|
_tmp_local_id = x.local_id
|
||||||
|
if x:
|
||||||
|
x.update(local_id=query.local_id).apply()
|
||||||
|
await cls.delete.where(cls.pid == pid).gino.status()
|
||||||
|
return _tmp_local_id
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def update_setu_data(
|
async def update_setu_data(
|
||||||
cls,
|
cls,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from gino.exceptions import UninitializedError
|
|||||||
from utils.utils import (
|
from utils.utils import (
|
||||||
is_number,
|
is_number,
|
||||||
get_message_text,
|
get_message_text,
|
||||||
get_message_imgs,
|
get_message_img,
|
||||||
)
|
)
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp import (
|
from nonebot.adapters.cqhttp import (
|
||||||
@@ -243,7 +243,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
if str(event.message) == "取消":
|
if str(event.message) == "取消":
|
||||||
await find_setu.finish("取消了操作", at_sender=True)
|
await find_setu.finish("取消了操作", at_sender=True)
|
||||||
imgs = get_message_imgs(event.json())
|
imgs = get_message_img(event.json())
|
||||||
if not imgs:
|
if not imgs:
|
||||||
await find_setu.reject("不搞错了,俺要图!")
|
await find_setu.reject("不搞错了,俺要图!")
|
||||||
state["img"] = imgs[0]
|
state["img"] = imgs[0]
|
||||||
@@ -253,7 +253,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
if get_message_text(event.json()) in ["帮助"]:
|
if get_message_text(event.json()) in ["帮助"]:
|
||||||
await find_setu.finish("通过图片获取本地色图id\n\t示例:查色图(图片)")
|
await find_setu.finish("通过图片获取本地色图id\n\t示例:查色图(图片)")
|
||||||
imgs = get_message_imgs(event.json())
|
imgs = get_message_img(event.json())
|
||||||
if imgs:
|
if imgs:
|
||||||
state["img"] = imgs[0]
|
state["img"] = imgs[0]
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ update_setu = on_command(
|
|||||||
async def _(bot: Bot, event: Event, state: T_State):
|
async def _(bot: Bot, event: Event, state: T_State):
|
||||||
if Config.get_config("send_setu", "DOWNLOAD_SETU"):
|
if Config.get_config("send_setu", "DOWNLOAD_SETU"):
|
||||||
await update_setu.send("开始更新色图...", at_sender=True)
|
await update_setu.send("开始更新色图...", at_sender=True)
|
||||||
await update_setu.send(await update_setu_img(), at_sender=True)
|
await update_setu_img(True)
|
||||||
else:
|
else:
|
||||||
await update_setu.finish("更新色图配置未开启")
|
await update_setu.finish("更新色图配置未开启")
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from services.log import logger
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from utils.image_utils import compressed_image, get_img_hash
|
from utils.image_utils import compressed_image, get_img_hash
|
||||||
from utils.utils import get_bot
|
from utils.utils import get_bot
|
||||||
from asyncio.exceptions import TimeoutError
|
from PIL import UnidentifiedImageError
|
||||||
from ..model import Setu
|
from ..model import Setu
|
||||||
from asyncpg.exceptions import UniqueViolationError
|
from asyncpg.exceptions import UniqueViolationError
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
@@ -90,7 +90,11 @@ headers = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def update_setu_img():
|
async def update_setu_img(flag: bool = False):
|
||||||
|
"""
|
||||||
|
更新色图
|
||||||
|
:param flag: 是否手动更新
|
||||||
|
"""
|
||||||
image_list = await Setu.get_all_setu()
|
image_list = await Setu.get_all_setu()
|
||||||
image_list.reverse()
|
image_list.reverse()
|
||||||
_success = 0
|
_success = 0
|
||||||
@@ -105,6 +109,9 @@ async def update_setu_img():
|
|||||||
path.mkdir(exist_ok=True, parents=True)
|
path.mkdir(exist_ok=True, parents=True)
|
||||||
rar_path.mkdir(exist_ok=True, parents=True)
|
rar_path.mkdir(exist_ok=True, parents=True)
|
||||||
if not local_image.exists() or not image.img_hash:
|
if not local_image.exists() or not image.img_hash:
|
||||||
|
temp_file = rar_path / f"{image.local_id}.jpg"
|
||||||
|
if temp_file.exists():
|
||||||
|
temp_file.unlink()
|
||||||
url_ = image.img_url
|
url_ = image.img_url
|
||||||
ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
|
ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
|
||||||
if ws_url:
|
if ws_url:
|
||||||
@@ -142,6 +149,14 @@ async def update_setu_img():
|
|||||||
continue
|
continue
|
||||||
img_hash = str(get_img_hash(f"{path}/{image.local_id}.jpg"))
|
img_hash = str(get_img_hash(f"{path}/{image.local_id}.jpg"))
|
||||||
await Setu.update_setu_data(image.pid, img_hash=img_hash)
|
await Setu.update_setu_data(image.pid, img_hash=img_hash)
|
||||||
|
except UnidentifiedImageError:
|
||||||
|
# 图片已删除
|
||||||
|
with open(local_image, 'r') as f:
|
||||||
|
if '404 Not Found' in f.read():
|
||||||
|
max_num = await Setu.delete_image(image.pid)
|
||||||
|
local_image.unlink()
|
||||||
|
os.rename(path / f"{max_num}.jpg", local_image)
|
||||||
|
logger.warning(f"更新色图 PID:{image.pid} 404,已删除并替换")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_success -= 1
|
_success -= 1
|
||||||
logger.error(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}")
|
logger.error(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}")
|
||||||
@@ -150,8 +165,7 @@ async def update_setu_img():
|
|||||||
error_info.append(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}")
|
error_info.append(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}")
|
||||||
else:
|
else:
|
||||||
logger.info(f"更新色图 {image.local_id}.jpg 已存在")
|
logger.info(f"更新色图 {image.local_id}.jpg 已存在")
|
||||||
error_info = ["无报错.."] if not error_info else error_info
|
if _success or error_info or flag:
|
||||||
if count or _success or error_info:
|
|
||||||
await get_bot().send_private_msg(
|
await get_bot().send_private_msg(
|
||||||
user_id=int(list(get_bot().config.superusers)[0]),
|
user_id=int(list(get_bot().config.superusers)[0]),
|
||||||
message=f'{str(datetime.now()).split(".")[0]} 更新 色图 完成,本地存在 {count} 张,实际更新 {_success} 张,'
|
message=f'{str(datetime.now()).split(".")[0]} 更新 色图 完成,本地存在 {count} 张,实际更新 {_success} 张,'
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
from nonebot import on_command
|
||||||
|
from nonebot.adapters.cqhttp import Bot, PrivateMessageEvent, GroupMessageEvent
|
||||||
|
from nonebot.typing import T_State
|
||||||
|
from nonebot.rule import to_me
|
||||||
|
|
||||||
|
__zx_plugin_name__ = "服务器 [Hidden]"
|
||||||
|
__plugin_version__ = 0.1
|
||||||
|
__plugin_author__ = "HibiKier"
|
||||||
|
|
||||||
|
|
||||||
|
server_ip = on_command("服务器", aliases={"ip"}, rule=to_me(), priority=5, block=True)
|
||||||
|
|
||||||
|
|
||||||
|
@server_ip.handle()
|
||||||
|
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||||
|
await server_ip.finish(
|
||||||
|
"|* 请不要发给其他人! *|\n"
|
||||||
|
"\t121.40.195.22\n"
|
||||||
|
"|* 请不要发给其他人! *|\n"
|
||||||
|
"csgo ~号键控制台输入 connect 121.40.195.22 进入服务器\n"
|
||||||
|
"然后再公屏输入 !diy 来使用皮肤(英文感叹号,注意)\n"
|
||||||
|
"【说不定可以凑到内战噢,欢迎~{娱乐为主}】",
|
||||||
|
at_sender=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@server_ip.handle()
|
||||||
|
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||||
|
if event.group_id == 698279647:
|
||||||
|
await server_ip.finish(
|
||||||
|
"嗨呀!当前服务器地址是:" "\n\tay: 121.40.195.22" "\n\t夜之北枭: 101.132.170.254"
|
||||||
|
)
|
||||||
|
elif event.group_id == 1046451860:
|
||||||
|
await server_ip.finish("嗨呀!当前服务器地址是:\n121.40.195.22\n !diy")
|
||||||
|
else:
|
||||||
|
await server_ip.finish("不好意思呀,小真寻不能为你使用此功能,因为服务器IP是真寻的小秘密呀!", at_sender=True)
|
||||||
@@ -1 +0,0 @@
|
|||||||
from .goods_info import *
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
from nonebot import on_command
|
|
||||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
|
||||||
from nonebot.typing import T_State
|
|
||||||
from configs.path_config import IMAGE_PATH
|
|
||||||
from utils.message_builder import image
|
|
||||||
from .data_source import create_shop_help, add_goods, del_goods, update_goods
|
|
||||||
from nonebot.permission import SUPERUSER
|
|
||||||
from utils.utils import get_message_text, is_number
|
|
||||||
from services.log import logger
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
__zx_plugin_name__ = "商店"
|
|
||||||
__plugin_usage__ = """
|
|
||||||
usage:
|
|
||||||
商店项目,这可不是奸商
|
|
||||||
指令:
|
|
||||||
商店
|
|
||||||
""".strip()
|
|
||||||
__plugin_superuser_usage__ = """
|
|
||||||
usage:
|
|
||||||
商品操作
|
|
||||||
指令:
|
|
||||||
添加商品 [名称]-[价格]-[描述]-?[折扣](小数)-?[限时时间](分钟)
|
|
||||||
删除商品 [名称或序号]
|
|
||||||
修改商品 -name [名称或序号] -price [价格] -des [描述] -discount [折扣] -time [限时]
|
|
||||||
示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60
|
|
||||||
示例:删除商品 2
|
|
||||||
示例:修改商品 -name 1 -price 900: 修改序号为1的商品的价格为900
|
|
||||||
* 修改商品只需添加需要值即可 *
|
|
||||||
""".strip()
|
|
||||||
__plugin_des__ = "商店系统[金币回收计划]"
|
|
||||||
__plugin_cmd__ = [
|
|
||||||
"商店",
|
|
||||||
"添加商品 [名称]-[价格]-[描述]-?[折扣](小数)-?[限时时间](分钟) [_superuser]",
|
|
||||||
"删除商品 [名称或序号] [_superuser]",
|
|
||||||
"修改商品 -name [名称或序号] -price [价格] -des [描述] -discount [折扣] -time [限时] [_superuser]",
|
|
||||||
]
|
|
||||||
__plugin_type__ = ('商店',)
|
|
||||||
__plugin_version__ = 0.1
|
|
||||||
__plugin_author__ = "HibiKier"
|
|
||||||
__plugin_settings__ = {
|
|
||||||
"level": 5,
|
|
||||||
"default_status": True,
|
|
||||||
"limit_superuser": False,
|
|
||||||
"cmd": ["商店"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
shop_help = on_command("商店", priority=5, block=True)
|
|
||||||
|
|
||||||
shop_add_goods = on_command("添加商品", priority=5, permission=SUPERUSER, block=True)
|
|
||||||
|
|
||||||
shop_del_goods = on_command("删除商品", priority=5, permission=SUPERUSER, block=True)
|
|
||||||
|
|
||||||
shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER, block=True)
|
|
||||||
|
|
||||||
|
|
||||||
@shop_help.handle()
|
|
||||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|
||||||
if not os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
|
||||||
await create_shop_help()
|
|
||||||
await shop_help.send(image("shop_help.png"))
|
|
||||||
|
|
||||||
|
|
||||||
@shop_add_goods.handle()
|
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|
||||||
msg = get_message_text(event.json())
|
|
||||||
if msg:
|
|
||||||
msg = msg.split("-")
|
|
||||||
if len(msg) < 3:
|
|
||||||
await shop_add_goods.finish("商品参数不完全...", at_sender=True)
|
|
||||||
if not is_number(msg[1]):
|
|
||||||
await shop_add_goods.finish("商品的价格必须是合法数字!", at_sender=True)
|
|
||||||
msg[1] = int(msg[1])
|
|
||||||
if len(msg) > 3:
|
|
||||||
if not is_number(msg[3]):
|
|
||||||
await shop_add_goods.finish("商品的折扣要小数啊!", at_sender=True)
|
|
||||||
msg[3] = float(msg[3])
|
|
||||||
if len(msg) > 4:
|
|
||||||
if not is_number(msg[4]):
|
|
||||||
await shop_add_goods.finish("商品的限时时间是要写多少分钟噢!", at_sender=True)
|
|
||||||
msg[4] = time.time() + int(msg[4]) * 60
|
|
||||||
if await add_goods(msg):
|
|
||||||
await shop_add_goods.send(f"添加商品 {msg[0]} 成功...", at_sender=True)
|
|
||||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
|
||||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
|
||||||
logger.info(f"USER {event.user_id} 上传商品 {msg} 成功")
|
|
||||||
else:
|
|
||||||
await shop_add_goods.send(f"添加商品 {msg[0]} 失败了...", at_sender=True)
|
|
||||||
logger.warning(f"USER {event.user_id} 上传商品 {msg} 失败")
|
|
||||||
|
|
||||||
|
|
||||||
@shop_del_goods.handle()
|
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|
||||||
msg = get_message_text(event.json())
|
|
||||||
if msg:
|
|
||||||
name = ""
|
|
||||||
id_ = 0
|
|
||||||
if is_number(msg):
|
|
||||||
id_ = int(msg)
|
|
||||||
else:
|
|
||||||
name = msg
|
|
||||||
rst, goods_name, code = await del_goods(name, id_)
|
|
||||||
if code == 200:
|
|
||||||
await shop_del_goods.send(f"删除商品 {goods_name} 成功了...", at_sender=True)
|
|
||||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
|
||||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
|
||||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 成功")
|
|
||||||
else:
|
|
||||||
await shop_del_goods.send(f"删除商品 {goods_name} 失败了...", at_sender=True)
|
|
||||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 失败")
|
|
||||||
|
|
||||||
|
|
||||||
@shop_update_goods.handle()
|
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|
||||||
msg = get_message_text(event.json())
|
|
||||||
if msg:
|
|
||||||
tmp = {}
|
|
||||||
msg = msg.split("-")
|
|
||||||
for x in msg:
|
|
||||||
if x.find("name") != -1:
|
|
||||||
tmp["name"] = x.split(" ")[1].strip()
|
|
||||||
elif x.find("price") != -1:
|
|
||||||
tmp["price"] = x.split(" ")[1].strip()
|
|
||||||
if not is_number(tmp["price"]):
|
|
||||||
await shop_update_goods.finish("价格必须是数字啊!", at_sender=True)
|
|
||||||
tmp["price"] = int(tmp["price"])
|
|
||||||
elif x.find("des") != -1:
|
|
||||||
tmp["des"] = x.split(" ")[1].strip()
|
|
||||||
elif x.find("discount") != -1:
|
|
||||||
tmp["discount"] = x.split(" ")[1].strip()
|
|
||||||
if not is_number(tmp["discount"]):
|
|
||||||
await shop_update_goods.finish("折扣必须是数字啊!", at_sender=True)
|
|
||||||
tmp["discount"] = float(tmp["discount"])
|
|
||||||
elif x.find("time") != -1:
|
|
||||||
tmp["time"] = x.split(" ")[1].strip()
|
|
||||||
if not is_number(tmp["time"]):
|
|
||||||
await shop_update_goods.finish("限时时间必须是数字啊!", at_sender=True)
|
|
||||||
tmp["time"] = time.time() + tmp["time"] * 60
|
|
||||||
if not tmp.get("name"):
|
|
||||||
await shop_update_goods.finish("未指定商品名称(序号也可)!", at_sender=True)
|
|
||||||
if is_number(tmp["name"]):
|
|
||||||
tmp["name"] = int(tmp["name"])
|
|
||||||
flag, name, text = await update_goods(tmp)
|
|
||||||
if flag:
|
|
||||||
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
|
|
||||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
|
||||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
|
||||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {tmp} 成功")
|
|
||||||
else:
|
|
||||||
await shop_update_goods.send(f"修改商品 {name} 失败了...", at_sender=True)
|
|
||||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {tmp} 失败")
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
from ..models.goods_info import GoodsInfo
|
|
||||||
from utils.image_utils import BuildImage
|
|
||||||
from utils.utils import is_number
|
|
||||||
from configs.path_config import IMAGE_PATH
|
|
||||||
from configs.config import Config
|
|
||||||
from nonebot import Driver
|
|
||||||
import nonebot
|
|
||||||
import time
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
driver: Driver = nonebot.get_driver()
|
|
||||||
|
|
||||||
|
|
||||||
# 导入内置商品 | 重新生成商店图片
|
|
||||||
@driver.on_startup
|
|
||||||
async def init_default_shop_goods():
|
|
||||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
|
||||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
|
||||||
if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
|
|
||||||
await add_goods(["好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"])
|
|
||||||
await add_goods(["好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)"])
|
|
||||||
await add_goods(["好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"])
|
|
||||||
|
|
||||||
|
|
||||||
# 创建商店界面
|
|
||||||
async def create_shop_help():
|
|
||||||
goods_lst = await GoodsInfo.get_all_goods()
|
|
||||||
tmp = ""
|
|
||||||
idx = 1
|
|
||||||
for goods in goods_lst:
|
|
||||||
tmp += (
|
|
||||||
f"{idx}.{goods.goods_name}\t\t售价:{goods.goods_price}金币\n"
|
|
||||||
f"\t\t{goods.goods_description}\n"
|
|
||||||
)
|
|
||||||
idx += 1
|
|
||||||
w = 1000
|
|
||||||
h = 400 + len(goods_lst) * 40
|
|
||||||
h = 1000 if h < 1000 else h
|
|
||||||
shop_logo = 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(
|
|
||||||
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
|
|
||||||
"注【通过 序号 或者 商品名称 购买】",
|
|
||||||
)
|
|
||||||
shop.text((20, 230), tmp[:-1])
|
|
||||||
shop.text((20, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
|
|
||||||
shop.save(f"{IMAGE_PATH}/shop_help.png")
|
|
||||||
|
|
||||||
|
|
||||||
# 添加商品
|
|
||||||
async def add_goods(msg: list):
|
|
||||||
data = {
|
|
||||||
"名称": None,
|
|
||||||
"价格": None,
|
|
||||||
"描述": None,
|
|
||||||
"折扣": 1,
|
|
||||||
"限时": 0,
|
|
||||||
}
|
|
||||||
keys = list(data.keys())
|
|
||||||
idx = 0
|
|
||||||
for x in msg:
|
|
||||||
data[keys[idx]] = x
|
|
||||||
idx += 1
|
|
||||||
return await GoodsInfo.add_goods(
|
|
||||||
data["名称"], data["价格"], data["描述"], data["折扣"], data["限时"]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# 删除商品
|
|
||||||
async def del_goods(name: str, id_: int):
|
|
||||||
goods_lst = await GoodsInfo.get_all_goods()
|
|
||||||
if id_:
|
|
||||||
if id_ < 1 or id_ > len(goods_lst):
|
|
||||||
return "序号错误,没有该序号商品...", "", 999
|
|
||||||
goods_name = goods_lst[id_ - 1].goods_name
|
|
||||||
if await GoodsInfo.delete_goods(goods_name):
|
|
||||||
return f"删除商品 {goods_name} 成功!", goods_name, 200
|
|
||||||
else:
|
|
||||||
return f"删除商品 {goods_name} 失败!", goods_name, 999
|
|
||||||
if name:
|
|
||||||
if await GoodsInfo.delete_goods(name):
|
|
||||||
return f"删除商品 {name} 成功!", name, 200
|
|
||||||
else:
|
|
||||||
return f"删除商品 {name} 失败!", name, 999
|
|
||||||
|
|
||||||
|
|
||||||
# 更新商品信息
|
|
||||||
async def update_goods(data: dict):
|
|
||||||
goods_lst = await GoodsInfo.get_all_goods()
|
|
||||||
if is_number(data["name"]):
|
|
||||||
if data["name"] < 1 or data["name"] > len(goods_lst):
|
|
||||||
return "序号错误,没有该序号的商品...", "", 999
|
|
||||||
goods = goods_lst[data["name"] - 1]
|
|
||||||
else:
|
|
||||||
goods = await GoodsInfo.get_goods_info(data["name"])
|
|
||||||
if not goods:
|
|
||||||
return "名称错误,没有该名称的商品...", "", 999
|
|
||||||
name = goods.goods_name
|
|
||||||
price = goods.goods_price
|
|
||||||
des = goods.goods_description
|
|
||||||
discount = goods.goods_discount
|
|
||||||
limit_time = goods.goods_limit_time
|
|
||||||
tmp = ""
|
|
||||||
if data.get("price"):
|
|
||||||
tmp += f'价格:{price} --> {data["price"]}\n'
|
|
||||||
price = data["price"]
|
|
||||||
if data.get("des"):
|
|
||||||
tmp += f'描述:{des} --> {data["des"]}\n'
|
|
||||||
des = data["des"]
|
|
||||||
if data.get("discount"):
|
|
||||||
tmp += f'折扣:{discount} --> {data["discount"]}\n'
|
|
||||||
discount = data["discount"]
|
|
||||||
if data.get("time"):
|
|
||||||
old_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(limit_time))
|
|
||||||
new_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(data["time"]))
|
|
||||||
tmp += f"折扣:{old_time} --> {new_time}\n"
|
|
||||||
limit_time = data["time"]
|
|
||||||
return (
|
|
||||||
await GoodsInfo.update_goods(name, price, des, discount, limit_time),
|
|
||||||
name,
|
|
||||||
tmp[:-1],
|
|
||||||
)
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
from models.sign_group_user import SignGroupUser
|
|
||||||
|
|
||||||
|
|
||||||
async def effect(user_id: int, group_id: int, name: str) -> bool:
|
|
||||||
if name in ["好感双倍加持卡Ⅰ", "好感度双倍加持卡Ⅰ"]:
|
|
||||||
user = await SignGroupUser.ensure(user_id, group_id)
|
|
||||||
await user.update(add_probability=0.1).apply()
|
|
||||||
if name in ["好感双倍加持卡Ⅱ", "好感度双倍加持卡Ⅱ"]:
|
|
||||||
user = await SignGroupUser.ensure(user_id, group_id)
|
|
||||||
await user.update(add_probability=0.2).apply()
|
|
||||||
if name in ["好感双倍加持卡Ⅲ", "好感度双倍加持卡Ⅲ"]:
|
|
||||||
user = await SignGroupUser.ensure(user_id, group_id)
|
|
||||||
await user.update(add_probability=0.3).apply()
|
|
||||||
return True
|
|
||||||
@@ -28,14 +28,14 @@ usage:
|
|||||||
每日签到
|
每日签到
|
||||||
会影响色图概率和开箱次数,以及签到的随机道具获取
|
会影响色图概率和开箱次数,以及签到的随机道具获取
|
||||||
指令:
|
指令:
|
||||||
签到
|
签到 ?[all]: all代表签到所有群
|
||||||
我的签到
|
我的签到
|
||||||
好感度排行
|
好感度排行
|
||||||
好感度总排行
|
好感度总排行
|
||||||
* 签到时有 3% 概率 * 2 *
|
* 签到时有 3% 概率 * 2 *
|
||||||
""".strip()
|
""".strip()
|
||||||
__plugin_des__ = "每日签到,证明你在这里"
|
__plugin_des__ = "每日签到,证明你在这里"
|
||||||
__plugin_cmd__ = ["签到", "我的签到", "好感度排行", "好感度总排行"]
|
__plugin_cmd__ = ["签到 ?[all]", "我的签到", "好感度排行", "好感度总排行"]
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier"
|
||||||
__plugin_settings__ = {
|
__plugin_settings__ = {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ async def check_in_all(nickname: str, user_qq: int):
|
|||||||
async with db.transaction():
|
async with db.transaction():
|
||||||
present = datetime.now()
|
present = datetime.now()
|
||||||
for u in await SignGroupUser.get_user_all_data(user_qq):
|
for u in await SignGroupUser.get_user_all_data(user_qq):
|
||||||
group = u.belonging_group
|
group = u.group_id
|
||||||
if not ((
|
if not ((
|
||||||
u.checkin_time_last + timedelta(hours=8)
|
u.checkin_time_last + timedelta(hours=8)
|
||||||
).date() >= present.date() or f"{u}_{group}_sign_{datetime.now().date()}" in os.listdir(
|
).date() >= present.date() or f"{u}_{group}_sign_{datetime.now().date()}" in os.listdir(
|
||||||
@@ -79,18 +79,18 @@ async def _handle_check_in(
|
|||||||
gift = f"额外金币 + {gift}"
|
gift = f"额外金币 + {gift}"
|
||||||
else:
|
else:
|
||||||
await BagUser.add_gold(user_qq, group, gold)
|
await BagUser.add_gold(user_qq, group, gold)
|
||||||
await BagUser.add_props(user_qq, group, gift)
|
await BagUser.add_property(user_qq, group, gift)
|
||||||
gift += ' + 1'
|
gift += ' + 1'
|
||||||
if critx2 + add_probability > 0.97 or critx2 < specify_probability:
|
if critx2 + add_probability > 0.97 or critx2 < specify_probability:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"(USER {user.user_qq}, GROUP {user.belonging_group})"
|
f"(USER {user.user_qq}, GROUP {user.group_id})"
|
||||||
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
||||||
f"(+{impression_added * 2:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
f"(+{impression_added * 2:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
||||||
)
|
)
|
||||||
return await get_card(user, nickname, impression_added, gold, gift, True)
|
return await get_card(user, nickname, impression_added, gold, gift, True)
|
||||||
else:
|
else:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"(USER {user.user_qq}, GROUP {user.belonging_group})"
|
f"(USER {user.user_qq}, GROUP {user.group_id})"
|
||||||
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
||||||
f"(+{impression_added:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
f"(+{impression_added:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from .config import (
|
|||||||
from models.sign_group_user import SignGroupUser
|
from models.sign_group_user import SignGroupUser
|
||||||
from models.group_member_info import GroupInfoUser
|
from models.group_member_info import GroupInfoUser
|
||||||
from nonebot.adapters.cqhttp import MessageSegment
|
from nonebot.adapters.cqhttp import MessageSegment
|
||||||
|
from configs.config import Config
|
||||||
from utils.utils import get_user_avatar
|
from utils.utils import get_user_avatar
|
||||||
from utils.image_utils import BuildImage
|
from utils.image_utils import BuildImage
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
@@ -55,32 +56,32 @@ async def get_card(
|
|||||||
_type = "view" if is_card_view else "sign"
|
_type = "view" if is_card_view else "sign"
|
||||||
card_file = (
|
card_file = (
|
||||||
Path(SIGN_TODAY_CARD_PATH)
|
Path(SIGN_TODAY_CARD_PATH)
|
||||||
/ f"{user_id}_{user.belonging_group}_{_type}_{date}.png"
|
/ f"{user_id}_{user.group_id}_{_type}_{date}.png"
|
||||||
)
|
)
|
||||||
if card_file.exists():
|
if card_file.exists():
|
||||||
return image(
|
return image(
|
||||||
f"{user_id}_{user.belonging_group}_{_type}_{date}.png", "sign/today_card"
|
f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if add_impression == -1:
|
if add_impression == -1:
|
||||||
card_file = (
|
card_file = (
|
||||||
Path(SIGN_TODAY_CARD_PATH)
|
Path(SIGN_TODAY_CARD_PATH)
|
||||||
/ f"{user_id}_{user.belonging_group}_view_{date}.png"
|
/ f"{user_id}_{user.group_id}_view_{date}.png"
|
||||||
)
|
)
|
||||||
if card_file.exists():
|
if card_file.exists():
|
||||||
return image(
|
return image(
|
||||||
f"{user_id}_{user.belonging_group}_view_{date}.png",
|
f"{user_id}_{user.group_id}_view_{date}.png",
|
||||||
"sign/today_card",
|
"sign/today_card",
|
||||||
)
|
)
|
||||||
is_card_view = True
|
is_card_view = True
|
||||||
ava = BytesIO(await get_user_avatar(user_id))
|
ava = BytesIO(await get_user_avatar(user_id))
|
||||||
uid = await GroupInfoUser.get_group_member_uid(
|
uid = await GroupInfoUser.get_group_member_uid(
|
||||||
user.user_qq, user.belonging_group
|
user.user_qq, user.group_id
|
||||||
)
|
)
|
||||||
impression_list = None
|
impression_list = None
|
||||||
if is_card_view:
|
if is_card_view:
|
||||||
_, impression_list, _ = await SignGroupUser.get_all_impression(
|
_, impression_list, _ = await SignGroupUser.get_all_impression(
|
||||||
user.belonging_group
|
user.group_id
|
||||||
)
|
)
|
||||||
return await asyncio.get_event_loop().run_in_executor(
|
return await asyncio.get_event_loop().run_in_executor(
|
||||||
None,
|
None,
|
||||||
@@ -239,9 +240,10 @@ def _generate_card(
|
|||||||
f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}",
|
f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}",
|
||||||
)
|
)
|
||||||
today_data.text((0, 25), f"总金币:{gold}")
|
today_data.text((0, 25), f"总金币:{gold}")
|
||||||
|
default_setu_prob = Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100
|
||||||
today_data.text(
|
today_data.text(
|
||||||
(0, 50),
|
(0, 50),
|
||||||
f"色图概率:{(70 + user.impression if user.impression < 100 else 100):.2f}%",
|
f"色图概率:{(default_setu_prob + user.impression if user.impression < 100 else 100):.2f}%",
|
||||||
)
|
)
|
||||||
today_data.text((0, 75), f"开箱次数:{(20 + int(user.impression / 3))}")
|
today_data.text((0, 75), f"开箱次数:{(20 + int(user.impression / 3))}")
|
||||||
_type = "view"
|
_type = "view"
|
||||||
@@ -285,10 +287,10 @@ def _generate_card(
|
|||||||
bk.paste(today_data, (580, 220), True)
|
bk.paste(today_data, (580, 220), True)
|
||||||
bk.paste(watermark, (15, 400), True)
|
bk.paste(watermark, (15, 400), True)
|
||||||
bk.save(
|
bk.save(
|
||||||
SIGN_TODAY_CARD_PATH / f"{user_id}_{user.belonging_group}_{_type}_{data}.png"
|
SIGN_TODAY_CARD_PATH / f"{user_id}_{user.group_id}_{_type}_{data}.png"
|
||||||
)
|
)
|
||||||
return image(
|
return image(
|
||||||
f"{user_id}_{user.belonging_group}_{_type}_{data}.png", "sign/today_card"
|
f"{user_id}_{user.group_id}_{_type}_{data}.png", "sign/today_card"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ async def translate_msg(language_type, msg):
|
|||||||
}
|
}
|
||||||
data = (await AsyncHttpx.post(url, data=data)).json()
|
data = (await AsyncHttpx.post(url, data=data)).json()
|
||||||
if data["errorCode"] == 0:
|
if data["errorCode"] == 0:
|
||||||
return data["translateResult"][0][0]["tgt"]
|
return f'原文:{msg}\n翻译{data["translateResult"][0][0]["tgt"]}'
|
||||||
return "翻译惜败.."
|
return "翻译惜败.."
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from services.log import logger
|
|||||||
from nonebot.rule import to_me
|
from nonebot.rule import to_me
|
||||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from utils.utils import get_message_imgs
|
from utils.utils import get_message_img
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from utils.utils import is_number, get_message_text
|
from utils.utils import is_number, get_message_text
|
||||||
from utils.image_utils import BuildImage, pic2b64
|
from utils.image_utils import BuildImage, pic2b64
|
||||||
@@ -150,9 +150,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
await update_img.reject("请输入支持的替换的底色:\n红色 蓝色 白色 绿色")
|
await update_img.reject("请输入支持的替换的底色:\n红色 蓝色 白色 绿色")
|
||||||
state["y"] = str(event.get_message())
|
state["y"] = str(event.get_message())
|
||||||
if state["_current_key"] == "imgs":
|
if state["_current_key"] == "imgs":
|
||||||
if not get_message_imgs(event.json()):
|
if not get_message_img(event.json()):
|
||||||
await update_img.reject("没图?没图?没图?来图速来!")
|
await update_img.reject("没图?没图?没图?来图速来!")
|
||||||
state[state["_current_key"]] = get_message_imgs(event.json())
|
state[state["_current_key"]] = get_message_img(event.json())
|
||||||
|
|
||||||
|
|
||||||
@update_img.handle()
|
@update_img.handle()
|
||||||
@@ -160,7 +160,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
if str(event.get_message()) in ["帮助"]:
|
if str(event.get_message()) in ["帮助"]:
|
||||||
await update_img.finish(image("update_img_help.png"))
|
await update_img.finish(image("update_img_help.png"))
|
||||||
raw_arg = get_message_text(event.json())
|
raw_arg = get_message_text(event.json())
|
||||||
img_list = get_message_imgs(event.json())
|
img_list = get_message_img(event.json())
|
||||||
if raw_arg:
|
if raw_arg:
|
||||||
args = raw_arg.split("[")[0].split(" ")
|
args = raw_arg.split("[")[0].split(" ")
|
||||||
print(args)
|
print(args)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from .data_source import get_anime
|
|||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||||
from utils.utils import get_message_imgs
|
from utils.utils import get_message_img
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
|
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ what_anime = on_command("识番", priority=5, block=True)
|
|||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
if str(event.get_message()) in ["取消", "算了"]:
|
if str(event.get_message()) in ["取消", "算了"]:
|
||||||
await what_anime.finish("已取消操作..", at_sender=True)
|
await what_anime.finish("已取消操作..", at_sender=True)
|
||||||
img_url = get_message_imgs(event.json())
|
img_url = get_message_img(event.json())
|
||||||
if not img_url:
|
if not img_url:
|
||||||
await what_anime.reject(prompt="图呢图呢图呢图呢GKD", at_sender=True)
|
await what_anime.reject(prompt="图呢图呢图呢图呢GKD", at_sender=True)
|
||||||
state["img_url"] = img_url
|
state["img_url"] = img_url
|
||||||
@@ -43,7 +43,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
if str(event.get_message()) in ["帮助"]:
|
if str(event.get_message()) in ["帮助"]:
|
||||||
await what_anime.finish(__plugin_usage__)
|
await what_anime.finish(__plugin_usage__)
|
||||||
img_url = get_message_imgs(event.json())
|
img_url = get_message_img(event.json())
|
||||||
if img_url:
|
if img_url:
|
||||||
state["img_url"] = img_url
|
state["img_url"] = img_url
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from utils.utils import get_message_imgs, get_message_text, is_chinese
|
from utils.utils import get_message_img, get_message_text, is_chinese
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from configs.path_config import TEMP_PATH
|
from configs.path_config import TEMP_PATH
|
||||||
from utils.image_utils import BuildImage
|
from utils.image_utils import BuildImage
|
||||||
@@ -47,7 +47,7 @@ w2b_img = on_command("黑白草图", aliases={"黑白图"}, priority=5, block=Tr
|
|||||||
@w2b_img.handle()
|
@w2b_img.handle()
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||||
# try:
|
# try:
|
||||||
img = get_message_imgs(event.json())
|
img = get_message_img(event.json())
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
if not img or not msg:
|
if not img or not msg:
|
||||||
await w2b_img.finish(f"格式错误:\n" + __plugin_usage__)
|
await w2b_img.finish(f"格式错误:\n" + __plugin_usage__)
|
||||||
|
|||||||
@@ -209,3 +209,4 @@ class WordBank(db.Model):
|
|||||||
if q:
|
if q:
|
||||||
return [(x.answer, x.format.split("<format>")[:-1]) for x in q]
|
return [(x.answer, x.format.split("<format>")[:-1]) for x in q]
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
from utils.utils import get_message_at, is_number, get_message_imgs, get_message_text
|
from utils.utils import get_message_at, is_number, get_message_img, get_message_text
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from configs.path_config import DATA_PATH
|
from configs.path_config import DATA_PATH
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
from .data_source import WordBankBuilder
|
from .data_source import WordBankBuilder
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
|
from utils.message_builder import image
|
||||||
|
from utils.image_utils import text2image
|
||||||
from .model import WordBank
|
from .model import WordBank
|
||||||
from nonebot.adapters.cqhttp import (
|
from nonebot.adapters.cqhttp import (
|
||||||
Bot,
|
Bot,
|
||||||
@@ -42,7 +44,7 @@ __plugin_version__ = 0.1
|
|||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier"
|
||||||
__plugin_settings__ = {
|
__plugin_settings__ = {
|
||||||
"admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL"),
|
"admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL"),
|
||||||
"cmd": ["词库问答", "添加词条", "删除词条", "查看词条"]
|
"cmd": ["词库问答", "添加词条", "删除词条", "查看词条"],
|
||||||
}
|
}
|
||||||
|
|
||||||
data_dir = Path(DATA_PATH) / "word_bank"
|
data_dir = Path(DATA_PATH) / "word_bank"
|
||||||
@@ -63,13 +65,15 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
if not r:
|
if not r:
|
||||||
await add_word.finish("未检测到词条问题...")
|
await add_word.finish("未检测到词条问题...")
|
||||||
problem = r.group(1).strip()
|
problem = r.group(1).strip()
|
||||||
answer = msg.split('答', maxsplit=1)[-1]
|
if not problem:
|
||||||
|
await add_word.finish("未检测到词条问题...")
|
||||||
|
answer = msg.split("答", maxsplit=1)[-1]
|
||||||
if not answer:
|
if not answer:
|
||||||
await add_word.finish("未检测到词条回答...")
|
await add_word.finish("未检测到词条回答...")
|
||||||
idx = 0
|
idx = 0
|
||||||
for n in bot.config.nickname:
|
for n in bot.config.nickname:
|
||||||
if problem.startswith(n):
|
if problem.startswith(n):
|
||||||
_problem = f"[_to_me|{n}]" + problem[len(n):]
|
_problem = f"[_to_me|{n}]" + problem[len(n) :]
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
_problem = problem
|
_problem = problem
|
||||||
@@ -80,7 +84,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
answer = answer.replace(f"[CQ:at,qq={at_}]", f"[__placeholder_{idx}]", 1)
|
answer = answer.replace(f"[CQ:at,qq={at_}]", f"[__placeholder_{idx}]", 1)
|
||||||
_builder.set_placeholder(idx, at_)
|
_builder.set_placeholder(idx, at_)
|
||||||
idx += 1
|
idx += 1
|
||||||
for img in get_message_imgs(event.json()):
|
for img in get_message_img(event.json()):
|
||||||
_x = img.split("?")[0]
|
_x = img.split("?")[0]
|
||||||
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", answer)
|
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", answer)
|
||||||
if r:
|
if r:
|
||||||
@@ -88,7 +92,8 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
for i in range(3):
|
for i in range(3):
|
||||||
answer = answer.replace(f",subType={i}", "")
|
answer = answer.replace(f",subType={i}", "")
|
||||||
answer = answer.replace(
|
answer = answer.replace(
|
||||||
rf"[CQ:image,file={r.group(1)},url={img}]", f"[__placeholder_{idx}]",
|
rf"[CQ:image,file={r.group(1)},url={img}]",
|
||||||
|
f"[__placeholder_{idx}]",
|
||||||
)
|
)
|
||||||
await AsyncHttpx.download_file(
|
await AsyncHttpx.download_file(
|
||||||
img, data_dir / f"{event.group_id}" / f"__placeholder_{rand}_{idx}.jpg"
|
img, data_dir / f"{event.group_id}" / f"__placeholder_{rand}_{idx}.jpg"
|
||||||
@@ -117,11 +122,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
x = problem.split(":")[-1]
|
x = problem.split(":")[-1]
|
||||||
if not is_number(x) or int(x) < 0:
|
if not is_number(x) or int(x) < 0:
|
||||||
await delete_word.finish("id必须为数字且符合规范!")
|
await delete_word.finish("id必须为数字且符合规范!")
|
||||||
p = (await WordBank.get_group_all_problem(event.group_id))
|
p = await WordBank.get_group_all_problem(event.group_id)
|
||||||
if p:
|
if p:
|
||||||
problem = p[int(x)]
|
problem = p[int(x)]
|
||||||
try:
|
try:
|
||||||
if answer := await WordBank.delete_problem_answer(event.user_id, event.group_id, problem, index):
|
if answer := await WordBank.delete_problem_answer(
|
||||||
|
event.user_id, event.group_id, problem, index
|
||||||
|
):
|
||||||
await delete_word.send(f"删除词条成功:{problem}\n回答:\n{answer}")
|
await delete_word.send(f"删除词条成功:{problem}\n回答:\n{answer}")
|
||||||
logger.info(
|
logger.info(
|
||||||
f"(USER {event.user_id}, GROUP "
|
f"(USER {event.user_id}, GROUP "
|
||||||
@@ -141,21 +148,20 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
|||||||
_problem_list = await WordBank.get_group_all_problem(event.group_id)
|
_problem_list = await WordBank.get_group_all_problem(event.group_id)
|
||||||
if not _problem_list:
|
if not _problem_list:
|
||||||
await show_word.finish("该群未收录任何词条..")
|
await show_word.finish("该群未收录任何词条..")
|
||||||
_problem_list = [f"{i}. {x}" for i, x in enumerate(_problem_list)]
|
_problem_list = [f"\t{i}. {x}" for i, x in enumerate(_problem_list)]
|
||||||
await show_word.send(
|
await show_word.send(
|
||||||
"该群已收录的词条:\n" + "\n".join(_problem_list)
|
image(
|
||||||
|
b64=await text2image(
|
||||||
|
"该群已收录的词条:\n\n" + "\n".join(_problem_list),
|
||||||
|
padding=10,
|
||||||
|
color="#f9f6f2",
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
_answer_list = await WordBank.get_group_all_answer(event.group_id, msg)
|
_answer_list = await WordBank.get_group_all_answer(event.group_id, msg)
|
||||||
if not _answer_list:
|
if not _answer_list:
|
||||||
await show_word.send(
|
await show_word.send("未收录该词条...")
|
||||||
"未收录该词条..."
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
_answer_list = [f"{i}. {x}" for i, x in enumerate(_answer_list)]
|
_answer_list = [f"{i}. {x}" for i, x in enumerate(_answer_list)]
|
||||||
await show_word.send(
|
await show_word.send(f"词条 {msg} 回答:\n" + "\n".join(_answer_list))
|
||||||
f"词条 {msg} 回答:\n" + "\n".join(_answer_list)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
|||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from utils.utils import get_message_text
|
from utils.utils import get_message_text
|
||||||
from configs.config import NICKNAME
|
from configs.config import NICKNAME
|
||||||
|
from .other_than import get_other_data
|
||||||
|
|
||||||
__zx_plugin_name__ = "疫情查询"
|
__zx_plugin_name__ = "疫情查询"
|
||||||
__plugin_usage__ = """
|
__plugin_usage__ = """
|
||||||
usage:
|
usage:
|
||||||
全国疫情查询
|
全国疫情查询
|
||||||
指令:
|
指令:
|
||||||
疫情 中国
|
疫情 中国/美国/英国...
|
||||||
疫情 [省份/城市]
|
疫情 [省份/城市]
|
||||||
* 当省份与城市重名时,可在后添加 "市" 或 "省" *
|
* 当省份与城市重名时,可在后添加 "市" 或 "省" *
|
||||||
示例:疫情 吉林 <- [省]
|
示例:疫情 吉林 <- [省]
|
||||||
@@ -20,9 +20,9 @@ usage:
|
|||||||
""".strip()
|
""".strip()
|
||||||
__plugin_des__ = "实时疫情数据查询"
|
__plugin_des__ = "实时疫情数据查询"
|
||||||
__plugin_cmd__ = ["疫情 [省份/城市]", "疫情 中国"]
|
__plugin_cmd__ = ["疫情 [省份/城市]", "疫情 中国"]
|
||||||
__plugin_type__ = ('一些工具',)
|
__plugin_type__ = ("一些工具",)
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier & yzyyz1387"
|
||||||
__plugin_settings__ = {
|
__plugin_settings__ = {
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"default_status": True,
|
"default_status": True,
|
||||||
@@ -54,4 +54,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
|||||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情失败"
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情失败"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await yiqing.send(f"{NICKNAME}没有查到{msg}的疫情查询...")
|
rely = await get_other_data(msg)
|
||||||
|
if rely:
|
||||||
|
await yiqing.send(rely)
|
||||||
|
logger.info(
|
||||||
|
f"(USER {event.user_id}, GROUP "
|
||||||
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情成功"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await yiqing.send(f"{NICKNAME}没有查到{msg}的疫情查询...")
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
from configs.path_config import TEXT_PATH
|
from configs.path_config import TEXT_PATH
|
||||||
from typing import List
|
from typing import List, Union
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
|
from utils.image_utils import text2image
|
||||||
|
from utils.message_builder import image
|
||||||
|
from nonebot.adapters.cqhttp import MessageSegment
|
||||||
import ujson as json
|
import ujson as json
|
||||||
|
|
||||||
china_city = Path(TEXT_PATH) / "china_city.json"
|
china_city = Path(TEXT_PATH) / "china_city.json"
|
||||||
@@ -12,7 +15,7 @@ data = {}
|
|||||||
url = "https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5"
|
url = "https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5"
|
||||||
|
|
||||||
|
|
||||||
async def get_yiqing_data(area: str):
|
async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
|
||||||
"""
|
"""
|
||||||
查看疫情数据
|
查看疫情数据
|
||||||
:param area: 省份/城市
|
:param area: 省份/城市
|
||||||
@@ -40,39 +43,49 @@ async def get_yiqing_data(area: str):
|
|||||||
if area == "中国":
|
if area == "中国":
|
||||||
data_ = epidemic_data["areaTree"][0]
|
data_ = epidemic_data["areaTree"][0]
|
||||||
else:
|
else:
|
||||||
data_ = [
|
try:
|
||||||
x
|
data_ = [
|
||||||
for x in epidemic_data["areaTree"][0]["children"]
|
x
|
||||||
if x["name"] == province
|
for x in epidemic_data["areaTree"][0]["children"]
|
||||||
][0]
|
if x["name"] == province
|
||||||
if city:
|
][0]
|
||||||
try:
|
if city:
|
||||||
data_ = [x for x in data_["children"] if x["name"] == city][0]
|
data_ = [x for x in data_["children"] if x["name"] == city][0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return "未查询到..."
|
return "未查询到..."
|
||||||
confirm = data_["total"]["confirm"] # 累计确诊
|
confirm = data_["total"]["confirm"] # 累计确诊
|
||||||
heal = data_["total"]["heal"] # 累计治愈
|
heal = data_["total"]["heal"] # 累计治愈
|
||||||
dead = data_["total"]["dead"] # 累计死亡
|
dead = data_["total"]["dead"] # 累计死亡
|
||||||
dead_rate = data_["total"]["deadRate"] # 死亡率
|
|
||||||
heal_rate = data_["total"]["healRate"] # 治愈率
|
|
||||||
now_confirm = data_["total"]["nowConfirm"] # 目前确诊
|
now_confirm = data_["total"]["nowConfirm"] # 目前确诊
|
||||||
suspect = data_["total"]["suspect"] # 疑似
|
|
||||||
add_confirm = data_["today"]["confirm"] # 新增确诊
|
add_confirm = data_["today"]["confirm"] # 新增确诊
|
||||||
|
grade = ""
|
||||||
|
_grade_color = ""
|
||||||
|
if data_["total"].get("grade"):
|
||||||
|
grade = data_["total"]["grade"]
|
||||||
|
if "中风险" in grade:
|
||||||
|
_grade_color = "#fa9424"
|
||||||
|
else:
|
||||||
|
_grade_color = "red"
|
||||||
|
|
||||||
|
dead_rate = f"{dead / confirm * 100:.2f}" # 死亡率
|
||||||
|
heal_rate = f"{heal / confirm * 100:.2f}" # 治愈率
|
||||||
|
|
||||||
x = f"{city}市" if city else f"{province}{province_type}"
|
x = f"{city}市" if city else f"{province}{province_type}"
|
||||||
return (
|
return image(b64=await text2image(
|
||||||
f"{x} 疫情数据:\n"
|
f"""
|
||||||
f"\t目前确诊:\n"
|
{x} 疫情数据 {f"(<f font_color={_grade_color}>{grade}</f>)" if grade else ""}:
|
||||||
f"\t\t确诊人数:{now_confirm}(+{add_confirm})\n"
|
目前确诊:
|
||||||
f"\t\t疑似人数:{suspect}\n"
|
确诊人数:<f font_color=red>{now_confirm}(+{add_confirm})</f>
|
||||||
f"==================\n"
|
-----------------
|
||||||
f"\t累计数据:\n"
|
累计数据:
|
||||||
f"\t\t确诊人数:{confirm}\n"
|
确诊人数:<f font_color=red>{confirm}</f>
|
||||||
f"\t\t治愈人数:{heal}\n"
|
治愈人数:<f font_color=#39de4b>{heal}</f>
|
||||||
f"\t\t死亡人数:{dead}\n"
|
死亡人数:<f font_color=#191d19>{dead}</f>
|
||||||
f"\t治愈率:{heal_rate}%\n"
|
治愈率:{heal_rate}%
|
||||||
f"\t死亡率:{dead_rate}%\n"
|
死亡率:{dead_rate}%
|
||||||
f"更新日期:{last_update_time}"
|
更新日期:{last_update_time}
|
||||||
)
|
""", font_size=30, color="#f9f6f2"
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
def get_city_and_province_list() -> List[str]:
|
def get_city_and_province_list() -> List[str]:
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
# python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2021/12/23 23:04
|
||||||
|
# @Author : yzyyz
|
||||||
|
# @Email : youzyyz1384@qq.com
|
||||||
|
# @File : other_than.py
|
||||||
|
# @Software: PyCharm
|
||||||
|
from utils.http_utils import AsyncHttpx
|
||||||
|
from nonebot.adapters.cqhttp import MessageSegment
|
||||||
|
from typing import Optional
|
||||||
|
from services.log import logger
|
||||||
|
from utils.image_utils import text2image
|
||||||
|
from utils.message_builder import image
|
||||||
|
from json.decoder import JSONDecodeError
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
|
__doc__ = """爬虫实现国外疫情数据(找不到好接口)"""
|
||||||
|
|
||||||
|
|
||||||
|
def intcomma(value) -> str:
|
||||||
|
"""
|
||||||
|
数字格式化
|
||||||
|
"""
|
||||||
|
orig = str(value)
|
||||||
|
new = re.sub(r"^(-?\d+)(\d{3})", r"\g<1>,\g<2>", orig)
|
||||||
|
return new if orig == new else intcomma(new)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_other_data(place: str, count: int = 0) -> Optional[MessageSegment]:
|
||||||
|
"""
|
||||||
|
:param place: 地名
|
||||||
|
:param count: 递归次数
|
||||||
|
:return: 格式化字符串
|
||||||
|
"""
|
||||||
|
if count == 5:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
html = (
|
||||||
|
(await AsyncHttpx.get("https://news.ifeng.com/c/special/7uLj4F83Cqm"))
|
||||||
|
.text.replace("\n", "")
|
||||||
|
.replace(" ", "")
|
||||||
|
)
|
||||||
|
find_data = re.compile(r"varallData=(.*?);</script>")
|
||||||
|
sum_ = re.findall(find_data, html)[0]
|
||||||
|
sum_ = json.loads(sum_)
|
||||||
|
except JSONDecodeError:
|
||||||
|
return await get_other_data(place, count + 1)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"疫情查询发生错误 {type(e)}:{e}")
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
other_country = sum_["yiqing_v2"]["dataList"][29]["child"]
|
||||||
|
for country in other_country:
|
||||||
|
if place == country["name2"]:
|
||||||
|
return image(
|
||||||
|
b64=await text2image(
|
||||||
|
f" {place} 疫情数据:\n"
|
||||||
|
"——————————————\n"
|
||||||
|
f" 新增病例:<f font_color=red>{intcomma(country['quezhen_add'])}</f>\n"
|
||||||
|
f" 现有确诊:<f font_color=red>{intcomma(country['quezhen_xianyou'])}</f>\n"
|
||||||
|
f" 累计确诊:<f font_color=red>{intcomma(country['quezhen'])}</f>\n"
|
||||||
|
f" 累计治愈:<f font_color=#39de4b>{intcomma(country['zhiyu'])}</f>\n"
|
||||||
|
f" 死亡:{intcomma(country['siwang'])}\n"
|
||||||
|
"——————————————"
|
||||||
|
# f"更新时间:{country['sys_publishDateTime']}"
|
||||||
|
# 时间无法精确到分钟,网页用了js我暂时找不到
|
||||||
|
,
|
||||||
|
font_size=30,
|
||||||
|
color="#f9f6f2",
|
||||||
|
padding=15
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
for city in country["child"]:
|
||||||
|
if place == city["name3"]:
|
||||||
|
return image(
|
||||||
|
b64=await text2image(
|
||||||
|
f"\n{place} 疫情数据:\n"
|
||||||
|
"——————————————\n"
|
||||||
|
f"\t新增病例:<f font_color=red>{intcomma(city['quezhen_add'])}</f>\n"
|
||||||
|
f"\t累计确诊:<f font_color=red>{intcomma(city['quezhen'])}</f>\n"
|
||||||
|
f"\t累计治愈:<f font_color=#39de4b>{intcomma(city['zhiyu'])}</f>\n"
|
||||||
|
f"\t死亡:{intcomma(city['siwang'])}\n"
|
||||||
|
"——————————————\n",
|
||||||
|
font_size=30,
|
||||||
|
color="#f9f6f2",
|
||||||
|
padding=15
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"疫情查询发生错误 {type(e)}:{e}")
|
||||||
|
return None
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -17,7 +17,7 @@ async def init():
|
|||||||
await db.gino.create_all()
|
await db.gino.create_all()
|
||||||
logger.info(f'Database loaded successfully!')
|
logger.info(f'Database loaded successfully!')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception(f'数据库连接错误.... e: {e}')
|
raise Exception(f'数据库连接错误.... {type(e)}: {e}')
|
||||||
|
|
||||||
|
|
||||||
async def disconnect():
|
async def disconnect():
|
||||||
|
|||||||
+3
-5
@@ -2,12 +2,10 @@
|
|||||||
"update_file": [
|
"update_file": [
|
||||||
"plugins",
|
"plugins",
|
||||||
"models",
|
"models",
|
||||||
"basic_plugins",
|
|
||||||
"utils",
|
|
||||||
"services",
|
"services",
|
||||||
"configs/utils",
|
"utils",
|
||||||
"bot.py"
|
"basic_plugins"
|
||||||
],
|
],
|
||||||
"add_file": ["resources/img/genshin/genshin_card", "resources/img/genshin/genshin_memo"],
|
"add_file": [],
|
||||||
"delete_file": []
|
"delete_file": []
|
||||||
}
|
}
|
||||||
|
|||||||
+246
-12
@@ -11,6 +11,7 @@ import random
|
|||||||
import cv2
|
import cv2
|
||||||
import base64
|
import base64
|
||||||
import imagehash
|
import imagehash
|
||||||
|
import re
|
||||||
|
|
||||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||||
Image.MAX_IMAGE_PIXELS = None
|
Image.MAX_IMAGE_PIXELS = None
|
||||||
@@ -136,6 +137,186 @@ def is_valid(file: str) -> bool:
|
|||||||
return valid
|
return valid
|
||||||
|
|
||||||
|
|
||||||
|
async def text2image(
|
||||||
|
text: str,
|
||||||
|
auto_parse: bool = True,
|
||||||
|
font_size: int = 20,
|
||||||
|
color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = "white",
|
||||||
|
font: str = "CJGaoDeGuo.otf",
|
||||||
|
font_color: Union[str, Tuple[int, int, int]] = "black",
|
||||||
|
padding: Union[int, Tuple[int, int, int, int]] = 0,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
解析文本并转为图片
|
||||||
|
使用标签
|
||||||
|
<f> </f>
|
||||||
|
可选配置项
|
||||||
|
font: str -> 特殊文本字体
|
||||||
|
font_size: int -> 特殊文本大小
|
||||||
|
font_color: str -> 特殊文本颜色
|
||||||
|
示例
|
||||||
|
在不在,<f font=YSHaoShenTi-2.ttf font_size=30 font_color=red>HibiKi小姐</f>,
|
||||||
|
你最近还好吗,<f font_size=15 font_color=black>我非常想你</f>,这段时间我非常不好过,
|
||||||
|
<f font_size=25>抽卡抽不到金色</f>,这让我很痛苦
|
||||||
|
参数:
|
||||||
|
:param text: 文本
|
||||||
|
:param auto_parse: 是否自动解析,否则原样发送
|
||||||
|
:param font_size: 普通字体大小
|
||||||
|
:param color: 背景颜色
|
||||||
|
:param font: 普通字体
|
||||||
|
:param font_color: 普通字体颜色
|
||||||
|
:param padding: 文本外边距,元组类型时为 (上,左,下,右)
|
||||||
|
"""
|
||||||
|
pw = ph = top_padding = left_padding = 0
|
||||||
|
if padding:
|
||||||
|
if isinstance(padding, int):
|
||||||
|
pw = padding * 2
|
||||||
|
ph = padding * 2
|
||||||
|
top_padding = left_padding = padding
|
||||||
|
elif isinstance(padding, tuple):
|
||||||
|
pw = padding[0] + padding[2]
|
||||||
|
ph = padding[1] + padding[3]
|
||||||
|
top_padding = padding[0]
|
||||||
|
left_padding = padding[1]
|
||||||
|
if auto_parse and re.search(r"<f(.*)>(.*)</f>", text):
|
||||||
|
_data = []
|
||||||
|
new_text = ""
|
||||||
|
placeholder_index = 0
|
||||||
|
for s in text.split("</f>"):
|
||||||
|
r = re.search(r"<f(.*)>(.*)", s)
|
||||||
|
if r:
|
||||||
|
start, end = r.span()
|
||||||
|
if start != 0 and (t := s[:start]):
|
||||||
|
new_text += t
|
||||||
|
_data.append(
|
||||||
|
[
|
||||||
|
(start, end),
|
||||||
|
f"[placeholder_{placeholder_index}]",
|
||||||
|
r.group(1).strip(),
|
||||||
|
r.group(2),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
new_text += f"[placeholder_{placeholder_index}]"
|
||||||
|
placeholder_index += 1
|
||||||
|
new_text += text.split("</f>")[-1]
|
||||||
|
image_list = []
|
||||||
|
current_placeholder_index = 0
|
||||||
|
# 切分换行,每行为单张图片
|
||||||
|
for s in new_text.split("\n"):
|
||||||
|
_tmp_text = s
|
||||||
|
img_height = BuildImage(0, 0, font_size=font_size).getsize("正")[1]
|
||||||
|
img_width = 0
|
||||||
|
_tmp_index = current_placeholder_index
|
||||||
|
for _ in range(s.count("[placeholder_")):
|
||||||
|
placeholder = _data[_tmp_index]
|
||||||
|
if "font_size" in placeholder[2]:
|
||||||
|
r = re.search(r"font_size=['\"]?(\d+)", placeholder[2])
|
||||||
|
if r:
|
||||||
|
w, h = BuildImage(0, 0, font_size=int(r.group(1))).getsize(
|
||||||
|
placeholder[3]
|
||||||
|
)
|
||||||
|
img_height = img_height if img_height > h else h
|
||||||
|
img_width += w
|
||||||
|
else:
|
||||||
|
img_width += BuildImage(0, 0, font_size=font_size).getsize(
|
||||||
|
placeholder[3]
|
||||||
|
)[0]
|
||||||
|
_tmp_text = _tmp_text.replace(f"[placeholder_{_tmp_index}]", "")
|
||||||
|
_tmp_index += 1
|
||||||
|
img_width += BuildImage(0, 0, font_size=font_size).getsize(_tmp_text)[0]
|
||||||
|
# img_width += len(_tmp_text) * font_size
|
||||||
|
# 开始画图
|
||||||
|
A = BuildImage(
|
||||||
|
img_width, img_height, color=color, font=font, font_size=font_size
|
||||||
|
)
|
||||||
|
basic_font_h = A.getsize("正")[1]
|
||||||
|
current_width = 0
|
||||||
|
# 遍历占位符
|
||||||
|
for _ in range(s.count("[placeholder_")):
|
||||||
|
if not s.startswith(f"[placeholder_{current_placeholder_index}]"):
|
||||||
|
slice_ = s.split(f"[placeholder_{current_placeholder_index}]")
|
||||||
|
await A.atext(
|
||||||
|
(current_width, A.h - basic_font_h - 1), slice_[0], font_color
|
||||||
|
)
|
||||||
|
current_width += A.getsize(slice_[0])[0]
|
||||||
|
placeholder = _data[current_placeholder_index]
|
||||||
|
# 解析配置
|
||||||
|
_font = font
|
||||||
|
_font_size = font_size
|
||||||
|
_font_color = font_color
|
||||||
|
for e in placeholder[2].split():
|
||||||
|
if e.startswith("font="):
|
||||||
|
_font = e.split("=")[-1]
|
||||||
|
if e.startswith("font_size=") or e.startswith("fs="):
|
||||||
|
_font_size = int(e.split("=")[-1])
|
||||||
|
if _font_size > 1000:
|
||||||
|
_font_size = 1000
|
||||||
|
if _font_size < 1:
|
||||||
|
_font_size = 1
|
||||||
|
if e.startswith("font_color") or e.startswith("fc="):
|
||||||
|
_font_color = e.split("=")[-1]
|
||||||
|
text_img = BuildImage(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
plain_text=placeholder[3],
|
||||||
|
font_size=_font_size,
|
||||||
|
font_color=_font_color,
|
||||||
|
font=_font,
|
||||||
|
)
|
||||||
|
_img_h = (
|
||||||
|
int(A.h / 2 - text_img.h / 2)
|
||||||
|
if new_text == "[placeholder_0]"
|
||||||
|
else A.h - text_img.h
|
||||||
|
)
|
||||||
|
await A.apaste(text_img, (current_width, _img_h - 1), True)
|
||||||
|
current_width += text_img.w
|
||||||
|
s = s[
|
||||||
|
s.index(f"[placeholder_{current_placeholder_index}]")
|
||||||
|
+ len(f"[placeholder_{current_placeholder_index}]") :
|
||||||
|
]
|
||||||
|
current_placeholder_index += 1
|
||||||
|
if s:
|
||||||
|
slice_ = s.split(f"[placeholder_{current_placeholder_index}]")
|
||||||
|
await A.atext((current_width, A.h - basic_font_h), slice_[0])
|
||||||
|
current_width += A.getsize(slice_[0])[0]
|
||||||
|
A.crop((0, 0, current_width, A.h))
|
||||||
|
# A.show()
|
||||||
|
image_list.append(A)
|
||||||
|
height = 0
|
||||||
|
width = 0
|
||||||
|
for img in image_list:
|
||||||
|
height += img.h
|
||||||
|
width = width if width > img.w else img.w
|
||||||
|
width += pw
|
||||||
|
height += ph
|
||||||
|
A = BuildImage(width + left_padding, height + top_padding, color=color)
|
||||||
|
current_height = top_padding
|
||||||
|
for img in image_list:
|
||||||
|
await A.apaste(img, (left_padding, current_height), True)
|
||||||
|
current_height += img.h
|
||||||
|
else:
|
||||||
|
width = 0
|
||||||
|
height = 0
|
||||||
|
_tmp = BuildImage(0, 0, font_size=font_size)
|
||||||
|
for x in text.split("\n"):
|
||||||
|
w, h = _tmp.getsize(x)
|
||||||
|
height += h
|
||||||
|
width = width if width > w else w
|
||||||
|
width += pw
|
||||||
|
height += ph
|
||||||
|
A = BuildImage(
|
||||||
|
width + left_padding,
|
||||||
|
height + top_padding,
|
||||||
|
font_size=font_size,
|
||||||
|
color=color,
|
||||||
|
font=font,
|
||||||
|
)
|
||||||
|
await A.atext((left_padding, top_padding), text, font_color)
|
||||||
|
# A.show()
|
||||||
|
return A.pic2bs4()
|
||||||
|
|
||||||
|
|
||||||
class BuildImage:
|
class BuildImage:
|
||||||
"""
|
"""
|
||||||
快捷生成图片与操作图片的工具类
|
快捷生成图片与操作图片的工具类
|
||||||
@@ -155,7 +336,7 @@ class BuildImage:
|
|||||||
ratio: float = 1,
|
ratio: float = 1,
|
||||||
is_alpha: bool = False,
|
is_alpha: bool = False,
|
||||||
plain_text: Optional[str] = None,
|
plain_text: Optional[str] = None,
|
||||||
font_color: Optional[Tuple[int, int, int]] = None,
|
font_color: Optional[Union[str, Tuple[int, int, int]]] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
参数:
|
参数:
|
||||||
@@ -167,7 +348,7 @@ class BuildImage:
|
|||||||
:param image_mode: 图片的类型
|
:param image_mode: 图片的类型
|
||||||
:param font_size: 文字大小
|
:param font_size: 文字大小
|
||||||
:param background: 打开图片的路径
|
:param background: 打开图片的路径
|
||||||
:param ttf: 字体,默认在 resource/ttf/ 路径下
|
:param font: 字体,默认在 resource/ttf/ 路径下
|
||||||
:param ratio: 倍率压缩
|
:param ratio: 倍率压缩
|
||||||
:param is_alpha: 是否背景透明
|
:param is_alpha: 是否背景透明
|
||||||
:param plain_text: 纯文字文本
|
:param plain_text: 纯文字文本
|
||||||
@@ -181,6 +362,7 @@ class BuildImage:
|
|||||||
self.font = ImageFont.truetype(FONT_PATH + font, int(font_size))
|
self.font = ImageFont.truetype(FONT_PATH + font, int(font_size))
|
||||||
if not plain_text and not color:
|
if not plain_text and not color:
|
||||||
color = (255, 255, 255)
|
color = (255, 255, 255)
|
||||||
|
self.background = background
|
||||||
if not background:
|
if not background:
|
||||||
if plain_text:
|
if plain_text:
|
||||||
if not color:
|
if not color:
|
||||||
@@ -367,7 +549,7 @@ class BuildImage:
|
|||||||
self,
|
self,
|
||||||
pos: Tuple[int, int],
|
pos: Tuple[int, int],
|
||||||
text: str,
|
text: str,
|
||||||
fill: Tuple[int, int, int] = (0, 0, 0),
|
fill: Union[str, Tuple[int, int, int]] = (0, 0, 0),
|
||||||
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
|
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@@ -385,7 +567,7 @@ class BuildImage:
|
|||||||
self,
|
self,
|
||||||
pos: Tuple[int, int],
|
pos: Tuple[int, int],
|
||||||
text: str,
|
text: str,
|
||||||
fill: Tuple[int, int, int] = (0, 0, 0),
|
fill: Union[str, Tuple[int, int, int]] = (0, 0, 0),
|
||||||
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
|
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@@ -416,7 +598,7 @@ class BuildImage:
|
|||||||
pos = (w, h)
|
pos = (w, h)
|
||||||
self.draw.text(pos, text, fill=fill, font=self.font)
|
self.draw.text(pos, text, fill=fill, font=self.font)
|
||||||
|
|
||||||
async def asave(self, path: Union[str, Path]):
|
async def asave(self, path: Optional[Union[str, Path]] = None):
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
异步 保存图片
|
异步 保存图片
|
||||||
@@ -425,15 +607,15 @@ class BuildImage:
|
|||||||
"""
|
"""
|
||||||
await self.loop.run_in_executor(None, self.save, path)
|
await self.loop.run_in_executor(None, self.save, path)
|
||||||
|
|
||||||
def save(self, path: Union[str, Path]):
|
def save(self, path: Optional[Union[str, Path]] = None):
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
保存图片
|
保存图片
|
||||||
参数:
|
参数:
|
||||||
:param path: 图片路径
|
:param path: 图片路径
|
||||||
"""
|
"""
|
||||||
if isinstance(path, Path):
|
if not path:
|
||||||
path = path.absolute()
|
path = self.background
|
||||||
self.markImg.save(path)
|
self.markImg.save(path)
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
@@ -620,7 +802,7 @@ class BuildImage:
|
|||||||
async def aline(
|
async def aline(
|
||||||
self,
|
self,
|
||||||
xy: Tuple[int, int, int, int],
|
xy: Tuple[int, int, int, int],
|
||||||
fill: Optional[Tuple[int, int, int]] = None,
|
fill: Optional[Union[str, Tuple[int, int, int]]] = None,
|
||||||
width: int = 1,
|
width: int = 1,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@@ -636,7 +818,7 @@ class BuildImage:
|
|||||||
def line(
|
def line(
|
||||||
self,
|
self,
|
||||||
xy: Tuple[int, int, int, int],
|
xy: Tuple[int, int, int, int],
|
||||||
fill: Optional[Tuple[int, int, int]] = None,
|
fill: Optional[Union[Tuple[int, int, int], str]] = None,
|
||||||
width: int = 1,
|
width: int = 1,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@@ -674,8 +856,8 @@ class BuildImage:
|
|||||||
for j in range(r2):
|
for j in range(r2):
|
||||||
lx = abs(i - r) # 到圆心距离的横坐标
|
lx = abs(i - r) # 到圆心距离的横坐标
|
||||||
ly = abs(j - r) # 到圆心距离的纵坐标
|
ly = abs(j - r) # 到圆心距离的纵坐标
|
||||||
l = (pow(lx, 2) + pow(ly, 2)) ** 0.5 # 三角函数 半径
|
l_ = (pow(lx, 2) + pow(ly, 2)) ** 0.5 # 三角函数 半径
|
||||||
if l < r3:
|
if l_ < r3:
|
||||||
pim_b[i - (r - r3), j - (r - r3)] = pim_a[i, j]
|
pim_b[i - (r - r3), j - (r - r3)] = pim_a[i, j]
|
||||||
self.markImg = imb
|
self.markImg = imb
|
||||||
|
|
||||||
@@ -784,6 +966,58 @@ class BuildImage:
|
|||||||
self.markImg = self.markImg.filter(_x)
|
self.markImg = self.markImg.filter(_x)
|
||||||
self.draw = ImageDraw.Draw(self.markImg)
|
self.draw = ImageDraw.Draw(self.markImg)
|
||||||
|
|
||||||
|
async def areplace_color_tran(
|
||||||
|
self,
|
||||||
|
src_color: Union[
|
||||||
|
Tuple[int, int, int], Tuple[Tuple[int, int, int], Tuple[int, int, int]]
|
||||||
|
],
|
||||||
|
replace_color: Tuple[int, int, int],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
异步 颜色替换
|
||||||
|
参数:
|
||||||
|
:param src_color: 目标颜色,或者使用列表,设置阈值
|
||||||
|
:param replace_color: 替换颜色
|
||||||
|
"""
|
||||||
|
self.loop.run_in_executor(
|
||||||
|
None, self.replace_color_tran, src_color, replace_color
|
||||||
|
)
|
||||||
|
|
||||||
|
def replace_color_tran(
|
||||||
|
self,
|
||||||
|
src_color: Union[
|
||||||
|
Tuple[int, int, int], Tuple[Tuple[int, int, int], Tuple[int, int, int]]
|
||||||
|
],
|
||||||
|
replace_color: Tuple[int, int, int],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
颜色替换
|
||||||
|
参数:
|
||||||
|
:param src_color: 目标颜色,或者使用元祖,设置阈值
|
||||||
|
:param replace_color: 替换颜色
|
||||||
|
"""
|
||||||
|
if isinstance(src_color, tuple):
|
||||||
|
start_ = src_color[0]
|
||||||
|
end_ = src_color[1]
|
||||||
|
else:
|
||||||
|
start_ = src_color
|
||||||
|
end_ = None
|
||||||
|
for i in range(self.w):
|
||||||
|
for j in range(self.h):
|
||||||
|
r, g, b = self.markImg.getpixel((i, j))
|
||||||
|
if not end_:
|
||||||
|
if r == start_[0] and g == start_[1] and b == start_[2]:
|
||||||
|
self.markImg.putpixel((i, j), replace_color)
|
||||||
|
else:
|
||||||
|
if (
|
||||||
|
start_[0] <= r <= end_[0]
|
||||||
|
and start_[1] <= g <= end_[1]
|
||||||
|
and start_[2] <= b <= end_[2]
|
||||||
|
):
|
||||||
|
self.markImg.putpixel((i, j), replace_color)
|
||||||
|
|
||||||
#
|
#
|
||||||
def getchannel(self, type_):
|
def getchannel(self, type_):
|
||||||
self.markImg = self.markImg.getchannel(type_)
|
self.markImg = self.markImg.getchannel(type_)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class AdminManager(StaticData):
|
|||||||
|
|
||||||
def get_plugin_module(self, cmd: str) -> Optional[str]:
|
def get_plugin_module(self, cmd: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
根据 cmd 获取功能 module
|
根据 cmd 获取功能 modules
|
||||||
:param cmd: 命令
|
:param cmd: 命令
|
||||||
"""
|
"""
|
||||||
for key in self._data.keys():
|
for key in self._data.keys():
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#
|
#
|
||||||
# def add_plugin_config(
|
# def add_plugin_config(
|
||||||
# self,
|
# self,
|
||||||
# module: str,
|
# modules: str,
|
||||||
# key: str,
|
# key: str,
|
||||||
# value: str,
|
# value: str,
|
||||||
# help_: Optional[str] = None,
|
# help_: Optional[str] = None,
|
||||||
@@ -26,39 +26,39 @@
|
|||||||
# ):
|
# ):
|
||||||
# """
|
# """
|
||||||
# 为插件添加一个配置
|
# 为插件添加一个配置
|
||||||
# :param module: 模块
|
# :param modules: 模块
|
||||||
# :param key: 键
|
# :param key: 键
|
||||||
# :param value: 值
|
# :param value: 值
|
||||||
# :param help_: 配置注解
|
# :param help_: 配置注解
|
||||||
# :param default_value: 默认值
|
# :param default_value: 默认值
|
||||||
# """
|
# """
|
||||||
# if self._data.get(module) is None:
|
# if self._data.get(modules) is None:
|
||||||
# self._data[module] = {}
|
# self._data[modules] = {}
|
||||||
# self._data[module][key] = {
|
# self._data[modules][key] = {
|
||||||
# "value": value,
|
# "value": value,
|
||||||
# "help": help_,
|
# "help": help_,
|
||||||
# "default_value": default_value,
|
# "default_value": default_value,
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# def remove_plugin_config(self, module: str):
|
# def remove_plugin_config(self, modules: str):
|
||||||
# """
|
# """
|
||||||
# 为插件删除一个配置
|
# 为插件删除一个配置
|
||||||
# :param module: 模块名
|
# :param modules: 模块名
|
||||||
# """
|
# """
|
||||||
# if module in self._data.keys():
|
# if modules in self._data.keys():
|
||||||
# del self._data[module]
|
# del self._data[modules]
|
||||||
#
|
#
|
||||||
# def get_config(self, module: str, key: str) -> Optional[Any]:
|
# def get_config(self, modules: str, key: str) -> Optional[Any]:
|
||||||
# """
|
# """
|
||||||
# 获取指定配置值
|
# 获取指定配置值
|
||||||
# :param module: 模块名
|
# :param modules: 模块名
|
||||||
# :param key: 配置名称
|
# :param key: 配置名称
|
||||||
# """
|
# """
|
||||||
# if module in self._data.keys():
|
# if modules in self._data.keys():
|
||||||
# if self._data[module].get(key):
|
# if self._data[modules].get(key):
|
||||||
# if self._data[module][key]["value"] is None:
|
# if self._data[modules][key]["value"] is None:
|
||||||
# return self._data[module][key]["default_value"]
|
# return self._data[modules][key]["default_value"]
|
||||||
# return self._data[module][key]["value"]
|
# return self._data[modules][key]["value"]
|
||||||
# return None
|
# return None
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ class Plugins2settingsManager(StaticData):
|
|||||||
self._data = (
|
self._data = (
|
||||||
self._data["PluginSettings"] if self._data["PluginSettings"] else {}
|
self._data["PluginSettings"] if self._data["PluginSettings"] else {}
|
||||||
)
|
)
|
||||||
|
for x in self._data.keys():
|
||||||
|
if self._data[x].get("cost_gold") is None:
|
||||||
|
self._data[x]["cost_gold"] = 0
|
||||||
|
|
||||||
def add_plugin_settings(
|
def add_plugin_settings(
|
||||||
self,
|
self,
|
||||||
@@ -30,7 +33,8 @@ class Plugins2settingsManager(StaticData):
|
|||||||
level: Optional[int] = 5,
|
level: Optional[int] = 5,
|
||||||
limit_superuser: Optional[bool] = False,
|
limit_superuser: Optional[bool] = False,
|
||||||
plugin_type: Tuple[Union[str, int]] = ("normal",),
|
plugin_type: Tuple[Union[str, int]] = ("normal",),
|
||||||
data_dict: Optional[dict] = None,
|
cost_gold: int = 0,
|
||||||
|
**kwargs
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
添加一个插件设置
|
添加一个插件设置
|
||||||
@@ -40,21 +44,22 @@ class Plugins2settingsManager(StaticData):
|
|||||||
:param level: 功能权限等级
|
:param level: 功能权限等级
|
||||||
:param limit_superuser: 功能状态是否限制超级用户
|
:param limit_superuser: 功能状态是否限制超级用户
|
||||||
:param plugin_type: 插件类型
|
:param plugin_type: 插件类型
|
||||||
:param data_dict: 封装好的字典数据
|
:param cost_gold: 需要消费的金币
|
||||||
"""
|
"""
|
||||||
if data_dict:
|
if kwargs:
|
||||||
level = data_dict.get("level") if data_dict.get("level") is not None else 5
|
level = kwargs.get("level") if kwargs.get("level") is not None else 5
|
||||||
default_status = (
|
default_status = (
|
||||||
data_dict.get("default_status")
|
kwargs.get("default_status")
|
||||||
if data_dict.get("default_status") is not None
|
if kwargs.get("default_status") is not None
|
||||||
else True
|
else True
|
||||||
)
|
)
|
||||||
limit_superuser = (
|
limit_superuser = (
|
||||||
data_dict.get("limit_superuser")
|
kwargs.get("limit_superuser")
|
||||||
if data_dict.get("limit_superuser") is not None
|
if kwargs.get("limit_superuser") is not None
|
||||||
else False
|
else False
|
||||||
)
|
)
|
||||||
cmd = data_dict.get("cmd") if data_dict.get("cmd") is not None else []
|
cmd = kwargs.get("cmd") if kwargs.get("cmd") is not None else []
|
||||||
|
cost_gold = cost_gold if kwargs.get("cost_gold") else 0
|
||||||
self._data[plugin] = {
|
self._data[plugin] = {
|
||||||
"level": level if level is not None else 5,
|
"level": level if level is not None else 5,
|
||||||
"default_status": default_status if default_status is not None else True,
|
"default_status": default_status if default_status is not None else True,
|
||||||
@@ -65,6 +70,7 @@ class Plugins2settingsManager(StaticData):
|
|||||||
"plugin_type": list(
|
"plugin_type": list(
|
||||||
plugin_type if plugin_type is not None else ("normal",)
|
plugin_type if plugin_type is not None else ("normal",)
|
||||||
),
|
),
|
||||||
|
"cost_gold": cost_gold,
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_plugin_data(self, module: str) -> dict:
|
def get_plugin_data(self, module: str) -> dict:
|
||||||
@@ -80,7 +86,7 @@ class Plugins2settingsManager(StaticData):
|
|||||||
self, cmd: str, is_all: bool = False
|
self, cmd: str, is_all: bool = False
|
||||||
) -> Union[str, List[str]]:
|
) -> Union[str, List[str]]:
|
||||||
"""
|
"""
|
||||||
根据 cmd 获取功能 module
|
根据 cmd 获取功能 modules
|
||||||
:param cmd: 命令
|
:param cmd: 命令
|
||||||
:param is_all: 获取全部包含cmd的模块
|
:param is_all: 获取全部包含cmd的模块
|
||||||
"""
|
"""
|
||||||
|
|||||||
+1
-1
@@ -208,7 +208,7 @@ def get_message_at(data: str) -> List[int]:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def get_message_imgs(data: str) -> List[str]:
|
def get_message_img(data: str) -> List[str]:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
获取消息中所有的 图片 的链接
|
获取消息中所有的 图片 的链接
|
||||||
|
|||||||
Reference in New Issue
Block a user