mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 06:12:53 +08:00
update v0.0.8.0
This commit is contained in:
parent
5e5168f804
commit
30b56583bd
4
.gitignore
vendored
4
.gitignore
vendored
@ -142,4 +142,6 @@ test.py
|
||||
server.py
|
||||
member_activity_handle.py
|
||||
Yu-Gi-Oh/
|
||||
|
||||
search_image/
|
||||
black_word/
|
||||
csgo/
|
||||
|
||||
401
README.md
401
README.md
@ -20,7 +20,7 @@
|
||||
|
||||
## 未完成的文档
|
||||
|
||||
[传送门](https://hibikier.github.io/zhenxun_bot/)
|
||||
# [传送门](https://hibikier.github.io/zhenxun_bot/)
|
||||
|
||||
## 真寻的帮助
|
||||
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
|
||||
@ -29,6 +29,17 @@
|
||||
|
||||
[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
|
||||
|
||||
## 来点优点?
|
||||
一.作为bot:
|
||||
* 实现了许多功能,且提供了大量功能管理命令
|
||||
* __..... 更多详细请通过`传送门`查看文档!__
|
||||
|
||||
二.作为框架?:
|
||||
* 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改
|
||||
* 方便增删插件,原生nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
|
||||
* 提供了cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`__plugin_cd_limit__`
|
||||
* __..... 更多详细请通过`传送门`查看文档!__
|
||||
|
||||
|
||||
## 功能列表
|
||||
<details>
|
||||
@ -210,6 +221,20 @@ python bot.py
|
||||
|
||||
## 更新
|
||||
|
||||
### 2021/1/5 \[v0.0.7.2]
|
||||
|
||||
* 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币
|
||||
* 商店插件将作为内置插件移动至basic_plugins
|
||||
* 商店插件通过export提供了方法,不需要修改商店插件代码添加商品数据和生效方法
|
||||
* 修改了hook插件顺序,主要以auth_hook为主
|
||||
* 修改商店图片样式
|
||||
* 取消每次启动更新城市列表(首次除外),采用定时更新,加快bot启动速度
|
||||
* 取消每次启动时截取今日素材,采用调用时截取保存,加快bot启动速度
|
||||
* 更新色图时当图片404时会删除并替换
|
||||
* 疫情消息回复改为图片
|
||||
* 修复商店折扣和限时时间无法生效
|
||||
* 修复原神玩家查询尘歌壶缺少图片
|
||||
|
||||
### 2021/12/26
|
||||
|
||||
* 修复群词条问题 空格 会被录入导致不断回复
|
||||
@ -221,7 +246,7 @@ python bot.py
|
||||
|
||||
### 2021/12/20
|
||||
|
||||
* 只有当真的发布新动态/视频的时候才获取并推送 [@pull/96](https://github.com/HibiKier/zhenxun_bot/pull/96)
|
||||
* 只有发布小于存储时间的新动态/视频的时候才获取并推送 [@pull/96](https://github.com/HibiKier/zhenxun_bot/pull/96)
|
||||
|
||||
### 2021/12/16 \[v0.0.7.0]
|
||||
|
||||
@ -246,366 +271,26 @@ python bot.py
|
||||
* 修改了权限插件加载顺序防止小概率优先加载权限插件引起报错
|
||||
* 本地图库新图库会统一建立在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
|
||||
- [ ] 提供更多对插件的控制
|
||||
- [ ] 明日方舟卡片式的签到..(大概)
|
||||
- [ ] 更多的群管理功能
|
||||
- [ ] 数据清理控制
|
||||
- [ ] docker容器
|
||||
- [ ] web管理
|
||||
|
||||
## 感谢
|
||||
[Onebot](https://github.com/howmanybots/onebot)
|
||||
[go-cqhttp](https://github.com/Mrs4s/go-cqhttp)
|
||||
[nonebot2](https://github.com/nonebot/nonebot2)
|
||||
[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)
|
||||
[cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins#%E7%94%9F%E6%88%90%E5%99%A8%E6%8F%92%E4%BB%B6)
|
||||
[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)
|
||||
[nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)
|
||||
[nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager)
|
||||
[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)
|
||||
[nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says)
|
||||
[AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus)
|
||||
[omega-miya](https://github.com/Ailitonia/omega-miya)
|
||||
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
|
||||
[Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台.
|
||||
[nonebot / nonebot2](https://github.com/nonebot/nonebot2) :跨平台Python异步机器人框架
|
||||
[Angel-Hair / XUN_Bot](https://github.com/Angel-Hair/XUN_Bot) :一个基于NoneBot和酷Q的功能性QQ机器人
|
||||
[pcrbot / cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins) :hoshino插件合集
|
||||
[MeetWq /nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw) :A simple withdraw plugin for Nonebot2
|
||||
[maxesisn / nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) :适用于nonebot2的点歌插件
|
||||
[nonepkg / nonebot-plugin-manager](https://github.com/nonepkg/nonebot-plugin-manager) :Nonebot Plugin Manager base on import hook
|
||||
[H-K-Y / Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot) :原神bot,这是一个基于nonebot和HoshinoBot的原神娱乐及信息查询插件
|
||||
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
|
||||
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
|
||||
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
|
||||
[KimigaiiWuyi / GenshinUID]("https://github.com/KimigaiiWuyi/GenshinUID") :一个基于HoshinoBot/NoneBot2的原神UID查询插件
|
||||
|
||||
@ -1 +1 @@
|
||||
__version__: v0.0.7.1
|
||||
__version__: v0.0.8.0
|
||||
|
||||
@ -1,19 +1,29 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.bag_user import BagUser
|
||||
from utils.manager import (
|
||||
plugins2settings_manager,
|
||||
admin_manager,
|
||||
group_manager,
|
||||
plugins_manager,
|
||||
plugins2cd_manager,
|
||||
plugins2block_manager,
|
||||
plugins2count_manager
|
||||
)
|
||||
from .utils import set_block_limit_false, status_message_manager
|
||||
from nonebot.typing import T_State
|
||||
from typing import Optional
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
PokeNotifyEvent
|
||||
PokeNotifyEvent,
|
||||
PrivateMessageEvent,
|
||||
Message,
|
||||
Event
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
@ -22,13 +32,11 @@ from utils.message_builder import at
|
||||
from models.level_user import LevelUser
|
||||
import nonebot
|
||||
|
||||
|
||||
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
|
||||
|
||||
ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
|
||||
|
||||
@ -37,15 +45,27 @@ ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
module = matcher.module
|
||||
plugins2info_dict = plugins2settings_manager.get_data()
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
cost_gold = 0
|
||||
if isinstance(event, GroupMessageEvent) and plugins2settings_manager.get_plugin_data(module).get('cost_gold'):
|
||||
cost_gold = plugins2settings_manager.get_plugin_data(module).get('cost_gold')
|
||||
if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
|
||||
await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
|
||||
raise IgnoredException(f"{module} 金币限制...")
|
||||
# 当插件不阻塞超级用户时,超级用户提前扣除金币
|
||||
if str(event.user_id) in bot.config.superusers and not plugins2info_dict[module]["limit_superuser"]:
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
try:
|
||||
if (
|
||||
(not isinstance(event, MessageEvent) and module != "poke")
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
(not isinstance(event, MessageEvent) and module != "poke")
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
) or (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
@ -56,8 +76,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
_module = _plugin.module
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if (
|
||||
"[superuser]" in plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
"[superuser]" in plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
@ -79,12 +99,12 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
# 个人权限
|
||||
if (
|
||||
not await LevelUser.check_level(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
admin_manager.get_plugin_level(module),
|
||||
)
|
||||
and admin_manager.get_plugin_level(module) > 0
|
||||
not await LevelUser.check_level(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
admin_manager.get_plugin_level(module),
|
||||
)
|
||||
and admin_manager.get_plugin_level(module) > 0
|
||||
):
|
||||
try:
|
||||
if _flmt.check(event.user_id):
|
||||
@ -92,7 +112,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
|
||||
f"{admin_manager.get_plugin_level(module)}",
|
||||
f"{admin_manager.get_plugin_level(module)}",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
@ -102,7 +122,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
raise IgnoredException("权限不足")
|
||||
else:
|
||||
if not await LevelUser.check_level(
|
||||
event.user_id, 0, admin_manager.get_plugin_level(module)
|
||||
event.user_id, 0, admin_manager.get_plugin_level(module)
|
||||
):
|
||||
try:
|
||||
await bot.send_private_msg(
|
||||
@ -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 isinstance(event, GroupMessageEvent) or (
|
||||
isinstance(event, PokeNotifyEvent) and event.group_id
|
||||
isinstance(event, PokeNotifyEvent) and event.group_id
|
||||
):
|
||||
if status_message_manager.get(event.group_id) is None:
|
||||
status_message_manager.delete(event.group_id)
|
||||
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
|
||||
event.group_id
|
||||
event.group_id
|
||||
):
|
||||
try:
|
||||
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
|
||||
@ -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):
|
||||
try:
|
||||
if module not in ignore_rst_module and _flmt_s.check(
|
||||
event.group_id
|
||||
event.group_id
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@ -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):
|
||||
try:
|
||||
if (
|
||||
_flmt_s.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
_flmt_s.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@ -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"):
|
||||
try:
|
||||
if (
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@ -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 isinstance(
|
||||
event, GroupMessageEvent
|
||||
event, GroupMessageEvent
|
||||
) and group_manager.check_group_is_white(event.group_id):
|
||||
return
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if (
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@ -233,3 +253,154 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
status_message_manager.add(id_)
|
||||
set_block_limit_false(event, module)
|
||||
raise IgnoredException("此功能正在维护...")
|
||||
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
# 以下为限制检测 #######################################################
|
||||
|
||||
# Cd
|
||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||
check_type = plugin_cd_data["check_type"]
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(module, cd_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(module, cd_type_)
|
||||
module = matcher.module
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
and status_message_manager.get(event.group_id) is None
|
||||
):
|
||||
status_message_manager.delete(event.group_id)
|
||||
# Cd
|
||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||
check_type = plugin_cd_data["check_type"]
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(module, cd_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(module, cd_type_)
|
||||
# Block
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
rst = plugin_block_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or check_type == "all"
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
if plugins2block_manager.check(block_type_, module):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{event.user_id}正在调用{module}....")
|
||||
else:
|
||||
plugins2block_manager.set_true(block_type_, module)
|
||||
# Count
|
||||
if (
|
||||
plugins2count_manager.check_plugin_count_status(module)
|
||||
and event.user_id not in bot.config.superusers
|
||||
):
|
||||
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
|
||||
limit_type = plugin_count_data["limit_type"]
|
||||
rst = plugin_count_data["rst"]
|
||||
count_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
count_type_ = event.group_id
|
||||
if not plugins2count_manager.check(module, count_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} count次数限制...")
|
||||
else:
|
||||
plugins2count_manager.increase(module, count_type_)
|
||||
# 功能花费的金币 #######################################
|
||||
# 功能花费的金币 #######################################
|
||||
if cost_gold:
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
|
||||
|
||||
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
发送信息
|
||||
:param rst: pass
|
||||
:param bot: pass
|
||||
:param event: pass
|
||||
"""
|
||||
rst = await init_rst(rst, event)
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
status_message_manager.add(event.group_id)
|
||||
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
|
||||
else:
|
||||
status_message_manager.add(event.user_id)
|
||||
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
|
||||
except ActionFailed:
|
||||
pass
|
||||
|
||||
|
||||
# 解除命令block阻塞
|
||||
@run_postprocessor
|
||||
async def _(
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception],
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
):
|
||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
||||
return
|
||||
module = matcher.module
|
||||
set_block_limit_false(event, module)
|
||||
|
||||
|
||||
async def init_rst(rst: str, event: MessageEvent):
|
||||
if "[uname]" in rst:
|
||||
uname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
rst = rst.replace("[uname]", uname)
|
||||
if "[nickname]" in rst:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
else:
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
rst = rst.replace("[nickname]", nickname)
|
||||
if "[at]" in rst and isinstance(event, GroupMessageEvent):
|
||||
rst = rst.replace("[at]", str(at(event.user_id)))
|
||||
return rst
|
||||
|
||||
|
||||
@ -1,146 +0,0 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from utils.message_builder import at
|
||||
from .utils import status_message_manager, set_block_limit_false
|
||||
from utils.manager import (
|
||||
plugins2cd_manager,
|
||||
plugins2block_manager,
|
||||
plugins2count_manager,
|
||||
)
|
||||
from typing import Optional
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import (
|
||||
Bot,
|
||||
Event,
|
||||
MessageEvent,
|
||||
PrivateMessageEvent,
|
||||
GroupMessageEvent,
|
||||
Message,
|
||||
)
|
||||
|
||||
|
||||
# 命令cd | 命令阻塞 | 命令次数
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
||||
return
|
||||
module = matcher.module
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
and status_message_manager.get(event.group_id) is None
|
||||
):
|
||||
status_message_manager.delete(event.group_id)
|
||||
# Count
|
||||
if (
|
||||
plugins2count_manager.check_plugin_count_status(module)
|
||||
and event.user_id not in bot.config.superusers
|
||||
):
|
||||
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
|
||||
limit_type = plugin_count_data["limit_type"]
|
||||
rst = plugin_count_data["rst"]
|
||||
count_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
count_type_ = event.group_id
|
||||
if not plugins2count_manager.check(module, count_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} count次数限制...")
|
||||
else:
|
||||
plugins2count_manager.increase(module, count_type_)
|
||||
# Cd
|
||||
if plugins2cd_manager.check_plugin_cd_status(module):
|
||||
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
|
||||
check_type = plugin_cd_data["check_type"]
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
cd_type_ = event.group_id
|
||||
if not plugins2cd_manager.check(module, cd_type_):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{module} 正在cd中...")
|
||||
else:
|
||||
plugins2cd_manager.start_cd(module, cd_type_)
|
||||
# Block
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
rst = plugin_block_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or check_type == "all"
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
if plugins2block_manager.check(block_type_, module):
|
||||
if rst:
|
||||
rst = await init_rst(rst, event)
|
||||
await send_msg(rst, bot, event)
|
||||
raise IgnoredException(f"{event.user_id}正在调用{module}....")
|
||||
else:
|
||||
plugins2block_manager.set_true(block_type_, module)
|
||||
|
||||
|
||||
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
|
||||
"""
|
||||
发送信息
|
||||
:param rst: pass
|
||||
:param bot: pass
|
||||
:param event: pass
|
||||
"""
|
||||
rst = await init_rst(rst, event)
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
status_message_manager.add(event.group_id)
|
||||
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
|
||||
else:
|
||||
status_message_manager.add(event.user_id)
|
||||
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
|
||||
except ActionFailed:
|
||||
pass
|
||||
|
||||
|
||||
# 解除命令block阻塞
|
||||
@run_postprocessor
|
||||
async def _(
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception],
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
):
|
||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
||||
return
|
||||
module = matcher.module
|
||||
set_block_limit_false(event, module)
|
||||
|
||||
|
||||
async def init_rst(rst: str, event: MessageEvent):
|
||||
if "[uname]" in rst:
|
||||
uname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
rst = rst.replace("[uname]", uname)
|
||||
if "[nickname]" in rst:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
else:
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
rst = rst.replace("[nickname]", nickname)
|
||||
if "[at]" in rst and isinstance(event, GroupMessageEvent):
|
||||
rst = rst.replace("[at]", str(at(event.user_id)))
|
||||
return rst
|
||||
@ -71,6 +71,8 @@ def init_plugins_settings(data_path: str):
|
||||
plugin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
if plugin_settings.get('cost_gold') is None:
|
||||
plugin_settings['cost_gold'] = 0
|
||||
if (
|
||||
plugin_settings["cmd"] is not None
|
||||
and plugin_name not in plugin_settings["cmd"]
|
||||
@ -97,7 +99,7 @@ def init_plugins_settings(data_path: str):
|
||||
plugins2settings_manager.add_plugin_settings(
|
||||
matcher.module,
|
||||
plugin_type=plugin_type,
|
||||
data_dict=plugin_settings,
|
||||
**plugin_settings,
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@ -7,6 +7,7 @@ from services.log import logger
|
||||
from configs.path_config import TEXT_PATH
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.utils import scheduler
|
||||
from pathlib import Path
|
||||
import nonebot
|
||||
|
||||
@ -27,31 +28,32 @@ async def update_city():
|
||||
"""
|
||||
china_city = Path(TEXT_PATH) / "china_city.json"
|
||||
data = {}
|
||||
try:
|
||||
res = await AsyncHttpx.get(
|
||||
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
provinces_data = json.loads(res.text)
|
||||
for province in provinces_data.keys():
|
||||
data[provinces_data[province]] = []
|
||||
if not china_city.exists():
|
||||
try:
|
||||
res = await AsyncHttpx.get(
|
||||
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
|
||||
timeout=5,
|
||||
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
city_data = json.loads(res.text)
|
||||
for city in city_data.keys():
|
||||
data[provinces_data[province]].append(city_data[city])
|
||||
with open(china_city, "w", encoding="utf8") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
logger.info("自动更新城市列表完成.....")
|
||||
except TimeoutError:
|
||||
logger.warning("自动更新城市列表超时.....")
|
||||
except ValueError:
|
||||
logger.warning("自动城市列表失败.....")
|
||||
except Exception as e:
|
||||
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
|
||||
provinces_data = json.loads(res.text)
|
||||
for province in provinces_data.keys():
|
||||
data[provinces_data[province]] = []
|
||||
res = await AsyncHttpx.get(
|
||||
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
|
||||
timeout=5,
|
||||
)
|
||||
res.encoding = "utf8"
|
||||
city_data = json.loads(res.text)
|
||||
for city in city_data.keys():
|
||||
data[provinces_data[province]].append(city_data[city])
|
||||
with open(china_city, "w", encoding="utf8") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
logger.info("自动更新城市列表完成.....")
|
||||
except TimeoutError:
|
||||
logger.warning("自动更新城市列表超时.....")
|
||||
except ValueError:
|
||||
logger.warning("自动城市列表失败.....")
|
||||
except Exception as e:
|
||||
logger.error(f"自动城市列表未知错误 {type(e)}:{e}")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
@ -101,3 +103,13 @@ async def _(bot: Bot):
|
||||
else:
|
||||
await GroupInfo.delete_group_info(group_id)
|
||||
logger.info(f"移除不存在的群聊信息:{group_id}")
|
||||
|
||||
|
||||
# 自动更新城市列表
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=6,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
await update_city()
|
||||
|
||||
2
plugins/shop/__init__.py → basic_plugins/shop/__init__.py
Executable file → Normal file
2
plugins/shop/__init__.py → basic_plugins/shop/__init__.py
Executable file → Normal file
@ -11,4 +11,4 @@ Config.add_plugin_config(
|
||||
)
|
||||
|
||||
|
||||
nonebot.load_plugins("plugins/shop")
|
||||
nonebot.load_plugins("basic_plugins/shop")
|
||||
175
plugins/shop/buy.py → basic_plugins/shop/buy.py
Executable file → Normal file
175
plugins/shop/buy.py → basic_plugins/shop/buy.py
Executable file → Normal file
@ -1,89 +1,86 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import get_message_text, is_number
|
||||
from models.bag_user import BagUser
|
||||
from services.db_context import db
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from .models.goods_info import GoodsInfo
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 购买道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
购买道具
|
||||
指令:
|
||||
购买 [序号或名称] ?[数量=1]
|
||||
示例:购买 好感双倍加持卡Ⅰ
|
||||
示例:购买 1 4
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 购买道具"
|
||||
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "购买道具"],
|
||||
}
|
||||
|
||||
|
||||
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@buy.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
if get_message_text(event.json()) in ["神秘药水"]:
|
||||
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
goods_name_lst = [x.goods_name for x in goods_lst]
|
||||
msg = get_message_text(event.json()).strip().split(" ")
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
if is_number(msg[1]) and int(msg[1]) > 0:
|
||||
num = int(msg[1])
|
||||
else:
|
||||
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
|
||||
# print(msg, num)
|
||||
if is_number(msg[0]):
|
||||
msg = int(msg[0])
|
||||
if msg > len(goods_lst) or msg < 1:
|
||||
await buy.finish("请输入正确的商品id!", at_sender=True)
|
||||
goods = goods_lst[msg - 1]
|
||||
else:
|
||||
if msg[0] in goods_name_lst:
|
||||
for i in range(len(goods_name_lst)):
|
||||
if msg[0] == goods_name_lst[i]:
|
||||
goods = goods_lst[i]
|
||||
break
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!")
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!", at_sender=True)
|
||||
async with db.transaction():
|
||||
if (
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
if await BagUser.spend_gold(
|
||||
event.user_id, event.group_id, goods.goods_price * num
|
||||
):
|
||||
for _ in range(num):
|
||||
await BagUser.add_props(event.user_id, event.group_id, goods.goods_name)
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||
)
|
||||
else:
|
||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 失败!"
|
||||
)
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import get_message_text, is_number
|
||||
from models.bag_user import BagUser
|
||||
from services.db_context import db
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from models.goods_info import GoodsInfo
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 购买道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
购买道具
|
||||
指令:
|
||||
购买 [序号或名称] ?[数量=1]
|
||||
示例:购买 好感双倍加持卡Ⅰ
|
||||
示例:购买 1 4
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 购买道具"
|
||||
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "购买道具"],
|
||||
}
|
||||
|
||||
|
||||
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@buy.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
goods = None
|
||||
if get_message_text(event.json()) in ["神秘药水"]:
|
||||
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
goods_name_lst = [x.goods_name for x in goods_lst]
|
||||
msg = get_message_text(event.json()).split()
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
if is_number(msg[1]) and int(msg[1]) > 0:
|
||||
num = int(msg[1])
|
||||
else:
|
||||
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
|
||||
# print(msg, num)
|
||||
if is_number(msg[0]):
|
||||
msg = int(msg[0])
|
||||
if msg > len(goods_lst) or msg < 1:
|
||||
await buy.finish("请输入正确的商品id!", at_sender=True)
|
||||
goods = goods_lst[msg - 1]
|
||||
else:
|
||||
if msg[0] in goods_name_lst:
|
||||
for i in range(len(goods_name_lst)):
|
||||
if msg[0] == goods_name_lst[i]:
|
||||
goods = goods_lst[i]
|
||||
break
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!")
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!", at_sender=True)
|
||||
async with db.transaction():
|
||||
if (
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num * goods.goods_discount:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
if await BagUser.buy_props(event.user_id, event.group_id, goods, num):
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||
)
|
||||
else:
|
||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 失败!"
|
||||
)
|
||||
0
plugins/shop/gold.py → basic_plugins/shop/gold.py
Executable file → Normal file
0
plugins/shop/gold.py → basic_plugins/shop/gold.py
Executable file → Normal file
104
plugins/shop/my_props.py → basic_plugins/shop/my_props.py
Executable file → Normal file
104
plugins/shop/my_props.py → basic_plugins/shop/my_props.py
Executable file → Normal file
@ -1,52 +1,52 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
我的道具
|
||||
指令:
|
||||
我的道具
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 我的道具"
|
||||
__plugin_cmd__ = ["我的道具"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "我的道具"],
|
||||
}
|
||||
|
||||
|
||||
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
pname_list = []
|
||||
pnum_list = []
|
||||
rst = ""
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p in pname_list:
|
||||
pnum_list[pname_list.index(p)] += 1
|
||||
else:
|
||||
pname_list.append(p)
|
||||
pnum_list.append(1)
|
||||
for i in range(len(pname_list)):
|
||||
rst += f"{i+1}.{pname_list[i]}\t×{pnum_list[i]}\n"
|
||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||
else:
|
||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
我的道具
|
||||
指令:
|
||||
我的道具
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 我的道具"
|
||||
__plugin_cmd__ = ["我的道具"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "我的道具"],
|
||||
}
|
||||
|
||||
|
||||
my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
pname_list = []
|
||||
pnum_list = []
|
||||
rst = ""
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p in pname_list:
|
||||
pnum_list[pname_list.index(p)] += 1
|
||||
else:
|
||||
pname_list.append(p)
|
||||
pnum_list.append(1)
|
||||
for i in range(len(pname_list)):
|
||||
rst += f"{i+1}.{pname_list[i]}\t×{pnum_list[i]}\n"
|
||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||
else:
|
||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
52
plugins/shop/reset_today_gold.py → basic_plugins/shop/reset_today_gold.py
Executable file → Normal file
52
plugins/shop/reset_today_gold.py → basic_plugins/shop/reset_today_gold.py
Executable file → Normal file
@ -1,26 +1,26 @@
|
||||
from utils.utils import scheduler
|
||||
from models.bag_user import BagUser
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "每日金币重置 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
# 重置每日金币
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=0,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
user_list = await BagUser.get_all_users()
|
||||
for user in user_list:
|
||||
await user.update(
|
||||
get_today_gold=0,
|
||||
spend_today_gold=0,
|
||||
).apply()
|
||||
except Exception as e:
|
||||
logger.error(f"重置每日金币错误 e:{e}")
|
||||
from utils.utils import scheduler
|
||||
from models.bag_user import BagUser
|
||||
from services.log import logger
|
||||
|
||||
|
||||
__zx_plugin_name__ = "每日金币重置 [Hidden]"
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
|
||||
|
||||
# 重置每日金币
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=0,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
user_list = await BagUser.get_all_users()
|
||||
for user in user_list:
|
||||
await user.update(
|
||||
get_today_gold=0,
|
||||
spend_today_gold=0,
|
||||
).apply()
|
||||
except Exception as e:
|
||||
logger.error(f"重置每日金币错误 e:{e}")
|
||||
133
basic_plugins/shop/shop_handle/__init__.py
Normal file
133
basic_plugins/shop/shop_handle/__init__.py
Normal file
@ -0,0 +1,133 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_shop_help, delete_goods, update_goods, registered_goods, parse_goods_info
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import get_message_text, is_number
|
||||
from nonebot.plugin import export
|
||||
from services.log import logger
|
||||
import os
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
商店项目,这可不是奸商
|
||||
指令:
|
||||
商店
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
usage:
|
||||
商品操作
|
||||
指令:
|
||||
添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)
|
||||
删除商品 [名称或序号]
|
||||
修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时]
|
||||
示例:添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
|
||||
示例:添加商品 name:可疑的药 price:5 des:效果未知
|
||||
示例:删除商品 2
|
||||
示例:修改商品 name:1 price:900 修改序号为1的商品的价格为900
|
||||
* 修改商品只需添加需要值即可 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店系统[金币回收计划]"
|
||||
__plugin_cmd__ = [
|
||||
"商店",
|
||||
"添加商品 name:[名称] price:[价格] des:[描述] ?discount:[折扣](小数) ?limit_time:[限时时间](小时)) [_superuser]",
|
||||
"删除商品 [名称或序号] [_superuser]",
|
||||
"修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时] [_superuser]",
|
||||
]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店"],
|
||||
}
|
||||
__plugin_block_limit__ = {
|
||||
"limit_type": "group"
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.registered_goods = registered_goods
|
||||
export.delete_goods = delete_goods
|
||||
export.update_goods = update_goods
|
||||
|
||||
shop_help = on_command("商店", priority=5, block=True)
|
||||
|
||||
shop_add_goods = on_command("添加商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
shop_del_goods = on_command("删除商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@shop_help.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await shop_help.send(image(b64=await create_shop_help()))
|
||||
|
||||
|
||||
@shop_add_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
data = parse_goods_info(msg)
|
||||
if isinstance(data, str):
|
||||
await shop_add_goods.finish(data)
|
||||
if not data.get("name") or not data.get("price") or not data.get("des"):
|
||||
await shop_add_goods.finish("name:price:des 参数不可缺少!")
|
||||
if await registered_goods(**data):
|
||||
await shop_add_goods.send(f"添加商品 {data['name']} 成功!\n"
|
||||
f"名称:{data['name']}\n"
|
||||
f"价格:{data['price']}金币\n"
|
||||
f"简介:{data['des']}\n"
|
||||
f"折扣:{data.get('discount')}\n"
|
||||
f"限时:{data.get('limit_time')}", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 添加商品 {msg} 成功")
|
||||
else:
|
||||
await shop_add_goods.send(f"添加商品 {msg} 失败了...", at_sender=True)
|
||||
logger.warning(f"USER {event.user_id} 添加商品 {msg} 失败")
|
||||
|
||||
|
||||
@shop_del_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
name = ""
|
||||
id_ = 0
|
||||
if is_number(msg):
|
||||
id_ = int(msg)
|
||||
else:
|
||||
name = msg
|
||||
rst, goods_name, code = await delete_goods(name, id_)
|
||||
if code == 200:
|
||||
await shop_del_goods.send(f"删除商品 {goods_name} 成功了...", at_sender=True)
|
||||
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
|
||||
os.remove(f"{IMAGE_PATH}/shop_help.png")
|
||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 成功")
|
||||
else:
|
||||
await shop_del_goods.send(f"删除商品 {goods_name} 失败了...", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 删除商品 {goods_name} 失败")
|
||||
|
||||
|
||||
@shop_update_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
data = parse_goods_info(msg)
|
||||
if isinstance(data, str):
|
||||
await shop_add_goods.finish(data)
|
||||
if not data.get("name"):
|
||||
await shop_add_goods.finish("name 参数不可缺少!")
|
||||
flag, name, text = await update_goods(**data)
|
||||
if flag:
|
||||
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功")
|
||||
else:
|
||||
await shop_update_goods.send(f"修改商品 {name} 失败了...", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败")
|
||||
|
||||
281
basic_plugins/shop/shop_handle/data_source.py
Normal file
281
basic_plugins/shop/shop_handle/data_source.py
Normal file
@ -0,0 +1,281 @@
|
||||
from models.goods_info import GoodsInfo
|
||||
from utils.image_utils import BuildImage
|
||||
from models.sign_group_user import SignGroupUser
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional, Union
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
from nonebot.plugin import require
|
||||
import nonebot
|
||||
import time
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
use = require("use")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def init_default_shop_goods():
|
||||
"""
|
||||
导入内置的三个商品
|
||||
"""
|
||||
|
||||
async def sign_card_1(**kwargs):
|
||||
user_id = kwargs['user_id']
|
||||
group_id = kwargs['group_id']
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.1).apply()
|
||||
|
||||
async def sign_card_2(**kwargs):
|
||||
user_id = kwargs['user_id']
|
||||
group_id = kwargs['group_id']
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.2).apply()
|
||||
|
||||
async def sign_card_3(**kwargs):
|
||||
user_id = kwargs['user_id']
|
||||
group_id = kwargs['group_id']
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=0.3).apply()
|
||||
|
||||
if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
|
||||
await registered_goods(
|
||||
"好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"
|
||||
)
|
||||
use.registered_use("好感度双倍加持卡Ⅰ", sign_card_1)
|
||||
await registered_goods("好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)")
|
||||
use.registered_use("好感度双倍加持卡Ⅱ", sign_card_2)
|
||||
await registered_goods(
|
||||
"好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"
|
||||
)
|
||||
use.registered_use("好感度双倍加持卡Ⅲ", sign_card_3)
|
||||
|
||||
|
||||
# 创建商店界面
|
||||
async def create_shop_help() -> str:
|
||||
"""
|
||||
制作商店图片
|
||||
:return: 图片base64
|
||||
"""
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
idx = 1
|
||||
_dc = {}
|
||||
font_h = BuildImage(0, 0).getsize("正")[1]
|
||||
h = 10
|
||||
_list = []
|
||||
for goods in goods_lst:
|
||||
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time:
|
||||
h += len(goods.goods_description.strip().split("\n")) * font_h + 80
|
||||
_list.append(goods)
|
||||
A = BuildImage(1000, h, color="#f9f6f2")
|
||||
current_h = 0
|
||||
for goods in _list:
|
||||
bk = BuildImage(
|
||||
700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
goods_image = BuildImage(
|
||||
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
name_image = BuildImage(
|
||||
580, 40, font_size=25, color="#e67b6b", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
await name_image.atext(
|
||||
(15, 0), f"{idx}.{goods.goods_name}", center_type="by_height"
|
||||
)
|
||||
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
|
||||
await name_image.atext((390, 0), "售价:", center_type="by_height")
|
||||
await name_image.atext(
|
||||
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
|
||||
)
|
||||
await name_image.atext(
|
||||
(
|
||||
440
|
||||
+ BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w,
|
||||
0,
|
||||
),
|
||||
" 金币",
|
||||
center_type="by_height",
|
||||
)
|
||||
await name_image.acircle_corner(5)
|
||||
await goods_image.apaste(name_image, (0, 5), True, center_type="by_width")
|
||||
await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
|
||||
await goods_image.acircle_corner(20)
|
||||
await bk.apaste(goods_image, alpha=True)
|
||||
# 添加限时图标和时间
|
||||
if goods.goods_limit_time > 0:
|
||||
_limit_time_logo = BuildImage(40, 40, background=f"{IMAGE_PATH}/other/time.png")
|
||||
await bk.apaste(_limit_time_logo, (600, 0), True)
|
||||
await bk.apaste(BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"), (640, 10), True)
|
||||
limit_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)).split()
|
||||
y_m_d = limit_time[0]
|
||||
_h_m = limit_time[1].split(":")
|
||||
h_m = _h_m[0] + "时 " + _h_m[1] + "分"
|
||||
await bk.atext((605, 38), str(y_m_d))
|
||||
await bk.atext((615, 57), str(h_m))
|
||||
await bk.aline((550, -1, 710, -1), "#a29ad6", 5)
|
||||
await bk.aline((550, 80, 710, 80), "#a29ad6", 5)
|
||||
idx += 1
|
||||
await A.apaste(bk, (0, current_h), True)
|
||||
current_h += 90
|
||||
w = 1000
|
||||
h = A.h + 230 + 100
|
||||
h = 1000 if h < 1000 else h
|
||||
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
|
||||
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
|
||||
shop.paste(A, (20, 230))
|
||||
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan.png")
|
||||
zx_img.replace_color_tran(((240, 240, 240), (255, 255, 255)), (249, 246, 242))
|
||||
await shop.apaste(zx_img, (780, 100))
|
||||
await shop.apaste(shop_logo, (450, 30), True)
|
||||
shop.text(
|
||||
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
|
||||
"注【通过 序号 或者 商品名称 购买】",
|
||||
)
|
||||
shop.text((20, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
|
||||
return shop.pic2bs4()
|
||||
|
||||
|
||||
async def registered_goods(
|
||||
name: str,
|
||||
price: int,
|
||||
des: str,
|
||||
discount: Optional[float] = 1,
|
||||
limit_time: Optional[int] = 0,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
添加商品
|
||||
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
|
||||
添加商品 name:萝莉酒杯 price:9999 des:普通的酒杯,但是里面.. discount:0.4 limit_time:90
|
||||
添加商品 name:可疑的药 price:5 des:效果未知
|
||||
:param name: 商品名称
|
||||
:param price: 商品价格
|
||||
:param des: 商品简介
|
||||
:param discount: 商品折扣
|
||||
:param limit_time: 商品限时销售时间,单位为小时
|
||||
:param kwargs: kwargs
|
||||
:return: 是否添加成功
|
||||
"""
|
||||
if kwargs:
|
||||
name = kwargs.get("name")
|
||||
price = kwargs.get("price")
|
||||
des = kwargs.get("des")
|
||||
discount = kwargs.get("discount")
|
||||
limit_time = kwargs.get("time_limit")
|
||||
limit_time = float(limit_time) if limit_time else limit_time
|
||||
discount = discount if discount is None else 1
|
||||
limit_time = int(time.time() + limit_time * 60 * 60) if limit_time is not None and limit_time != 0 else 0
|
||||
return await GoodsInfo.add_goods(
|
||||
name, int(price), des, float(discount), limit_time
|
||||
)
|
||||
|
||||
|
||||
# 删除商品
|
||||
async def delete_goods(name: str, id_: int) -> "str, str, int":
|
||||
"""
|
||||
删除商品
|
||||
:param name: 商品名称
|
||||
:param id_: 商品id
|
||||
:return: 删除状况
|
||||
"""
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
if id_:
|
||||
if id_ < 1 or id_ > len(goods_lst):
|
||||
return "序号错误,没有该序号商品...", "", 999
|
||||
goods_name = goods_lst[id_ - 1].goods_name
|
||||
if await GoodsInfo.delete_goods(goods_name):
|
||||
return f"删除商品 {goods_name} 成功!", goods_name, 200
|
||||
else:
|
||||
return f"删除商品 {goods_name} 失败!", goods_name, 999
|
||||
if name:
|
||||
if await GoodsInfo.delete_goods(name):
|
||||
return f"删除商品 {name} 成功!", name, 200
|
||||
else:
|
||||
return f"删除商品 {name} 失败!", name, 999
|
||||
|
||||
|
||||
# 更新商品信息
|
||||
async def update_goods(**kwargs) -> "str, str, int":
|
||||
"""
|
||||
更新商品信息
|
||||
:param kwargs: kwargs
|
||||
:return: 更新状况
|
||||
"""
|
||||
if kwargs:
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
if is_number(kwargs["name"]):
|
||||
if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst):
|
||||
return "序号错误,没有该序号的商品...", "", 999
|
||||
goods = goods_lst[int(kwargs["name"]) - 1]
|
||||
else:
|
||||
goods = await GoodsInfo.get_goods_info(kwargs["name"])
|
||||
if not goods:
|
||||
return "名称错误,没有该名称的商品...", "", 999
|
||||
name = goods.goods_name
|
||||
price = goods.goods_price
|
||||
des = goods.goods_description
|
||||
discount = goods.goods_discount
|
||||
limit_time = goods.goods_limit_time
|
||||
new_time = 0
|
||||
tmp = ""
|
||||
if kwargs.get("price"):
|
||||
tmp += f'价格:{price} --> {kwargs["price"]}\n'
|
||||
price = kwargs["price"]
|
||||
if kwargs.get("des"):
|
||||
tmp += f'描述:{des} --> {kwargs["des"]}\n'
|
||||
des = kwargs["des"]
|
||||
if kwargs.get("discount"):
|
||||
tmp += f'折扣:{discount} --> {kwargs["discount"]}\n'
|
||||
discount = kwargs["discount"]
|
||||
if kwargs.get("limit_time"):
|
||||
new_time = time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
time.localtime(time.time() + int(kwargs["limit_time"] * 60 * 60)),
|
||||
)
|
||||
tmp += f"折扣至: {new_time}\n"
|
||||
limit_time = kwargs["limit_time"]
|
||||
return (
|
||||
await GoodsInfo.update_goods(
|
||||
name,
|
||||
int(price),
|
||||
des,
|
||||
float(discount),
|
||||
int(time.time() + limit_time * 60 * 60 if limit_time != 0 and new_time else 0),
|
||||
),
|
||||
name,
|
||||
tmp[:-1],
|
||||
)
|
||||
|
||||
|
||||
def parse_goods_info(msg: str) -> Union[dict, str]:
|
||||
"""
|
||||
解析格式数据
|
||||
:param msg: 消息
|
||||
:return: 解析完毕的数据data
|
||||
"""
|
||||
if "name:" not in msg:
|
||||
return "必须指定修改的商品名称或序号!"
|
||||
data = {}
|
||||
for x in msg.split():
|
||||
sp = x.split(":", maxsplit=1)
|
||||
if str(sp[1]).strip():
|
||||
sp[1] = sp[1].strip()
|
||||
print(sp)
|
||||
if sp[0] == "name":
|
||||
data["name"] = sp[1]
|
||||
elif sp[0] == "price":
|
||||
if not is_number(sp[1]) or int(sp[1]) < 0:
|
||||
return "price参数不合法,必须大于等于0!"
|
||||
data["price"] = sp[1]
|
||||
elif sp[0] == "des":
|
||||
data["des"] = sp[1]
|
||||
elif sp[0] == "discount":
|
||||
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||
return "discount参数不合法,必须大于0!"
|
||||
data["discount"] = sp[1]
|
||||
elif sp[0] == "limit_time":
|
||||
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||
return "limit_time参数不合法,必须大于0!"
|
||||
data["limit_time"] = sp[1]
|
||||
return data
|
||||
147
plugins/shop/use/__init__.py → basic_plugins/shop/use/__init__.py
Executable file → Normal file
147
plugins/shop/use/__init__.py → basic_plugins/shop/use/__init__.py
Executable file → Normal file
@ -1,71 +1,76 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import is_number, get_message_text
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from services.db_context import db
|
||||
from .data_source import effect
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 使用道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
普通的使用道具
|
||||
指令:
|
||||
使用道具 [序号或道具名称]
|
||||
* 序号以 ”我的道具“ 为准 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 使用道具"
|
||||
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "使用道具"],
|
||||
}
|
||||
|
||||
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@use_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg in ["", "帮助"]:
|
||||
await use_props.finish(__plugin_usage__)
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
async with db.transaction():
|
||||
pname_list = []
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p not in pname_list:
|
||||
pname_list.append(p)
|
||||
if is_number(msg):
|
||||
if 0 < int(msg) <= len(pname_list):
|
||||
name = pname_list[int(msg) - 1]
|
||||
else:
|
||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||
else:
|
||||
if msg not in pname_list:
|
||||
await use_props.finish("道具名称错误!", at_sender=True)
|
||||
name = msg
|
||||
if await BagUser.del_props(
|
||||
event.user_id, event.group_id, name
|
||||
) and await effect(event.user_id, event.group_id, name):
|
||||
await use_props.send(f"使用道具 {name} 成功!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 成功"
|
||||
)
|
||||
else:
|
||||
await use_props.send(f"使用道具 {name} 失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 失败"
|
||||
)
|
||||
else:
|
||||
await use_props.send("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import is_number, get_message_text
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from services.db_context import db
|
||||
from nonebot.plugin import export
|
||||
from .data_source import effect, registered_use
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 使用道具"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
普通的使用道具
|
||||
指令:
|
||||
使用道具 [序号或道具名称]
|
||||
* 序号以 ”我的道具“ 为准 *
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 使用道具"
|
||||
__plugin_cmd__ = ["使用道具 [序号或道具名称]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "使用道具"],
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.registered_use = registered_use
|
||||
|
||||
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@use_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg in ["", "帮助"]:
|
||||
await use_props.finish(__plugin_usage__)
|
||||
props = await BagUser.get_props(event.user_id, event.group_id)
|
||||
if props:
|
||||
async with db.transaction():
|
||||
pname_list = []
|
||||
props = props[:-1].split(",")
|
||||
for p in props:
|
||||
if p != "":
|
||||
if p not in pname_list:
|
||||
pname_list.append(p)
|
||||
if is_number(msg):
|
||||
if 0 < int(msg) <= len(pname_list):
|
||||
name = pname_list[int(msg) - 1]
|
||||
else:
|
||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||
else:
|
||||
if msg not in pname_list:
|
||||
await use_props.finish("道具名称错误!", at_sender=True)
|
||||
name = msg
|
||||
if await BagUser.del_props(
|
||||
event.user_id, event.group_id, name
|
||||
) and await effect(event.user_id, event.group_id, name):
|
||||
await use_props.send(f"使用道具 {name} 成功!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 成功"
|
||||
)
|
||||
else:
|
||||
await use_props.send(f"使用道具 {name} 失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} 失败"
|
||||
)
|
||||
else:
|
||||
await use_props.send("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
45
basic_plugins/shop/use/data_source.py
Normal file
45
basic_plugins/shop/use/data_source.py
Normal file
@ -0,0 +1,45 @@
|
||||
import asyncio
|
||||
from services.log import logger
|
||||
|
||||
_use_func_data = {}
|
||||
|
||||
|
||||
async def effect(user_id: int, group_id: int, goods_name: str) -> bool:
|
||||
"""
|
||||
商品生效
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param goods_name: 商品名称
|
||||
:return: 使用是否成功
|
||||
"""
|
||||
# 优先使用注册的商品插件
|
||||
try:
|
||||
if _use_func_data.get(goods_name):
|
||||
_kwargs = _use_func_data[goods_name]["kwargs"]
|
||||
_kwargs["goods_name"] = goods_name
|
||||
_kwargs["user_id"] = user_id
|
||||
_kwargs["group_id"] = group_id
|
||||
if asyncio.iscoroutinefunction(_use_func_data[goods_name]["func"]):
|
||||
await _use_func_data[goods_name]["func"](
|
||||
**_kwargs,
|
||||
)
|
||||
else:
|
||||
_use_func_data[goods_name]["func"](
|
||||
**_kwargs,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
|
||||
def registered_use(goods_name: str, func, **kwargs):
|
||||
"""
|
||||
注册商品使用方法
|
||||
:param goods_name: 商品名称
|
||||
:param func: 使用函数
|
||||
:param kwargs: kwargs
|
||||
"""
|
||||
if goods_name in _use_func_data.keys():
|
||||
raise ValueError("该商品使用函数已被注册!")
|
||||
_use_func_data[goods_name] = {"func": func, "kwargs": kwargs}
|
||||
@ -1,5 +1,6 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
|
||||
|
||||
class BagUser(db.Model):
|
||||
@ -85,7 +86,7 @@ class BagUser(db.Model):
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def add_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
||||
async def add_gold(cls, user_qq: int, belonging_group: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
增加金币
|
||||
@ -99,27 +100,23 @@ class BagUser(db.Model):
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold + num,
|
||||
get_total_gold=user.get_total_gold + num,
|
||||
get_today_gold=user.get_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 + num,
|
||||
get_total_gold=num,
|
||||
get_today_gold=num,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold + num,
|
||||
get_total_gold=user.get_total_gold + num,
|
||||
get_today_gold=user.get_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 + num,
|
||||
get_total_gold=num,
|
||||
get_today_gold=num,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int) -> bool:
|
||||
async def spend_gold(cls, user_qq: int, belonging_group: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
花费金币
|
||||
@ -133,27 +130,23 @@ class BagUser(db.Model):
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold - num,
|
||||
spend_total_gold=user.spend_total_gold + num,
|
||||
spend_today_gold=user.spend_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 - num,
|
||||
spend_total_gold=num,
|
||||
spend_today_gold=num,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if user:
|
||||
await user.update(
|
||||
gold=user.gold - num,
|
||||
spend_total_gold=user.spend_total_gold + num,
|
||||
spend_today_gold=user.spend_today_gold + num,
|
||||
).apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
belonging_group=belonging_group,
|
||||
gold=100 - num,
|
||||
spend_total_gold=num,
|
||||
spend_today_gold=num,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def add_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
||||
async def add_props(cls, user_qq: int, belonging_group: int, name: str):
|
||||
"""
|
||||
说明:
|
||||
增加道具
|
||||
@ -167,16 +160,12 @@ class BagUser(db.Model):
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
await user.update(props=user.props + f"{name},").apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq, belonging_group=belonging_group, props=f"{name},"
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if user:
|
||||
await user.update(props=user.props + f"{name},").apply()
|
||||
else:
|
||||
await cls.create(
|
||||
user_qq=user_qq, belonging_group=belonging_group, props=f"{name},"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def del_props(cls, user_qq: int, belonging_group: int, name: str) -> bool:
|
||||
@ -193,27 +182,48 @@ class BagUser(db.Model):
|
||||
)
|
||||
query = query.with_for_update()
|
||||
user = await query.gino.first()
|
||||
try:
|
||||
if user:
|
||||
rst = ""
|
||||
props = user.props
|
||||
if props.find(name) != -1:
|
||||
props = props.split(",")
|
||||
try:
|
||||
index = props.index(name)
|
||||
except ValueError:
|
||||
return False
|
||||
props = props[:index] + props[index + 1 :]
|
||||
for p in props:
|
||||
if p != "":
|
||||
rst += p + ","
|
||||
await user.update(props=rst).apply()
|
||||
return True
|
||||
else:
|
||||
if user:
|
||||
rst = ""
|
||||
props = user.props
|
||||
if props.find(name) != -1:
|
||||
props = props.split(",")
|
||||
try:
|
||||
index = props.index(name)
|
||||
except ValueError:
|
||||
return False
|
||||
props = props[:index] + props[index + 1 :]
|
||||
for p in props:
|
||||
if p != "":
|
||||
rst += p + ","
|
||||
await user.update(props=rst).apply()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except Exception:
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def buy_props(
|
||||
cls, user_qq: int, belonging_group: int, goods: "GoodsInfo", goods_num: int
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
购买道具
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param belonging_group: 所在群聊
|
||||
:param goods: 商品
|
||||
:param goods_num: 商品数量
|
||||
"""
|
||||
try:
|
||||
# 折扣后金币
|
||||
spend_gold = goods.goods_discount * goods.goods_price * goods_num
|
||||
await BagUser.spend_gold(user_qq, belonging_group, spend_gold)
|
||||
for _ in range(goods_num):
|
||||
await BagUser.add_props(user_qq, belonging_group, goods.goods_name)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"buy_props 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
|
||||
26
plugins/shop/models/goods_info.py → models/goods_info.py
Executable file → Normal file
26
plugins/shop/models/goods_info.py → models/goods_info.py
Executable file → Normal file
@ -1,5 +1,6 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
|
||||
|
||||
class GoodsInfo(db.Model):
|
||||
@ -34,16 +35,18 @@ class GoodsInfo(db.Model):
|
||||
:param goods_limit_time: 商品限时
|
||||
"""
|
||||
try:
|
||||
await cls.create(
|
||||
goods_name=goods_name,
|
||||
goods_price=goods_price,
|
||||
goods_description=goods_description,
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
if not await cls.get_goods_info(goods_name):
|
||||
await cls.create(
|
||||
goods_name=goods_name,
|
||||
goods_price=goods_price,
|
||||
goods_description=goods_description,
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo add_goods 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_goods(cls, goods_name: str) -> bool:
|
||||
@ -99,7 +102,8 @@ class GoodsInfo(db.Model):
|
||||
if goods_limit_time:
|
||||
await query.update(goods_limit_time=goods_limit_time).apply()
|
||||
return True
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
@ -40,7 +40,7 @@ def is_expired(data: dict):
|
||||
|
||||
# 检查写入
|
||||
def check_write(data: dict, up_char_file):
|
||||
if not is_expired(data['char']):
|
||||
if is_expired(data['char']):
|
||||
for x in list(data.keys()):
|
||||
data[x]['title'] = ''
|
||||
else:
|
||||
|
||||
@ -146,12 +146,14 @@ def _format_card_information(_count: int, user_id, pool_name):
|
||||
five_index_list = []
|
||||
five_list = []
|
||||
five_dict = {}
|
||||
_start_add_count = 72 if pool_name == 'char' else 62
|
||||
_x = 90 if pool_name == 'char' else 80 # 保底
|
||||
add = 0.0
|
||||
if genshin_count.get(user_id) and _count <= 90:
|
||||
if genshin_count.get(user_id) and _count <= _x:
|
||||
f_count = genshin_count[user_id]
|
||||
else:
|
||||
f_count = 0
|
||||
if genshin_pl_count.get(user_id) and _count <= 90:
|
||||
if genshin_pl_count.get(user_id) and _count <= _x:
|
||||
count = genshin_pl_count[user_id]
|
||||
else:
|
||||
count = 0
|
||||
@ -159,23 +161,23 @@ def _format_card_information(_count: int, user_id, pool_name):
|
||||
count += 1
|
||||
f_count += 1
|
||||
# 十连保底
|
||||
if count == 10 and f_count != 90:
|
||||
if f_count >= 72:
|
||||
if count == 10 and f_count != _x:
|
||||
if f_count >= _start_add_count:
|
||||
add += I72_ADD
|
||||
char, code = _get_genshin_card(2, pool_name, add=add)
|
||||
count = 0
|
||||
# 大保底
|
||||
elif f_count == 90:
|
||||
elif f_count == _x:
|
||||
char, code = _get_genshin_card(3, pool_name)
|
||||
else:
|
||||
if f_count >= 72:
|
||||
if f_count >= _start_add_count:
|
||||
add += I72_ADD
|
||||
char, code = _get_genshin_card(pool_name=pool_name, add=add)
|
||||
if code == 1:
|
||||
count = 0
|
||||
star_list[code] += 1
|
||||
if code == 0:
|
||||
if _count <= 90:
|
||||
if _count <= _x:
|
||||
genshin_five[user_id] = f_count
|
||||
add = 0.0
|
||||
f_count = 0
|
||||
@ -186,7 +188,7 @@ def _format_card_information(_count: int, user_id, pool_name):
|
||||
except KeyError:
|
||||
five_dict[char.name] = 1
|
||||
char_list.append(char)
|
||||
if _count <= 90:
|
||||
if _count <= _x:
|
||||
genshin_count[user_id] = f_count
|
||||
genshin_pl_count[user_id] = count
|
||||
return char_list, five_list, five_index_list, five_dict, star_list
|
||||
|
||||
@ -7,9 +7,10 @@ from utils.browser import get_browser
|
||||
from configs.path_config import IMAGE_PATH
|
||||
import nonebot
|
||||
from services.log import logger
|
||||
from utils.utils import scheduler
|
||||
from nonebot.permission import SUPERUSER
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
from datetime import datetime, timedelta
|
||||
import os
|
||||
import asyncio
|
||||
import time
|
||||
@ -52,9 +53,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if time.strftime("%w") == "0":
|
||||
await material.send("今天是周日,所有材料副本都开放了。")
|
||||
return
|
||||
file_name = str((datetime.now() - timedelta(hours=4)).date())
|
||||
if not (Path(IMAGE_PATH) / "genshin" / "material" / f"{file_name}.png").exists():
|
||||
await update_image()
|
||||
await material.send(
|
||||
Message(
|
||||
image("daily_material.png", "genshin/material")
|
||||
image(f"{file_name}.png", "genshin/material")
|
||||
+ "\n※ 每日素材数据来源于 genshin.pub"
|
||||
)
|
||||
)
|
||||
@ -73,7 +77,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await super_cmd.send(f"更新失败...")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def update_image():
|
||||
page = None
|
||||
try:
|
||||
@ -140,7 +143,8 @@ async def update_image():
|
||||
background_img.paste(x, (current_width, current_height))
|
||||
current_height += x.size[1]
|
||||
current_width += 600
|
||||
background_img.save(f"{IMAGE_PATH}/genshin/material/daily_material.png")
|
||||
file_name = str((datetime.now() - timedelta(hours=4)).date())
|
||||
background_img.save(f"{IMAGE_PATH}/genshin/material/{file_name}.png")
|
||||
await page.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
@ -163,16 +167,3 @@ def get_background_height(weapons_imgs: List[str]) -> int:
|
||||
return height
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=4,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
for _ in range(5):
|
||||
try:
|
||||
await update_image()
|
||||
logger.info(f"更新每日天赋素材成功...")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"更新每日天赋素材出错 e:{e}")
|
||||
|
||||
@ -64,7 +64,7 @@ async def get_image(
|
||||
"affix_level": char["weapon"]["affix_level"],
|
||||
}
|
||||
|
||||
await init_image(char_data_list, _x)
|
||||
await init_image(char_data_list, _x, home_data_list)
|
||||
return await get_genshin_image(
|
||||
user_id,
|
||||
uid,
|
||||
|
||||
@ -510,11 +510,12 @@ def get_char_data_image(
|
||||
return region, _h
|
||||
|
||||
|
||||
async def init_image(char_data_list: List[Dict], char_detailed_dict: dict):
|
||||
async def init_image(char_data_list: List[Dict], char_detailed_dict: dict, home_data_list: List[Dict]):
|
||||
"""
|
||||
下载头像
|
||||
:param char_data_list: 角色列表
|
||||
:param char_detailed_dict: 角色武器
|
||||
:param home_data_list: 家园列表
|
||||
"""
|
||||
for char in char_data_list:
|
||||
file = image_path / "chars" / f'{char["name"]}.png'
|
||||
@ -528,3 +529,10 @@ async def init_image(char_data_list: List[Dict], char_detailed_dict: dict):
|
||||
await AsyncHttpx.download_file(
|
||||
char_detailed_dict[char]["weapon_image"], file
|
||||
)
|
||||
for home in home_data_list:
|
||||
file = image_path / "homes" / f'{home["name"]}.png'
|
||||
file.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not file.exists():
|
||||
await AsyncHttpx.download_file(
|
||||
home["icon"], file
|
||||
)
|
||||
|
||||
@ -41,8 +41,19 @@ usage:
|
||||
示例:塞红包 1000
|
||||
示例:塞红包 1000 10
|
||||
""".strip()
|
||||
__plugin_superuser_usage__ = """
|
||||
usage:
|
||||
节日全群红包指令
|
||||
指令:
|
||||
节日红包 [金额] [数量] ?[祝福语] ?[指定群]
|
||||
""".strip()
|
||||
__plugin_des__ = "运气项目又来了"
|
||||
__plugin_cmd__ = ["塞红包 [金币数] ?[红包数=5]", "开/抢", "退回"]
|
||||
__plugin_cmd__ = [
|
||||
"塞红包 [金币数] ?[红包数=5]",
|
||||
"开/抢",
|
||||
"退回",
|
||||
"节日红包 [金额] [数量] ?[祝福语] ?[指定群] [_superuser]",
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
@ -51,9 +62,7 @@ __plugin_settings__ = {
|
||||
"limit_superuser": False,
|
||||
"cmd": ["金币红包", "塞红包"],
|
||||
}
|
||||
__plugin_resources__ = {
|
||||
"prts": IMAGE_PATH
|
||||
}
|
||||
__plugin_resources__ = {"prts": IMAGE_PATH}
|
||||
|
||||
gold_redbag = on_command(
|
||||
"塞红包", aliases={"金币红包"}, priority=5, block=True, permission=GROUP
|
||||
@ -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)
|
||||
if not flag:
|
||||
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)
|
||||
if num > group_member_num:
|
||||
await gold_redbag.send('你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...')
|
||||
await gold_redbag.send("你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...")
|
||||
num = group_member_num
|
||||
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
flag, result = init_redbag(
|
||||
@ -181,7 +192,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
.replace("。", "")
|
||||
)
|
||||
if msg:
|
||||
if '红包' not in msg:
|
||||
if "红包" not in msg:
|
||||
return
|
||||
flag1 = True
|
||||
flag2 = True
|
||||
@ -306,7 +317,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await end_festive_redbag(bot, g)
|
||||
except JobLookupError:
|
||||
pass
|
||||
init_redbag(int(bot.self_id), g, f"{NICKNAME}", amount, num, int(bot.self_id), 1)
|
||||
init_redbag(
|
||||
int(bot.self_id), g, f"{NICKNAME}", amount, num, int(bot.self_id), 1
|
||||
)
|
||||
scheduler.add_job(
|
||||
end_festive_redbag,
|
||||
"date",
|
||||
|
||||
@ -20,7 +20,7 @@ except ModuleNotFoundError:
|
||||
__zx_plugin_name__ = "本地图库"
|
||||
__plugin_usage__ = f"""
|
||||
usage:
|
||||
发送指定图库下的随机或指定id图片
|
||||
发送指定图库下的随机或指定id图片genshin_memo
|
||||
指令:
|
||||
{Config.get_config("image_management", "IMAGE_DIR_LIST")} ?[id]
|
||||
示例:美图
|
||||
|
||||
@ -105,7 +105,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
path = get_message_imgs(event.json())
|
||||
if path in Config.get_config("image_management", "IMAGE_DIR_LIST"):
|
||||
state["path"] = path
|
||||
await continuous_upload_img.send("图来!!")
|
||||
await continuous_upload_img.send("图来!!【停止请发送 ‘stop’ 开始上传】")
|
||||
state["tmp"] = []
|
||||
|
||||
|
||||
|
||||
@ -124,6 +124,27 @@ class Setu(db.Model):
|
||||
).gino.first()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def delete_image(cls, pid: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
删除图片并替换
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
"""
|
||||
query = await cls.query.where(cls.pid == pid).gino.first()
|
||||
if query:
|
||||
is_r18 = query.is_r18
|
||||
num = await cls.get_image_count(is_r18)
|
||||
x = await cls.query.where((cls.is_r18 == is_r18) & (cls.local_id == num - 1)).gino.first()
|
||||
_tmp_local_id = x.local_id
|
||||
if x:
|
||||
x.update(local_id=query.local_id).apply()
|
||||
await cls.delete.where(cls.pid == pid).gino.status()
|
||||
return _tmp_local_id
|
||||
return -1
|
||||
|
||||
|
||||
@classmethod
|
||||
async def update_setu_data(
|
||||
cls,
|
||||
|
||||
@ -3,7 +3,7 @@ from services.log import logger
|
||||
from datetime import datetime
|
||||
from utils.image_utils import compressed_image, get_img_hash
|
||||
from utils.utils import get_bot
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from PIL import UnidentifiedImageError
|
||||
from ..model import Setu
|
||||
from asyncpg.exceptions import UniqueViolationError
|
||||
from configs.config import Config
|
||||
@ -142,6 +142,14 @@ async def update_setu_img():
|
||||
continue
|
||||
img_hash = str(get_img_hash(f"{path}/{image.local_id}.jpg"))
|
||||
await Setu.update_setu_data(image.pid, img_hash=img_hash)
|
||||
except UnidentifiedImageError:
|
||||
# 图片已删除
|
||||
with open(local_image, 'r') as f:
|
||||
if '404 Not Found' in f.read():
|
||||
max_num = await Setu.delete_image(image.pid)
|
||||
local_image.unlink()
|
||||
os.rename(path / f"{max_num}.jpg", local_image)
|
||||
logger.warning(f"更新色图 PID:{image.pid} 404,已删除并替换")
|
||||
except Exception as e:
|
||||
_success -= 1
|
||||
logger.error(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}")
|
||||
|
||||
36
plugins/server_ip.py
Normal file
36
plugins/server_ip.py
Normal file
@ -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 *
|
||||
""".strip()
|
||||
__plugin_des__ = "每日签到,证明你在这里"
|
||||
__plugin_cmd__ = ["签到", "我的签到", "好感度排行", "好感度总排行"]
|
||||
__plugin_cmd__ = ["签到 ?[all]", "我的签到", "好感度排行", "好感度总排行"]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
|
||||
@ -59,7 +59,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await yiqing.send(rely)
|
||||
logger.info(
|
||||
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'}) 查询疫情成功"
|
||||
)
|
||||
else:
|
||||
await yiqing.send(f"{NICKNAME}没有查到{msg}的疫情查询...")
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
from configs.path_config import TEXT_PATH
|
||||
from typing import List
|
||||
from typing import List, Union
|
||||
from pathlib import Path
|
||||
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
|
||||
|
||||
china_city = Path(TEXT_PATH) / "china_city.json"
|
||||
@ -12,7 +15,7 @@ data = {}
|
||||
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: 省份/城市
|
||||
@ -40,16 +43,16 @@ async def get_yiqing_data(area: str):
|
||||
if area == "中国":
|
||||
data_ = epidemic_data["areaTree"][0]
|
||||
else:
|
||||
data_ = [
|
||||
x
|
||||
for x in epidemic_data["areaTree"][0]["children"]
|
||||
if x["name"] == province
|
||||
][0]
|
||||
if city:
|
||||
try:
|
||||
try:
|
||||
data_ = [
|
||||
x
|
||||
for x in epidemic_data["areaTree"][0]["children"]
|
||||
if x["name"] == province
|
||||
][0]
|
||||
if city:
|
||||
data_ = [x for x in data_["children"] if x["name"] == city][0]
|
||||
except IndexError:
|
||||
return "未查询到..."
|
||||
except IndexError:
|
||||
return "未查询到..."
|
||||
confirm = data_["total"]["confirm"] # 累计确诊
|
||||
heal = data_["total"]["heal"] # 累计治愈
|
||||
dead = data_["total"]["dead"] # 累计死亡
|
||||
@ -59,20 +62,22 @@ async def get_yiqing_data(area: str):
|
||||
suspect = data_["total"]["suspect"] # 疑似
|
||||
add_confirm = data_["today"]["confirm"] # 新增确诊
|
||||
x = f"{city}市" if city else f"{province}{province_type}"
|
||||
return (
|
||||
f"{x} 疫情数据:\n"
|
||||
f"\t目前确诊:\n"
|
||||
f"\t\t确诊人数:{now_confirm}(+{add_confirm})\n"
|
||||
f"\t\t疑似人数:{suspect}\n"
|
||||
f"==================\n"
|
||||
f"\t累计数据:\n"
|
||||
f"\t\t确诊人数:{confirm}\n"
|
||||
f"\t\t治愈人数:{heal}\n"
|
||||
f"\t\t死亡人数:{dead}\n"
|
||||
f"\t治愈率:{heal_rate}%\n"
|
||||
f"\t死亡率:{dead_rate}%\n"
|
||||
f"更新日期:{last_update_time}"
|
||||
)
|
||||
return image(b64=await text2image(
|
||||
f"""
|
||||
{x} 疫情数据:
|
||||
目前确诊:
|
||||
确诊人数:<f font_color=red>{now_confirm}(+{add_confirm})</f>
|
||||
疑似人数:{suspect}
|
||||
-----------------
|
||||
累计数据:
|
||||
确诊人数:<f font_color=red>{confirm}</f>
|
||||
治愈人数:<f font_color=#39de4b>{heal}</f>
|
||||
死亡人数:<f font_color=#191d19>{dead}</f>
|
||||
治愈率:{heal_rate}%
|
||||
死亡率:{dead_rate}%
|
||||
更新日期:{last_update_time}
|
||||
""", font_size=30, color="#f9f6f2"
|
||||
))
|
||||
|
||||
|
||||
def get_city_and_province_list() -> List[str]:
|
||||
|
||||
@ -6,8 +6,12 @@
|
||||
# @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
|
||||
|
||||
@ -23,50 +27,66 @@ def intcomma(value) -> str:
|
||||
return new if orig == new else intcomma(new)
|
||||
|
||||
|
||||
async def get_other_data(place: str) -> Optional[str]:
|
||||
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
|
||||
find_data = re.compile(r"varallData=(.*?);</script>")
|
||||
sum_ = re.findall(find_data, html)[0]
|
||||
try:
|
||||
sum_ = json.loads(sum_)
|
||||
other_country = sum_["yiqing_v2"]["dataList"][29]["child"]
|
||||
for country in other_country:
|
||||
if place == country["name2"]:
|
||||
return (
|
||||
f"{place} 疫情数据:\n"
|
||||
"——————————————\n"
|
||||
f"新增病例:{intcomma(country['quezhen_add'])}\n"
|
||||
f"现有确诊:{intcomma(country['quezhen_xianyou'])}\n"
|
||||
f"累计确诊:{intcomma(country['quezhen'])}\n"
|
||||
f"累计治愈:{intcomma(country['zhiyu'])}\n"
|
||||
f"死亡:{intcomma(country['siwang'])}\n"
|
||||
"——————————————"
|
||||
# f"更新时间:{country['sys_publishDateTime']}"
|
||||
# 时间无法精确到分钟,网页用了js我暂时找不到
|
||||
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 (
|
||||
f"{place} 疫情数据:\n"
|
||||
"——————————————\n"
|
||||
f"新增病例:{intcomma(city['quezhen_add'])}\n"
|
||||
f"累计确诊:{intcomma(city['quezhen'])}\n"
|
||||
f"累计治愈:{intcomma(city['zhiyu'])}\n"
|
||||
f"死亡:{intcomma(city['siwang'])}\n"
|
||||
"——————————————"
|
||||
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}")
|
||||
|
||||
BIN
resources/img/other/time.png
Normal file
BIN
resources/img/other/time.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
BIN
resources/ttf/CJGaoDeGuo.otf
Normal file
BIN
resources/ttf/CJGaoDeGuo.otf
Normal file
Binary file not shown.
BIN
resources/ttf/SweiSpringCJKtc-Bold.ttf
Normal file
BIN
resources/ttf/SweiSpringCJKtc-Bold.ttf
Normal file
Binary file not shown.
BIN
resources/ttf/SweiSpringSugarCJKtc-Regular.ttf
Normal file
BIN
resources/ttf/SweiSpringSugarCJKtc-Regular.ttf
Normal file
Binary file not shown.
BIN
resources/ttf/YSHaoShenTi-2.ttf
Normal file
BIN
resources/ttf/YSHaoShenTi-2.ttf
Normal file
Binary file not shown.
BIN
resources/ttf/sarasa-mono-sc-nerd-regular.ttf
Normal file
BIN
resources/ttf/sarasa-mono-sc-nerd-regular.ttf
Normal file
Binary file not shown.
@ -17,7 +17,7 @@ async def init():
|
||||
await db.gino.create_all()
|
||||
logger.info(f'Database loaded successfully!')
|
||||
except Exception as e:
|
||||
raise Exception(f'数据库连接错误.... e: {e}')
|
||||
raise Exception(f'数据库连接错误.... {type(e)}: {e}')
|
||||
|
||||
|
||||
async def disconnect():
|
||||
|
||||
@ -2,11 +2,10 @@
|
||||
"update_file": [
|
||||
"plugins",
|
||||
"models",
|
||||
"basic_plugins",
|
||||
"utils",
|
||||
"services",
|
||||
"configs/utils",
|
||||
"utils",
|
||||
"resources/ttf"
|
||||
],
|
||||
"add_file": ["resources/img/genshin/genshin_card", "resources/img/genshin/genshin_memo"],
|
||||
"add_file": ["resources/img/other/time.png"],
|
||||
"delete_file": []
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import random
|
||||
import cv2
|
||||
import base64
|
||||
import imagehash
|
||||
import re
|
||||
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
Image.MAX_IMAGE_PIXELS = None
|
||||
@ -136,6 +137,178 @@ def is_valid(file: str) -> bool:
|
||||
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: 文本外边距,元组类型时为 (上,左,下,右)
|
||||
"""
|
||||
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="):
|
||||
_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"):
|
||||
_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
|
||||
top_padding = left_padding = 0
|
||||
if padding:
|
||||
if isinstance(padding, int):
|
||||
width += padding * 2
|
||||
height += padding * 2
|
||||
top_padding = left_padding = padding
|
||||
elif isinstance(padding, tuple):
|
||||
width += padding[0] + padding[2]
|
||||
height += padding[1] + padding[3]
|
||||
top_padding = padding[0]
|
||||
left_padding = padding[1]
|
||||
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
|
||||
# A.show()
|
||||
return A.pic2bs4()
|
||||
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
|
||||
A = BuildImage(width, height, font_size=font_size, color=color)
|
||||
await A.atext((0, 0), text, font_color)
|
||||
# A.show()
|
||||
return A.pic2bs4()
|
||||
|
||||
|
||||
class BuildImage:
|
||||
"""
|
||||
快捷生成图片与操作图片的工具类
|
||||
@ -155,7 +328,7 @@ class BuildImage:
|
||||
ratio: float = 1,
|
||||
is_alpha: bool = False,
|
||||
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 +340,7 @@ class BuildImage:
|
||||
:param image_mode: 图片的类型
|
||||
:param font_size: 文字大小
|
||||
:param background: 打开图片的路径
|
||||
:param ttf: 字体,默认在 resource/ttf/ 路径下
|
||||
:param font: 字体,默认在 resource/ttf/ 路径下
|
||||
:param ratio: 倍率压缩
|
||||
:param is_alpha: 是否背景透明
|
||||
:param plain_text: 纯文字文本
|
||||
@ -367,7 +540,7 @@ class BuildImage:
|
||||
self,
|
||||
pos: Tuple[int, int],
|
||||
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,
|
||||
):
|
||||
"""
|
||||
@ -385,7 +558,7 @@ class BuildImage:
|
||||
self,
|
||||
pos: Tuple[int, int],
|
||||
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,
|
||||
):
|
||||
"""
|
||||
@ -620,7 +793,7 @@ class BuildImage:
|
||||
async def aline(
|
||||
self,
|
||||
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,
|
||||
):
|
||||
"""
|
||||
@ -636,7 +809,7 @@ class BuildImage:
|
||||
def line(
|
||||
self,
|
||||
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,
|
||||
):
|
||||
"""
|
||||
@ -784,6 +957,58 @@ class BuildImage:
|
||||
self.markImg = self.markImg.filter(_x)
|
||||
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_):
|
||||
self.markImg = self.markImg.getchannel(type_)
|
||||
|
||||
@ -21,6 +21,9 @@ class Plugins2settingsManager(StaticData):
|
||||
self._data = (
|
||||
self._data["PluginSettings"] if self._data["PluginSettings"] else {}
|
||||
)
|
||||
for x in self._data.keys():
|
||||
if self._data[x].get("cost_gold") is None:
|
||||
self._data[x]["cost_gold"] = 0
|
||||
|
||||
def add_plugin_settings(
|
||||
self,
|
||||
@ -30,7 +33,8 @@ class Plugins2settingsManager(StaticData):
|
||||
level: Optional[int] = 5,
|
||||
limit_superuser: Optional[bool] = False,
|
||||
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 limit_superuser: 功能状态是否限制超级用户
|
||||
:param plugin_type: 插件类型
|
||||
:param data_dict: 封装好的字典数据
|
||||
:param cost_gold: 需要消费的金币
|
||||
"""
|
||||
if data_dict:
|
||||
level = data_dict.get("level") if data_dict.get("level") is not None else 5
|
||||
if kwargs:
|
||||
level = kwargs.get("level") if kwargs.get("level") is not None else 5
|
||||
default_status = (
|
||||
data_dict.get("default_status")
|
||||
if data_dict.get("default_status") is not None
|
||||
kwargs.get("default_status")
|
||||
if kwargs.get("default_status") is not None
|
||||
else True
|
||||
)
|
||||
limit_superuser = (
|
||||
data_dict.get("limit_superuser")
|
||||
if data_dict.get("limit_superuser") is not None
|
||||
kwargs.get("limit_superuser")
|
||||
if kwargs.get("limit_superuser") is not None
|
||||
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] = {
|
||||
"level": level if level is not None else 5,
|
||||
"default_status": default_status if default_status is not None else True,
|
||||
@ -65,6 +70,7 @@ class Plugins2settingsManager(StaticData):
|
||||
"plugin_type": list(
|
||||
plugin_type if plugin_type is not None else ("normal",)
|
||||
),
|
||||
"cost_gold": cost_gold,
|
||||
}
|
||||
|
||||
def get_plugin_data(self, module: str) -> dict:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user