Merge branch 'main' into main

This commit is contained in:
HibiKier 2023-02-18 22:56:25 +08:00 committed by GitHub
commit fef85190c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
138 changed files with 5649 additions and 6249 deletions

4
.gitignore vendored
View File

@ -156,8 +156,9 @@ data/
.env.dev
/resources/text/
/resources/image/
/resources/temp/
!/resources/template/
configs/config.py
/configs/config.py
configs/config.yaml
./.env
./.env.dev
@ -165,3 +166,4 @@ plugins/csgo_server/
plugins/activity/
!/resources/image/genshin/alc/back.png
!/data/genshin_alc/
.vscode/launch.json

330
README.md
View File

@ -5,22 +5,27 @@
![maven](https://img.shields.io/badge/go--cqhttp-1.0.0-red)
# 绪山真寻Bot
****
此项目基于 Nonebot2 和 go-cqhttp 开发,以 postgresql 作为数据库的QQ群娱乐机器人
## 关于
用爱发电,某些功能学习借鉴了大佬们的代码,因为绪山真寻实在太可爱了因此开发了
绪山真寻bot实现了一些对群友的娱乐功能和实用功能大概
如果该项目的图片等等侵犯猫豆腐老师权益请联系我删除!
是新手希望有个地方讨论绪山真寻Bot或者有问题或建议可以发送issues或加入[ <strong>[是真寻酱哒](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>]
是新手希望有个地方讨论绪山真寻Bot或者有问题或建议可以发送issues或加入[ <strong>[是真寻酱哒(萌新版)](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>]
更喜欢讨论可爱的真寻,讨论插件开发nonebot2开发可以加入[ <strong>[真寻酱的技术群](https://jq.qq.com/?_wv=1027&k=E6sUkMzo) </strong>])
[//]: # (是老手!讨论插件开发nonebot2开发可以加入[ <strong>[真寻酱的技术群]&#40;https://jq.qq.com/?_wv=1027&k=u8PgBkMZ&#41; </strong>])
## 声明
此项目仅用于学习交流,请勿用于非法用途
# Nonebot2
<img style="height: 200px;width: 200px;" src="https://camo.githubusercontent.com/0ef71e86056da694c540790aa4a4e314396884d6c4fdb95362a7538b27a1b034/68747470733a2f2f76322e6e6f6e65626f742e6465762f6c6f676f2e706e67">
非常 [ **[NICE](https://github.com/nonebot/nonebot2)** ] 的OneBot框架
@ -30,18 +35,23 @@
# [传送门](https://hibikier.github.io/zhenxun_bot/)
## 真寻的帮助
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
## 普通帮助图片
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/help.png)
## HTML版帮助图片
![x](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs_image/html_help.png)
## Web UI
[zhenxun_bot_webui](https://github.com/HibiKier/zhenxun_bot_webui)
## 一键安装脚本
[zhenxun_bot-deploy](https://github.com/AkashiCoin/zhenxun_bot-deploy)
## 提供符合真寻标准的插件仓库
@ -50,152 +60,164 @@
## 来点优点?
* 实现了许多功能,且提供了大量功能管理命令
* 通过Config配置项将所有插件配置统计保存至config.yaml利于统一用户修改
* 方便增删插件原生nonebot2 matcher不需要额外修改仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
* 提供了cd阻塞每日次数等限制仅仅通过简单的属性就可以生成一个限制例如`__plugin_cd_limit__`
* __..... 更多详细请通过`传送门`查看文档__
* 实现了许多功能,且提供了大量功能管理命令
* 通过Config配置项将所有插件配置统计保存至config.yaml利于统一用户修改
* 方便增删插件原生nonebot2 matcher不需要额外修改仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
* 提供了cd阻塞每日次数等限制仅仅通过简单的属性就可以生成一个限制例如`__plugin_cd_limit__`
* __..... 更多详细请通过`传送门`查看文档__
## 功能列表
<details>
<summary>已实现的功能</summary>
### 已实现的常用功能
- [x] 昵称系统(群与群与私聊分开.
- [x] 图灵AI会把'你'等关键字替换为你的昵称),且带有 [AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus),够味
- [x] 签到/我的签到/好感度排行/好感度总排行(影响色图概率和开箱次数,支持配置)
- [x] 发送某文件夹下的随机图片(支持自定义,默认:美图,萝莉,壁纸)
- [x] 色图(这不是基础功能嘛喂)
- [x] coser
- [x] 黑白草图生成器
- [x] 鸡汤/语录
- [x] 骂我(钉宫语音)
- [x] 戳一戳(概率发送美图,钉宫语音或者戳回去)
- [x] 模拟开箱/我的开箱/群开箱统计/我的金色/设置cookiecsgo内置爬虫脚本需要提前抓取数据和图片需要session可能需要代理阿里云服务器等ip也许已经被ban了我无代理访问失败如果访问太多账号API调用可能被禁止访问api
- [x] 鲁迅说过
- [x] 构造假消息(自定义的分享链接)
- [x] 商店/我的金币/购买道具/使用道具
- [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
- [x] 我有一个朋友想问问..借鉴pcrbot插件
- [x] 原神黄历
- [x] 原神今日素材
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 原神便笺查询
- [x] 原神玩家查询
- [x] 原神树脂提醒
- [x] 原神签到/自动签到
- [x] 金币红包
- [x] 微博热搜
- [x] B站主播/UP/番剧订阅
- [x] pil对图片的一些操作
- [x] BUFF饰品底价查询需要session
- [x] 天气查询
- [x] 疫情查询
- [x] bt磁力搜索咳咳这功能我想dddd
- [x] reimu搜索上车 (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
- [x] 靠图识番 (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
- [x] 以图搜图 (使用[nonebot_plugin_picsearcher](https://github.com/synodriver/nonebot_plugin_picsearcher)插件)
- [x] 搜番
- [x] 点歌 [nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)插件(删除了选歌和评论)
- [x] epic免费游戏
- [x] p站排行榜
- [x] p站搜图
- [x] 翻译(日英韩)
- [x] pix图库一个自己的图库含有增删查改黑名单等命令
* [x] 昵称系统(群与群与私聊分开.
- [x] 查看当前群欢迎消息
- [x] 查看该群自己的权限
- [x] 我的信息(只是为了看看什么时候入群)
- [x] 更新信息(如果继续更新的话)
- [x] go-cqhttp最新版下载和上传不需要请删除
- [x] 撤回
- [x] 滴滴滴-(用户对超级用户发送消息)
- [x] 金币红包/金币排行
- [x] 俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
- [x] 网易云热评
- [x] 念首古诗
- [x] 获取b站视频封面
- [x] 通过PID获取图片
- [x] 功能统计可视化
- [x] 词云
- [x] 关于
* [x] 图灵AI会把'你'等关键字替换为你的昵称),且带有 [AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus),够味
* [x] 签到/我的签到/好感度排行/好感度总排行(影响色图概率和开箱次数,支持配置)
* [x] 发送某文件夹下的随机图片(支持自定义,默认:美图,萝莉,壁纸)
* [x] 色图(这不是基础功能嘛喂)
* [x] coser
* [x] 黑白草图生成器
* [x] 鸡汤/语录
* [x] 骂我(钉宫语音)
* [x] 戳一戳(概率发送美图,钉宫语音或者戳回去)
* [x] 模拟开箱/我的开箱/群开箱统计/我的金色/设置cookiecsgo内置爬虫脚本需要提前抓取数据和图片需要session可能需要代理阿里云服务器等ip也许已经被ban了我无代理访问失败如果访问太多账号API调用可能被禁止访问api
* [x] 鲁迅说过
* [x] 构造假消息(自定义的分享链接)
* [x] 商店/我的金币/购买道具/使用道具
* [x] 8种手游抽卡 (查看 [nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw))
* [x] 我有一个朋友想问问..借鉴pcrbot插件
* [x] 原神黄历
* [x] 原神今日素材
* [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
* [x] 原神便笺查询
* [x] 原神玩家查询
* [x] 原神树脂提醒
* [x] 原神签到/自动签到
* [x] 金币红包
* [x] 微博热搜
* [x] B站主播/UP/番剧订阅
* [x] pil对图片的一些操作
* [x] BUFF饰品底价查询需要session
* [x] 天气查询
* [x] 疫情查询
* [x] bt磁力搜索咳咳这功能我想dddd
* [x] reimu搜索上车 (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
* [x] 靠图识番 (使用[XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)的插件)
* [x] 以图搜图 (使用[nonebot_plugin_picsearcher](https://github.com/synodriver/nonebot_plugin_picsearcher)插件)
* [x] 搜番
* [x] 点歌 [nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2)插件(删除了选歌和评论)
* [x] epic免费游戏
* [x] p站排行榜
* [x] p站搜图
* [x] 翻译(日英韩)
* [x] pix图库一个自己的图库含有增删查改黑名单等命令
* [x] 查看当前群欢迎消息
* [x] 查看该群自己的权限
* [x] 我的信息(只是为了看看什么时候入群)
* [x] 更新信息(如果继续更新的话)
* [x] go-cqhttp最新版下载和上传不需要请删除
* [x] 撤回
* [x] 滴滴滴-(用户对超级用户发送消息)
* [x] 金币红包/金币排行
* [x] 俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
* [x] 网易云热评
* [x] 念首古诗
* [x] 获取b站视频封面
* [x] 通过PID获取图片
* [x] 功能统计可视化
* [x] 词云
* [x] 关于
### 已实现的管理员功能
- [x] 更新群组成员信息
- [x] 95%的群功能开关
- [x] 查看群内被动技能状态
- [x] 自定义群欢迎消息(是真寻的不是管家的!)
- [x] .ban/.unban支持设置ban时长= 黑白名单
- [x] 刷屏禁言相关:刷屏检测设置/设置禁言时长/设置检测次数
- [x] 上传图片/连续上传图片 (上传图片至指定图库)
- [x] 移动图片 (同上)
- [x] 删除图片 (同上)
- [x] 群内B站订阅
- [x] 词条设置
- [x] 休息吧/醒来
* [x] 更新群组成员信息
* [x] 95%的群功能开关
* [x] 查看群内被动技能状态
* [x] 自定义群欢迎消息(是真寻的不是管家的!)
* [x] .ban/.unban支持设置ban时长= 黑白名单
* [x] 刷屏禁言相关:刷屏检测设置/设置禁言时长/设置检测次数
* [x] 上传图片/连续上传图片 (上传图片至指定图库)
* [x] 移动图片 (同上)
* [x] 删除图片 (同上)
* [x] 群内B站订阅
* [x] 词条设置
* [x] 休息吧/醒来
### 已实现的超级用户功能
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
- [x] 开启/关闭指定群的广播通知
- [x] 广播
- [x] 自检(检查系统状态)
- [x] 所有群组/所有好友
- [x] 退出指定群
- [x] 更新好友信息/更新群信息
- [x] /t对用户进行回复或发送消息
- [x] 上传/删除/修改商品(需要编写对应的商品功能)
- [x] 节日红包发送
- [x] 修改群权限
- [x] ban
- [x] 更新色图
- [x] 更新价格/更加图片csgo开箱
- [x] 重载原神/方舟/赛马娘/坎公骑冠剑卡池
- [x] 更新原神今日素材/更新原神资源信息
- [x] PIX相关操作
- [x] 检查更新真寻
- [x] 重启
- [x] 添加/删除/查看群白名单
- [x] 功能开关(更多设置)
- [x] 功能状态
- [x] b了
- [x] 执行sql
- [x] 重载配置
- [x] 清理临时数据
- [x] 增删群认证
- [x] 同意/拒绝好友/群聊请求
- [x] 配置重载
* [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
* [x] 开启/关闭指定群的广播通知
* [x] 广播
* [x] 自检(检查系统状态)
* [x] 所有群组/所有好友
* [x] 退出指定群
* [x] 更新好友信息/更新群信息
* [x] /t对用户进行回复或发送消息
* [x] 上传/删除/修改商品(需要编写对应的商品功能)
* [x] 节日红包发送
* [x] 修改群权限
* [x] ban
* [x] 更新色图
* [x] 更新价格/更加图片csgo开箱
* [x] 重载原神/方舟/赛马娘/坎公骑冠剑卡池
* [x] 更新原神今日素材/更新原神资源信息
* [x] PIX相关操作
* [x] 检查更新真寻
* [x] 重启
* [x] 添加/删除/查看群白名单
* [x] 功能开关(更多设置)
* [x] 功能状态
* [x] b了
* [x] 执行sql
* [x] 重载配置
* [x] 清理临时数据
* [x] 增删群认证
* [x] 同意/拒绝好友/群聊请求
* [x] 配置重载
#### 超级用户的被动技能
- [x] 邀请入群提醒(别人邀请真寻入群)
- [x] 添加好友提醒(别人添加真寻好友)
* [x] 邀请入群提醒(别人邀请真寻入群)
* [x] 添加好友提醒(别人添加真寻好友)
### 已实现的被动技能
- [x] 进群欢迎消息
- [x] 群早晚安
- [x] 每日开箱重置提醒
- [x] b站转发解析解析b站分享信息支持bvbilibili链接b站手机端转发卡片cvb23.tv且5分钟内不解析相同url
- [x] 丢人爬(爬表情包)
- [x] epic通知每日发送epic免费游戏链接
- [x] 原神黄历提醒
- [x] 复读
### 已实现的看不见的技能!
- [x] 刷屏禁言检测
- [x] 功能调用统计
- [x] 检测恶意触发命令将被最高权限ban掉30分钟只有最高权限(9级)可以进行unban
- [x] 自动同意好友请求,加群请求将会提醒管理员,退群提示,加群欢迎等等
- [x] 群聊时间检测当群聊最后一人发言时间大于当前36小时后将关闭该群所有通知即被动技能
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
- [x] 群权限系统
- [x] 定时更新权限
- [x] 自动配置重载
* [x] 进群欢迎消息
* [x] 群早晚安
* [x] 每日开箱重置提醒
* [x] b站转发解析解析b站分享信息支持bvbilibili链接b站手机端转发卡片cvb23.tv且5分钟内不解析相同url
* [x] 丢人爬(爬表情包)
* [x] epic通知每日发送epic免费游戏链接
* [x] 原神黄历提醒
* [x] 复读
### 已实现的看不见的技能
* [x] 刷屏禁言检测
* [x] 功能调用统计
* [x] 检测恶意触发命令将被最高权限ban掉30分钟只有最高权限(9级)可以进行unban
* [x] 自动同意好友请求,加群请求将会提醒管理员,退群提示,加群欢迎等等
* [x] 群聊时间检测当群聊最后一人发言时间大于当前36小时后将关闭该群所有通知即被动技能
* [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
* [x] 群权限系统
* [x] 定时更新权限
* [x] 自动配置重载
</details>
## 详细配置请前往文档以下为最简部署和配置如果你有基础并学习过nonebot2的话
## 简单部署
```
@ -238,26 +260,38 @@ python bot.py
```
## 使用Docker
__Docker 单机版仅真寻Bot__
**Docker 单机版仅真寻Bot**
**点击下方的 GitHub 徽标查看教程**
[![Github](https://shields.io/badge/GITHUB-Sakuracio-4476AF?logo=github&style=for-the-badge)](https://github.com/Sakuracio/zhenxun_bot_docker)
[![DOCKER](https://shields.io/badge/docker-hibikier/zhenxun_bot-4476AF?logo=docker&style=for-the-badge)](https://hub.docker.com/r/hibikier/zhenxun_bot)
__Docker 全量版(包含 真寻Bot PostgreSQL数据库 go-cqhttp webui等__
**Docker 全量版(包含 真寻Bot PostgreSQL数据库 go-cqhttp webui等**
[![Github](https://shields.io/badge/GITHUB-SinKy--Yan-4476AF?logo=github&style=for-the-badge)](https://github.com/SinKy-Yan/zhenxunbot-docker)
[![DOCKER](https://shields.io/badge/docker-jyishit/zhenxun_bot-4476AF?logo=docker&style=for-the-badge)](https://hub.docker.com/r/jyishit/zhenxun_bot)
**点击上方的 GitHub 徽标查看教程**
PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能无法正常启动全量版容器**
## [爱发电](https://afdian.net/@HibiKier)
<details>
<summary>爱发电 以及 感谢投喂 </summary>
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
### 感谢名单
(可以告诉我你的 __github__ 地址我偷偷换掉0v|)
(可以告诉我你的 **github** 地址我偷偷换掉0v|)
[shenqi](https://afdian.net/u/fa923a8cfe3d11eba61752540025c377)
[A_Kyuu](https://afdian.net/u/b83954fc2c1211eba9eb52540025c377)
[疯狂混沌](https://afdian.net/u/789a2f9200cd11edb38352540025c377)
[投冥](https://afdian.net/a/144514mm)
[茶喵](https://afdian.net/u/fd22382eac4d11ecbfc652540025c377)
[AemokpaTNR](https://afdian.net/u/1169bb8c8a9611edb0c152540025c377)
[爱发电用户_wrxn](https://afdian.net/u/4aa03d20db4311ecb1e752540025c377)
[qqw](https://afdian.net/u/b71db4e2cc3e11ebb76652540025c377)
[溫一壺月光下酒](https://afdian.net/u/ad667a5c650c11ed89bf52540025c377)
[伝木](https://afdian.net/u/246b80683f9511edba7552540025c377)
[阿奎](https://afdian.net/u/da41f72845d511ed930d52540025c377)
[醉梦尘逸](https://afdian.net/u/bc11d2683cd011ed99b552540025c377)
[Abc](https://afdian.net/u/870dc10a3cd311ed828852540025c377)
@ -280,25 +314,37 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
[ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377)
[爱发电用户_b9S4](https://afdian.net/u/3d8f30581a2911edba6d52540025c377)
[爱发电用户_c58s](https://afdian.net/u/a6ad8dda195e11ed9a4152540025c377)
[爱发电用户_eNr9](https://afdian.net/u/05fdb41c0c9a11ed814952540025c377)
[MangataAkihi](https://github.com/Sakuracio)
[](https://afdian.net/u/69b76e9ec77b11ec874f52540025c377)
[爱发电用户_eNr9](https://afdian.net/u/05fdb41c0c9a11ed814952540025c377)
[MangataAkihi](https://github.com/Sakuracio)
[](https://afdian.net/u/69b76e9ec77b11ec874f52540025c377)
[爱发电用户_Bc6j](https://afdian.net/u/8546be24f44111eca64052540025c377)
[大魔王](https://github.com/xipesoy)
[大魔王](https://github.com/xipesoy)
[CopilotLaLaLa](https://github.com/CopilotLaLaLa)
[嘿小欧](https://afdian.net/u/daa4bec4f24911ec82e552540025c377)
[嘿小欧](https://afdian.net/u/daa4bec4f24911ec82e552540025c377)
[回忆的秋千](https://afdian.net/u/e315d9c6f14f11ecbeef52540025c377)
[十年くん](https://github.com/shinianj)
[](https://afdian.net/u/9b266244f23911eca19052540025c377)
[yajiwa](https://github.com/yajiwa)
[爆金币](https://afdian.net/u/0d78879ef23711ecb22452540025c377)
</details>
## 更新
### 2022/2/18
* 数据库舍弃`gino`使用`tortoise`
* 昵称提供命令`全局昵称设置`
* `manager_group`群管理操作中`退群``修改群权限``添加/删除群白名单``添加/删除群认证`在群聊中使用命令时且未指定群聊时,默认指定当前群聊
### 2022/1/31
* 修复B站转发卡片BUG [@pull/1249](https://github.com/HibiKier/zhenxun_bot/pull/1249)
### 2022/1/27
* 替换pixiv反向代理地址 [@pull/1244](https://github.com/HibiKier/zhenxun_bot/pull/1244)
### 2022/12/31
* 修复epic报错优化简介 [@pull/1226](https://github.com/HibiKier/zhenxun_bot/pull/1226)
@ -457,7 +503,7 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
### 2022/9/27
* 更新b站转发解析 [@pull/1117](https://github.com/HibiKier/zhenxun_bot/pull/1117)
* 更新b站转发解析 [@pull/1117](https://github.com/HibiKier/zhenxun_bot/pull/1117)
### 2022/9/24
@ -556,12 +602,14 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
<br>
__..... 更多更新信息请查看文档__
**..... 更多更新信息请查看文档**
## Todo
- [x] web管理
* [x] web管理
## 感谢
[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异步机器人框架

View File

@ -1,29 +1,29 @@
import asyncio
import os
import time
from datetime import datetime
from pathlib import Path
from typing import List
import ujson as json
from nonebot.adapters.onebot.v11.message import MessageSegment
from services.log import logger
from configs.config import Config
from configs.path_config import DATA_PATH, IMAGE_PATH
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
from utils.message_builder import image
from utils.utils import get_bot, get_matchers
from pathlib import Path
from models.group_member_info import GroupInfoUser
from datetime import datetime
from services.db_context import db
from models.level_user import LevelUser
from configs.config import Config
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
import asyncio
import time
import os
import ujson as json
custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
)
ICON_PATH = IMAGE_PATH / 'other'
ICON_PATH = IMAGE_PATH / "other"
async def group_current_status(group_id: int) -> str:
@ -38,7 +38,9 @@ async def group_current_status(group_id: int) -> str:
for i, task in enumerate(_data):
name = _data[task]
name_image = BuildImage(0, 0, plain_text=f"{i+1}.{name}", font_size=20)
bk = BuildImage(name_image.w + 200, name_image.h + 20, color=(103, 177, 109), font_size=15)
bk = BuildImage(
name_image.w + 200, name_image.h + 20, color=(103, 177, 109), font_size=15
)
await bk.apaste(name_image, (10, 0), True, "by_height")
a_icon = BuildImage(40, 40, background=ICON_PATH / "btn_false.png")
if group_manager.check_group_task_status(group_id, task):
@ -123,7 +125,7 @@ def change_global_task_status(cmd: str) -> str:
task_data = group_manager.get_task_data()
status = cmd[:2]
_cmd = cmd[4:]
if '全部被动' in cmd:
if "全部被动" in cmd:
for task in task_data:
if status == "开启":
group_manager.open_global_task(task)
@ -134,7 +136,7 @@ def change_global_task_status(cmd: str) -> str:
else:
modules = [x for x in task_data if task_data[x].lower() == _cmd.lower()]
if not modules:
return '未查询到该被动任务'
return "未查询到该被动任务"
if status == "开启":
group_manager.open_global_task(modules[0])
else:
@ -301,50 +303,40 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
# try:
for user_info in _group_user_list:
nickname = user_info["card"] or user_info["nickname"]
async with db.transaction():
# 更新权限
if user_info["role"] in [
"owner",
"admin",
] and not await LevelUser.is_group_flag(user_info["user_id"], group_id):
await LevelUser.set_level(
user_info["user_id"],
user_info["group_id"],
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
)
if str(user_info["user_id"]) in bot.config.superusers:
await LevelUser.set_level(
user_info["user_id"], user_info["group_id"], 9
)
user = await GroupInfoUser.get_member_info(
user_info["user_id"], user_info["group_id"]
)
if user:
if user.user_name != nickname:
await user.update(user_name=nickname).apply()
logger.info(
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功"
)
_exist_member_list.append(int(user_info["user_id"]))
continue
join_time = datetime.strptime(
time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"])
),
"%Y-%m-%d %H:%M:%S",
)
if await GroupInfoUser.add_member_info(
# 更新权限
if user_info["role"] in [
"owner",
"admin",
] and not await LevelUser.is_group_flag(user_info["user_id"], group_id):
await LevelUser.set_level(
user_info["user_id"],
user_info["group_id"],
nickname,
join_time,
):
_exist_member_list.append(int(user_info["user_id"]))
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
else:
_error_member_list.append(
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n"
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
)
if str(user_info["user_id"]) in bot.config.superusers:
await LevelUser.set_level(user_info["user_id"], user_info["group_id"], 9)
user = await GroupInfoUser.filter(
user_qq=user_info["user_id"], group_id=user_info["group_id"]
).first()
if user:
if user.user_name != nickname:
await user.update(user_name=nickname).apply()
logger.info(
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功"
)
_exist_member_list.append(int(user_info["user_id"]))
continue
join_time = datetime.strptime(
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"])),
"%Y-%m-%d %H:%M:%S",
)
await GroupInfoUser.update_or_create(
user_qq=user_info["user_id"],
group_id=user_info["group_id"],
defaults={"user_name": nickname, "user_join_time": join_time},
)
_exist_member_list.append(int(user_info["user_id"]))
logger.info("更新成功", "更新成员信息", user_info["user_id"], user_info["group_id"])
_del_member_list = list(
set(_exist_member_list).difference(
set(await GroupInfoUser.get_group_member_id_list(group_id))
@ -352,10 +344,8 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
)
if _del_member_list:
for del_user in _del_member_list:
if await GroupInfoUser.delete_member_info(del_user, group_id):
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
else:
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
await GroupInfoUser.filter(user_qq=del_user, group_id=group_id).delete()
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
if _error_member_list and remind_superuser:
result = ""
for error_user in _error_member_list:

View File

@ -1,10 +1,10 @@
from nonebot import on_notice
from services.log import logger
from nonebot.adapters.onebot.v11 import GroupAdminNoticeEvent
from models.level_user import LevelUser
from models.group_member_info import GroupInfoUser
from configs.config import Config
from configs.config import Config
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from services.log import logger
__zx_plugin_name__ = "群管理员变动监测 [Hidden]"
__plugin_version__ = 0.1
@ -16,11 +16,11 @@ admin_notice = on_notice(priority=5)
@admin_notice.handle()
async def _(event: GroupAdminNoticeEvent):
try:
nickname = (
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
).user_name
except AttributeError:
if user := await GroupInfoUser.filter(
user_qq=event.user_id, group_id=event.group_id
).first():
nickname = user.nickname
else:
nickname = event.user_id
if event.sub_type == "set":
await LevelUser.set_level(

View File

@ -1,14 +1,14 @@
from typing import List
from configs.config import Config
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.params import CommandArg
from ._data_source import custom_group_welcome
from nonebot.adapters.onebot.v11.permission import GROUP
from configs.config import Config
from nonebot.params import CommandArg
from services.log import logger
from utils.depends import ImageList
from ._data_source import custom_group_welcome
__zx_plugin_name__ = "自定义进群欢迎消息 [Admin]"
__plugin_usage__ = """
@ -19,12 +19,14 @@ usage
Note可以通过[at]来确认是否艾特新成员
示例自定义进群欢迎消息 欢迎你[at]
""".strip()
__plugin_des__ = '简易的自定义群欢迎消息'
__plugin_cmd__ = ['自定义群欢迎消息 ?[文本] ?[图片]']
__plugin_des__ = "简易的自定义群欢迎消息"
__plugin_cmd__ = ["自定义群欢迎消息 ?[文本] ?[图片]"]
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"admin_level": Config.get_config("admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"),
"admin_level": Config.get_config(
"admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"
),
}
custom_welcome = on_command(
@ -37,7 +39,9 @@ custom_welcome = on_command(
@custom_welcome.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg(), img: List[str] = ImageList()):
async def _(
event: GroupMessageEvent, arg: Message = CommandArg(), img: List[str] = ImageList()
):
msg = arg.extract_plain_text().strip()
if not msg and not img:
await custom_welcome.finish(__plugin_usage__)

View File

@ -1,15 +1,16 @@
from utils.utils import scheduler, get_bot
from ._data_source import update_member_info
from services.log import logger
from models.group_info import GroupInfo
from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError
from models.group_info import GroupInfo
from services.log import logger
from utils.utils import get_bot, scheduler
__zx_plugin_name__ = '管理方面定时任务 [Hidden]'
__plugin_usage__ = ''
__plugin_des__ = '成员信息和管理权限的定时更新'
from ._data_source import update_member_info
__zx_plugin_name__ = "管理方面定时任务 [Hidden]"
__plugin_usage__ = ""
__plugin_des__ = "成员信息和管理权限的定时更新"
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_author__ = "HibiKier"
# 自动更新群员信息
@ -42,7 +43,7 @@ async def _():
if bot:
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
all_group = [x.group_id for x in await GroupInfo.get_all_group()]
all_group = [x.group_id for x in await GroupInfo.all()]
for g in gl:
if g not in all_group:
await update_member_info(g, False)

View File

@ -1,18 +1,22 @@
from utils.message_builder import image
from utils.utils import scheduler, get_bot
from nonebot import on_message
from services.log import logger
from models.group_info import GroupInfo
from models.friend_user import FriendUser
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import NICKNAME, Config
from pathlib import Path
import shutil
from pathlib import Path
import nonebot
from nonebot import on_message
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import NICKNAME, Config
from configs.path_config import IMAGE_PATH
from models.friend_user import FriendUser
from models.group_info import GroupInfo
from services.log import logger
from utils.message_builder import image
from utils.utils import broadcast_group, get_bot, scheduler
__zx_plugin_name__ = "定时任务相关 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {'zwa': '早晚安'}
__plugin_task__ = {"zwa": "早晚安"}
Config.add_plugin_config(
@ -24,20 +28,23 @@ Config.add_plugin_config(
)
Config.add_plugin_config(
"_backup",
"BACKUP_FLAG",
True,
help_="是否开启文件备份",
default_value=True
"_backup", "BACKUP_FLAG", True, help_="是否开启文件备份", default_value=True
)
Config.add_plugin_config(
"_backup",
"BACKUP_DIR_OR_FILE",
['data/black_word', 'data/configs', 'data/statistics', 'data/word_bank', 'data/manager', 'configs'],
[
"data/black_word",
"data/configs",
"data/statistics",
"data/word_bank",
"data/manager",
"configs",
],
name="文件备份",
help_="备份的文件夹或文件",
default_value=[]
default_value=[],
)
@ -51,18 +58,9 @@ cx = on_message(priority=9999, block=False, rule=lambda: False)
minute=1,
)
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
result = image("zao.jpg", "zhenxun")
try:
await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + result)
except ActionFailed:
logger.warning(f"{g} 发送早安失败")
except Exception as e:
logger.error(f"早晚安错误 e:{e}")
img = image(IMAGE_PATH / "zhenxun" / "zao.jpg")
await broadcast_group("[[_task|zwa]]早上好" + img, log_cmd="被动早晚安")
logger.info("每日早安发送")
# 睡觉了
@ -72,20 +70,9 @@ async def _():
minute=59,
)
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
result = image("sleep.jpg", "zhenxun")
try:
await bot.send_group_msg(
group_id=g, message=f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + result
)
except ActionFailed:
logger.warning(f"{g} 发送晚安失败")
except Exception as e:
logger.error(f"早晚安错误 e:{e}")
img = image(IMAGE_PATH / "zhenxun" / "sleep.jpg")
await broadcast_group("[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + img, log_cmd="被动早晚安")
logger.info("每日晚安发送")
# 自动更新群组信息
@ -95,22 +82,27 @@ async def _():
minute=1,
)
async def _():
try:
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
group_info = await bot.get_group_info(group_id=g)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
)
logger.info(f"自动更新群组 {g} 信息成功")
except Exception as e:
logger.error(f"自动更新群组信息错误 e:{e}")
bots = nonebot.get_bots()
_used_group = []
for bot in bots.values():
try:
group_list = await bot.get_group_list()
gl = [g["group_id"] for g in group_list if g["group_id"] not in _used_group]
for g in gl:
_used_group.append(g)
group_info = await bot.get_group_info(group_id=g)
await GroupInfo.update_or_create(
group_id=group_info["group_id"],
defaults={
"group_name": group_info["group_name"],
"max_member_count": group_info["max_member_count"],
"member_count": group_info["member_count"],
"group_flag": 1,
},
)
logger.info(f"自动更新群组信息成功", group_id=g)
except Exception as e:
logger.error(f"Bot: {bot.self_id} 自动更新群组信息", e=e)
# 自动更新好友信息
@ -124,10 +116,10 @@ async def _():
bot = get_bot()
fl = await bot.get_friend_list()
for f in fl:
if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
else:
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
await FriendUser.create(user_id=f["user_id"], user_name=f["nickname"])
logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
# else:
# logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
except Exception as e:
logger.error(f"自动更新群组信息错误 e:{e}")
@ -140,7 +132,7 @@ async def _():
)
async def _():
if Config.get_config("_backup", "BACKUP_FLAG"):
_backup_path = Path() / 'backup'
_backup_path = Path() / "backup"
_backup_path.mkdir(exist_ok=True, parents=True)
for x in Config.get_config("_backup", "BACKUP_DIR_OR_FILE"):
try:
@ -155,12 +147,13 @@ async def _():
if _p.exists():
_p.unlink()
shutil.copy(x, _p)
logger.info(f'已完成自动备份:{x}')
logger.info(f"已完成自动备份:{x}")
except Exception as e:
logger.error(f"自动备份文件 {x} 发生错误 {type(e)}:{e}")
# 一次性任务
# 固定时间触发,仅触发一次:
#
# from datetime import datetime

View File

@ -1,16 +1,22 @@
from typing import Tuple, List
from typing import List
from nonebot import on_command
from nonebot.adapters.onebot.v11 import (
Bot,
GroupMessageEvent,
Message,
MessageEvent,
PrivateMessageEvent,
)
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
from configs.config import NICKNAME, Config
from models.ban_user import BanUser
from models.level_user import LevelUser
from nonebot import on_command
from nonebot.adapters.onebot.v11 import (Bot, GroupMessageEvent, Message,
MessageEvent, PrivateMessageEvent)
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from services.log import logger
from utils.depends import AtList
from utils.utils import get_message_at, is_number
from utils.depends import AtList, OneCommand
from utils.utils import is_number
from .data_source import a_ban, parse_ban_time
@ -68,46 +74,38 @@ super_ban = on_command("b了", permission=SUPERUSER, priority=5, block=True)
async def _(
bot: Bot,
event: GroupMessageEvent,
cmd: Tuple[str, ...] = Command(),
cmd: str = OneCommand(),
arg: Message = CommandArg(),
qq: List[int] = AtList()
at_list: List[int] = AtList(),
):
cmd = cmd[0]
result = ""
if qq:
qq = qq[0]
user_name = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
user_name = user_name["card"] or user_name["nickname"]
if at_list:
qq = at_list[0]
user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
user_name = user["card"] or user["nickname"]
msg = arg.extract_plain_text().strip()
time = parse_ban_time(msg)
if isinstance(time, str):
await ban.finish(time, at_sender=True)
user_level = await LevelUser.get_user_level(event.user_id, event.group_id)
is_not_superuser = str(event.user_id) not in bot.config.superusers
if cmd in [".ban", "/ban"]:
if (
await LevelUser.get_user_level(event.user_id, event.group_id)
<= await LevelUser.get_user_level(qq, event.group_id)
and str(event.user_id) not in bot.config.superusers
):
at_user_level = await LevelUser.get_user_level(qq, event.group_id)
if user_level <= at_user_level and is_not_superuser:
await ban.finish(
f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!",
at_sender=True,
)
logger.info(f"用户封禁 时长: {time}", cmd, event.user_id, event.group_id, qq)
result = await a_ban(qq, time, user_name, event)
else:
if (
await BanUser.check_ban_level(
qq, await LevelUser.get_user_level(event.user_id, event.group_id)
)
and str(event.user_id) not in bot.config.superusers
):
if await BanUser.check_ban_level(qq, user_level) and is_not_superuser:
await ban.finish(
f"ban掉 {user_name} 的管理员权限比您高无法进行unban", at_sender=True
)
if await BanUser.unban(qq):
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 解禁"
)
result = f"已经把 {user_name} 从黑名单中删除了!"
logger.info(f"解除用户封禁", cmd, event.user_id, event.group_id, qq)
result = f"已经将 {user_name} 从黑名单中删除了!"
else:
result = f"{user_name} 不在黑名单!"
else:
@ -119,54 +117,62 @@ async def _(
async def _(
bot: Bot,
event: PrivateMessageEvent,
cmd: Tuple[str, ...] = Command(),
cmd: str = OneCommand(),
arg: Message = CommandArg(),
):
cmd = cmd[0]
msg = arg.extract_plain_text().strip()
if msg:
if str(event.user_id) in bot.config.superusers:
msg_splt = msg.split()
if is_number(msg_splt[0]):
qq = int(msg_splt[0])
msg = msg_splt[1:]
if cmd in [".ban", "/ban"]:
time = parse_ban_time(" ".join(msg))
if isinstance(time, str):
await ban.finish(time)
result = await a_ban(qq, time, str(qq), event, 9)
else:
if await BanUser.unban(qq):
logger.info(f"USER {event.user_id} 将 USER {qq} 解禁")
result = f"已经把 {qq} 从黑名单中删除了!"
else:
result = f"{qq} 不在黑名单!"
await ban.send(result)
if msg and str(event.user_id) in bot.config.superusers:
msg_split = msg.split()
if msg_split and is_number(msg_split[0]):
qq = int(msg_split[0])
param = msg_split[1:]
if cmd in [".ban", "/ban"]:
time = parse_ban_time(" ".join(param))
if isinstance(time, str):
logger.info(time, cmd, event.user_id, target=qq)
await ban.finish(time)
result = await a_ban(qq, time, str(qq), event, 9)
else:
await ban.finish(
"qq号必须是数字\n格式:.ban [qq] [hour]? [minute]?", at_sender=True
)
if await BanUser.unban(qq):
result = f"已经把 {qq} 从黑名单中删除了!"
else:
result = f"{qq} 不在黑名单!"
await ban.send(result)
logger.info(result, cmd, event.user_id, target=qq)
else:
await ban.send("参数不正确!\n格式:.ban [qq] [hour]? [minute]?", at_sender=True)
@super_ban.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
async def _(
bot: Bot,
event: MessageEvent,
cmd: str = OneCommand(),
arg: Message = CommandArg(),
at_list: List[int] = AtList(),
):
user_name = ""
qq = None
if isinstance(event, GroupMessageEvent):
qq = get_message_at(event.json())
if qq:
qq = qq[0]
if at_list:
qq = at_list[0]
user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
user_name = user["card"] or user["nickname"]
else:
qq = arg.extract_plain_text().strip()
if not is_number(qq):
msg = arg.extract_plain_text().strip()
if not is_number(msg):
await super_ban.finish("对象qq必须为纯数字...")
qq = int(qq)
user_name = qq
qq = int(msg)
user_name = msg
if qq:
if not await BanUser.ban(qq, 10, 99999999):
await BanUser.unban(qq)
await BanUser.ban(qq, 10, 99999999)
await BanUser.ban(qq, 10, 99999999)
await ban.send(f"已将 {user_name} 拉入黑名单!")
logger.info(
f"已将 {user_name} 拉入黑名单!",
cmd,
event.user_id,
event.group_id if isinstance(event, GroupMessageEvent) else None,
qq,
)
else:
await super_ban.send("需要添加被super ban的对象可以使用at或者指定qq..")
await super_ban.send("需要提供被super ban的对象可以使用at或者指定qq...")

View File

@ -1,10 +1,12 @@
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from typing import Optional, Union
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from configs.config import NICKNAME
from models.level_user import LevelUser
from utils.utils import is_number
from models.ban_user import BanUser
from models.level_user import LevelUser
from services.log import logger
from typing import Union
from utils.utils import is_number
def parse_ban_time(msg: str) -> Union[int, str]:
@ -12,21 +14,31 @@ def parse_ban_time(msg: str) -> Union[int, str]:
解析ban时长
:param msg: 文本消息
"""
if not msg:
return -1
msg = msg.split()
if len(msg) == 1:
if not is_number(msg[0].strip()):
return "参数必须是数字!"
return int(msg[0]) * 60 * 60
else:
if not is_number(msg[0].strip()) or not is_number(msg[1].strip()):
return "参数必须是数字!"
return int(msg[0]) * 60 * 60 + int(msg[1]) * 60
try:
if not msg:
return -1
msg_split = msg.split()
if len(msg_split) == 1:
if not is_number(msg_split[0].strip()):
return "参数必须是数字!"
return int(msg_split[0]) * 60 * 60
else:
if not is_number(msg_split[0].strip()) or not is_number(
msg_split[1].strip()
):
return "参数必须是数字!"
return int(msg_split[0]) * 60 * 60 + int(msg_split[1]) * 60
except ValueError as e:
logger.error("解析ban时长错误", ".ban", e=e)
return "时长不可以带小数点!"
async def a_ban(
qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None
qq: int,
time: int,
user_name: str,
event: MessageEvent,
ban_level: Optional[int] = None,
) -> str:
"""
ban
@ -36,12 +48,15 @@ async def a_ban(
:param event: event
:param ban_level: ban级别
"""
group_id = None
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
ban_level = await LevelUser.get_user_level(event.user_id, event.group_id)
if not ban_level:
return "未查询到ban级用户权限"
if await BanUser.ban(qq, ban_level, time):
logger.info(
f"USER {event.user_id} GROUP"
f" {event.group_id if isinstance(event, GroupMessageEvent) else ''} 将 USER {qq} 封禁 时长 {time / 60} 分钟"
f"将 [Target]({qq})封禁 时长 {time / 60} 分钟", ".ban", event.user_id, group_id
)
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
if time != -1:
@ -49,14 +64,14 @@ async def a_ban(
else:
result += f"将在 ∞ 分钟后解封"
else:
time = await BanUser.check_ban_time(qq)
if is_number(time):
time = abs(int(time))
if time < 60:
time = str(time) + ""
ban_time = await BanUser.check_ban_time(qq)
if isinstance(ban_time, int):
ban_time = abs(float(ban_time))
if ban_time < 60:
ban_time = str(ban_time) + ""
else:
time = str(int(time / 60)) + " 分钟"
ban_time = str(int(ban_time / 60)) + " 分钟"
else:
time += " 分钟"
result = f"{user_name} 已在黑名单!预计 {time}后解封"
ban_time += " 分钟"
result = f"{user_name} 已在黑名单!预计 {ban_time}后解封"
return result

View File

@ -1,8 +1,11 @@
from configs.config import Config
from models.chat_history import ChatHistory
from nonebot import on_message
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from configs.config import Config
from models.chat_history import ChatHistory
from services.log import logger
from utils.depends import PlaintText
from utils.utils import scheduler
from ._rule import rule
@ -19,14 +22,38 @@ Config.add_plugin_config(
chat_history = on_message(rule=rule, priority=1, block=False)
TEMP_LIST = []
@chat_history.handle()
async def _(event: MessageEvent, msg: str = PlaintText()):
group_id = None
if isinstance(event, GroupMessageEvent):
await ChatHistory.add_chat_msg(
event.user_id, event.group_id, str(event.get_message()), msg
)
else:
await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message()), msg)
group_id = event.group_id
TEMP_LIST.append(
{
"user_qq": event.user_id,
"group_id": group_id,
"text": str(event.get_message()),
"plain_text": msg,
}
)
@scheduler.scheduled_job(
"interval",
minutes=1,
)
async def _():
try:
message_list = TEMP_LIST.copy()
TEMP_LIST.clear()
if message_list:
model_list = [ChatHistory(**x) for x in message_list]
await ChatHistory.bulk_create(model_list)
logger.debug(f"批量添加聊天记录 {len(message_list)}", "定时任务")
except Exception as e:
logger.error(f"定时批量添加聊天记录", "定时任务", e=e)
# @test.handle()

View File

@ -1,16 +1,16 @@
from datetime import datetime, timedelta
from typing import Any, Tuple
import pytz
from models.chat_history import ChatHistory
from models.group_member_info import GroupInfoUser
from nonebot import on_regex
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from nonebot.params import RegexGroup
from utils.image_utils import BuildImage, text2image
from utils.utils import is_number
from utils.message_builder import image
from typing import Tuple, Any
from models.chat_history import ChatHistory
from models.group_member_info import GroupInfoUser
from utils.image_utils import BuildImage, text2image
from utils.message_builder import image
from utils.utils import is_number
__zx_plugin_name__ = "消息统计"
__plugin_usage__ = """
@ -29,12 +29,7 @@ usage
消息统计n=15
""".strip()
__plugin_des__ = "发言消息排行"
__plugin_cmd__ = [
"消息统计",
"周消息统计",
"月消息统计",
"日消息统计"
]
__plugin_cmd__ = ["消息统计", "周消息统计", "月消息统计", "日消息统计"]
__plugin_type__ = ("数据统计", 1)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
@ -44,7 +39,9 @@ __plugin_settings__ = {
}
msg_handler = on_regex(r"^(周|月|日)?消息统计(des|DES)?(n=[0-9]{1,2})?$", priority=5, block=True)
msg_handler = on_regex(
r"^(周|月|日)?消息统计(des|DES)?(n=[0-9]{1,2})?$", priority=5, block=True
)
@msg_handler.handle()
@ -56,7 +53,9 @@ async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup())
if num and is_number(num) and 10 < int(num) < 50:
num = int(num)
time_now = datetime.now()
zero_today = time_now - timedelta(hours=time_now.hour, minutes=time_now.minute, seconds=time_now.second)
zero_today = time_now - timedelta(
hours=time_now.hour, minutes=time_now.minute, seconds=time_now.second
)
if date in [""]:
date_scope = (zero_today, time_now)
elif date in [""]:
@ -70,9 +69,9 @@ async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup())
num_str = "发言次数:\n\n"
idx = 1
for uid, num in rank_data:
try:
user_name = (await GroupInfoUser.get_member_info(uid, gid)).user_name
except AttributeError:
if user := await GroupInfoUser.filter(user_qq=uid, group_id=gid).first():
user_name = user.user_name
else:
user_name = uid
name += f"\t{idx}.{user_name} \n\n"
num_str += f"\t{num}\n\n"

View File

@ -1,26 +1,27 @@
from nonebot import on_notice, on_request
from configs.path_config import IMAGE_PATH, DATA_PATH
from models.level_user import LevelUser
from utils.message_builder import image
from models.group_member_info import GroupInfoUser
from datetime import datetime
from services.log import logger
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
GroupIncreaseNoticeEvent,
GroupDecreaseNoticeEvent,
)
from utils.manager import group_manager, plugins2settings_manager, requests_manager
from configs.config import NICKNAME
from models.group_info import GroupInfo
from utils.utils import FreqLimiter
from configs.config import Config
from pathlib import Path
import random
import os
import ujson as json
import random
from datetime import datetime
from pathlib import Path
import ujson as json
from nonebot import on_notice, on_request
from nonebot.adapters.onebot.v11 import (
ActionFailed,
Bot,
GroupDecreaseNoticeEvent,
GroupIncreaseNoticeEvent,
)
from configs.config import NICKNAME, Config
from configs.path_config import DATA_PATH, IMAGE_PATH
from models.group_info import GroupInfo
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from services.log import logger
from utils.depends import GetConfig
from utils.manager import group_manager, plugins2settings_manager, requests_manager
from utils.message_builder import image
from utils.utils import FreqLimiter
__zx_plugin_name__ = "群事件处理 [Hidden]"
__plugin_version__ = 0.1
@ -65,7 +66,7 @@ add_group = on_request(priority=1, block=False)
@group_increase_handle.handle()
async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
if event.user_id == int(bot.self_id):
group = await GroupInfo.get_group_info(event.group_id)
group = await GroupInfo.filter(group_id=event.group_id).first()
# 群聊不存在或被强制拉群,退出该群
if (not group or group.group_flag == 0) and Config.get_config(
"invite_manager", "flag"
@ -115,15 +116,12 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
user_info = await bot.get_group_member_info(
group_id=event.group_id, user_id=event.user_id
)
if await GroupInfoUser.add_member_info(
user_info["user_id"],
user_info["group_id"],
user_info["nickname"],
join_time,
):
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
else:
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
await GroupInfoUser.update_or_create(
user_qq=user_info["user_id"],
group_id=user_info["group_id"],
defaults={"user_name": user_info["nickname"], "user_join_time": join_time},
)
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
# 群欢迎消息
if _flmt.check(event.group_id):
@ -152,7 +150,11 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
else:
await group_increase_handle.send(
"[[_task|group_welcome]]新人快跑啊!!本群现状↓(快使用自定义!)"
+ image(random.choice(os.listdir(IMAGE_PATH / "qxz")), "qxz")
+ image(
IMAGE_PATH
/ "qxz"
/ random.choice(os.listdir(IMAGE_PATH / "qxz"))
)
)
@ -162,13 +164,13 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent):
if event.sub_type == "kick_me":
group_id = event.group_id
operator_id = event.operator_id
try:
operator_name = (
await GroupInfoUser.get_member_info(event.operator_id, event.group_id)
).user_name
except AttributeError:
if user := await GroupInfoUser.get_or_none(
user_qq=event.operator_id, group_id=event.group_id
):
operator_name = user.user_name
else:
operator_name = "None"
group = await GroupInfo.get_group_info(group_id)
group = await GroupInfo.filter(group_id=group_id).first()
group_name = group.group_name if group else ""
coffee = int(list(bot.config.superusers)[0])
await bot.send_private_msg(
@ -182,16 +184,19 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent):
if event.user_id == int(bot.self_id):
group_manager.delete_group(event.group_id)
return
try:
user_name = (
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
).user_name
except AttributeError:
user_name = str(event.user_id)
if await GroupInfoUser.delete_member_info(event.user_id, event.group_id):
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除成功")
if user := await GroupInfoUser.get_or_none(
user_qq=event.user_id, group_id=event.group_id
):
user_name = user.user_name
else:
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败")
user_name = f"{event.user_id}"
await GroupInfoUser.filter(user_qq=event.user_id, group_id=event.group_id).delete()
logger.info(
f"名称: {user_name} 退出群聊",
"group_decrease_handle",
event.user_id,
event.group_id,
)
rst = ""
if event.sub_type == "leave":
rst = f"{user_name}离开了我们..."

View File

@ -1,39 +1,40 @@
import time
from typing import Optional
import nonebot
from nonebot.adapters.onebot.v11 import (
GroupMessageEvent,
PrivateMessageEvent,
Bot,
Event,
MessageEvent,
GroupMessageEvent,
Message,
MessageEvent,
PokeNotifyEvent,
PrivateMessageEvent,
)
from nonebot.exception import ActionFailed, IgnoredException
from nonebot.internal.matcher import Matcher
from configs.config import Config
from models.bag_user import BagUser
from models.ban_user import BanUser
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from models.user_shop_gold_log import UserShopGoldLog
from services.log import logger
from utils.decorator import Singleton
from utils.manager import (
plugins2block_manager,
StaticData,
plugins2settings_manager,
group_manager,
admin_manager,
plugins_manager,
group_manager,
plugins2block_manager,
plugins2cd_manager,
plugins2count_manager,
plugins2settings_manager,
plugins_manager,
)
from utils.message_builder import at
from utils.utils import FreqLimiter
from configs.config import Config
import time
ignore_rst_module = ["ai", "poke", "dialogue"]
@ -97,11 +98,11 @@ async def send_msg(msg: str, bot: Bot, event: MessageEvent):
msg = msg.replace("[uname]", uname)
if "[nickname]" in msg:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
nickname = await GroupInfoUser.get_user_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
nickname = await FriendUser.get_user_nickname(event.user_id)
msg = msg.replace("[nickname]", nickname)
if "[at]" in msg and isinstance(event, GroupMessageEvent):
msg = msg.replace("[at]", str(at(event.user_id)))
@ -142,16 +143,19 @@ class AuthChecker:
:param event: event
"""
try:
plugin_name = matcher.plugin_name
cost_gold = await self.auth_cost(plugin_name, bot, event)
if hasattr(event, "user_id") and str(event.user_id) not in bot.config.superusers:
await self.auth_basic(plugin_name, bot, event)
self.auth_group(plugin_name, bot, event)
await self.auth_admin(plugin_name, matcher, bot, event)
await self.auth_plugin(plugin_name, matcher, bot, event)
await self.auth_limit(plugin_name, bot, event)
if cost_gold:
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
if plugin_name := matcher.plugin_name:
cost_gold = await self.auth_cost(plugin_name, bot, event)
user_id = getattr(event, "user_id", None)
if user_id and str(user_id) not in bot.config.superusers:
await self.auth_basic(plugin_name, bot, event)
self.auth_group(plugin_name, bot, event)
await self.auth_admin(plugin_name, matcher, bot, event)
await self.auth_plugin(plugin_name, matcher, bot, event)
await self.auth_limit(plugin_name, bot, event)
if cost_gold:
await BagUser.spend_gold(
event.user_id, event.group_id, cost_gold
)
except IsSuperuserException:
return
@ -221,7 +225,9 @@ class AuthChecker:
else:
plugins2count_manager.increase(plugin_name, count_type_)
async def auth_plugin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
async def auth_plugin(
self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event
):
"""
说明:
插件状态
@ -345,6 +351,7 @@ class AuthChecker:
and plugin_name not in ignore_rst_module
):
self._flmt_c.start_cd(event.group_id)
logger.info(f"{event.user_id} ||XXXXXX: {matcher.module}")
await bot.send_group_msg(
group_id=event.group_id, message="此功能正在维护..."
)
@ -364,7 +371,9 @@ class AuthChecker:
set_block_limit_false(event, plugin_name)
raise IgnoredException("此功能正在维护...")
async def auth_admin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
async def auth_admin(
self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event
):
"""
说明:
管理员命令 个人权限
@ -504,8 +513,13 @@ class AuthChecker:
await BagUser.spend_gold(
event.user_id, event.group_id, psm.cost_gold
)
await UserShopGoldLog.add_shop_log(
event.user_id, event.group_id, 2, plugin_name, psm.cost_gold, 1
await UserShopGoldLog.create(
user_qq=event.user_id,
group_id=event.group_id,
type=2,
name=plugin_name,
num=1,
spend_gold=psm.cost_gold,
)
cost_gold = psm.cost_gold
return cost_gold

View File

@ -1,20 +1,21 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
ActionFailed,
Bot,
Event,
MessageEvent,
ActionFailed,
PokeNotifyEvent,
GroupMessageEvent,
MessageEvent,
PokeNotifyEvent,
)
from nonebot.matcher import Matcher
from nonebot.message import IgnoredException, run_preprocessor
from nonebot.typing import T_State
from configs.config import Config
from models.ban_user import BanUser
from utils.utils import is_number, static_flmt, FreqLimiter
from utils.message_builder import at
from ._utils import ignore_rst_module, other_limit_plugins
from utils.utils import FreqLimiter, is_number, static_flmt
from ._utils import ignore_rst_module, other_limit_plugins
Config.add_plugin_config(
"hook",
@ -49,7 +50,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
and str(event.user_id) not in bot.config.superusers
):
time = await BanUser.check_ban_time(event.user_id)
if is_number(time):
if isinstance(time, int):
time = abs(int(time))
if time < 60:
time = str(time) + ""

View File

@ -28,12 +28,12 @@ async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State
if matcher.type == "message" and matcher.priority not in [1, 999]:
if state["_prefix"]["raw_command"]:
if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
if await BanUser.ban(
await BanUser.ban(
event.user_id,
9,
Config.get_config("hook", "MALICIOUS_BAN_TIME") * 60,
):
logger.info(f"USER {event.user_id} 触发了恶意触发检测")
)
logger.info(f"USER {event.user_id} 触发了恶意触发检测")
if isinstance(event, GroupMessageEvent):
try:
await bot.send_group_msg(

View File

@ -1,23 +1,23 @@
import nonebot
from nonebot import Driver
from nonebot.adapters.onebot.v11 import Bot
from configs.path_config import DATA_PATH
from .init_group_manager import init_group_manager, group_manager
from services.log import logger
from .check_plugin_status import check_plugin_status
from .init import init
from .init_none_plugin_count_manager import init_none_plugin_count_manager
from .init_plugin_info import init_plugin_info
from .init_plugins_config import init_plugins_config
from .init_plugins_data import init_plugins_data, plugins_manager
from .init_none_plugin_count_manager import init_none_plugin_count_manager
from .init_plugins_resources import init_plugins_resources
from .init_plugins_settings import init_plugins_settings
from .init_plugin_info import init_plugin_info
from .init_plugins_limit import (
init_plugins_block_limit,
init_plugins_count_limit,
init_plugins_cd_limit,
init_plugins_count_limit,
)
from .init import init
from .check_plugin_status import check_plugin_status
from nonebot.adapters.onebot.v11 import Bot
from services.log import logger
from nonebot import Driver
import nonebot
from .init_plugins_resources import init_plugins_resources
from .init_plugins_settings import init_plugins_settings
__zx_plugin_name__ = "初始化插件数据 [Hidden]"
__plugin_version__ = 0.1
@ -44,10 +44,6 @@ async def _():
init_plugins_config()
init_plugins_resources()
init_none_plugin_count_manager()
# x = group_manager.get_super_old_data()
# if x:
# for key in x.keys():
# plugins_manager.block_plugin(key, block_type=x[key])
if _flag:
raise Exception("首次运行已在configs目录下生成配置文件config.yaml修改后重启即可...")
logger.info("初始化数据完成...")

View File

@ -1,73 +0,0 @@
from pathlib import Path
from utils.manager import group_manager
from services.db_context import db
from asyncpg.exceptions import DuplicateColumnError
from services.log import logger
try:
import ujson as json
except ModuleNotFoundError:
import json
try:
from models.group_remind import GroupRemind
except ModuleNotFoundError:
pass
async def init_group_manager():
"""
旧数据格式替换为新格式
初始化数据
"""
old_group_level_file = Path() / "data" / "manager" / "group_level.json"
old_plugin_list_file = Path() / "data" / "manager" / "plugin_list.json"
if old_group_level_file.exists():
data = json.load(open(old_group_level_file, "r", encoding="utf8"))
for key in data.keys():
group = key
level = data[key]
group_manager.set_group_level(group, level)
old_group_level_file.unlink()
group_manager.save()
if old_plugin_list_file.exists():
data = json.load(open(old_plugin_list_file, "r", encoding="utf8"))
for plugin in data.keys():
for group in data[plugin].keys():
if group == "default" and not data[plugin]["default"]:
group_manager.block_plugin(plugin)
elif not data[plugin][group]:
group_manager.block_plugin(plugin, group)
old_plugin_list_file.unlink()
old_data_table = Path() / "models" / "group_remind.py"
try:
if old_data_table.exists():
b = {
"hy": "group_welcome",
"kxcz": "open_case_reset_remind",
"zwa": "zwa",
"blpar": "bilibili_parse",
"epic": "epic_free_game",
"pa": "pa",
"almanac": "genshin_alc",
}
for group in group_manager.get_data()["group_manager"]:
for remind in b:
try:
status = await GroupRemind.get_status(int(group), remind)
if status is not None:
if status:
await group_manager.open_group_task(group, b[remind])
logger.info(f"读取旧数据-->{group} 开启 {b[remind]}")
else:
await group_manager.close_group_task(group, b[remind])
logger.info(f"读取旧数据-->{group} 关闭 {b[remind]}")
except Exception as e:
pass
query = db.text("DROP TABLE group_reminds;")
await db.first(query)
old_data_table.unlink()
logger.info("旧数据读取完毕,删除了舍弃表 group_reminds...")
except (ModuleNotFoundError, DuplicateColumnError):
pass
group_manager.save()

View File

@ -27,6 +27,8 @@ def init_plugins_settings():
else:
if plugin_data := plugin_data_manager.get(matcher.plugin_name):
if plugin_settings := plugin_data.plugin_setting:
if (name := _module.__getattribute__("__zx_plugin_name__")) not in plugin_settings.cmd:
plugin_settings.cmd.append(name)
# 管理员命令
if plugin_data.plugin_type == PluginType.ADMIN:
admin_manager.add_admin_plugin_settings(

View File

@ -1,20 +1,25 @@
from nonebot import on_request, on_message
import asyncio
import re
import time
from datetime import datetime
from nonebot import on_message, on_request
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
Bot,
FriendRequestEvent,
GroupRequestEvent,
MessageEvent,
)
from models.friend_user import FriendUser
from datetime import datetime
from configs.config import NICKNAME, Config
from utils.manager import requests_manager
from models.friend_user import FriendUser
from models.group_info import GroupInfo
from services.log import logger
from utils.manager import requests_manager
from utils.utils import scheduler
import asyncio
import time
import re
from .utils import time_manager
__zx_plugin_name__ = "好友群聊处理请求 [Hidden]"
__plugin_version__ = 0.1
@ -27,101 +32,109 @@ friend_req = on_request(priority=5, block=True)
group_req = on_request(priority=5, block=True)
x = on_message(priority=999, block=False, rule=lambda: False)
exists_data = {"private": {}, "group": {}}
@friend_req.handle()
async def _(bot: Bot, event: FriendRequestEvent):
global exists_data
if exists_data["private"].get(event.user_id):
if time.time() - exists_data["private"][event.user_id] < 60 * 5:
return
exists_data["private"][event.user_id] = time.time()
user = await bot.get_stranger_info(user_id=event.user_id)
nickname = user["nickname"]
sex = user["sex"]
age = str(user["age"])
comment = event.comment
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份好友申请*****\n"
f"昵称:{nickname}({event.user_id})\n"
f"自动同意:{'' if Config.get_config('invite_manager', 'AUTO_ADD_FRIEND') else '×'}\n"
f"日期:{str(datetime.now()).split('.')[0]}\n"
f"备注:{event.comment}",
)
if Config.get_config("invite_manager", "AUTO_ADD_FRIEND"):
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.add_friend_info(user["user_id"], user["nickname"])
else:
requests_manager.add_request(
event.user_id,
"private",
event.flag,
nickname=nickname,
sex=sex,
age=age,
comment=comment,
if time_manager.add_user_request(event.user_id):
logger.debug(f"收录 用户[{event.user_id}] 好友请求", "好友请求")
user = await bot.get_stranger_info(user_id=event.user_id)
nickname = user["nickname"]
sex = user["sex"]
age = str(user["age"])
comment = event.comment
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份好友申请*****\n"
f"昵称:{nickname}({event.user_id})\n"
f"自动同意:{'' if Config.get_config('invite_manager', 'AUTO_ADD_FRIEND') else '×'}\n"
f"日期:{str(datetime.now()).split('.')[0]}\n"
f"备注:{event.comment}",
)
if Config.get_config("invite_manager", "AUTO_ADD_FRIEND"):
logger.debug(f"已开启好友请求自动同意,成功通过该请求", "好友请求", target=event.user_id)
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.create(user_id=user["user_id"], user_name=user["nickname"])
else:
requests_manager.add_request(
event.user_id,
"private",
event.flag,
nickname=nickname,
sex=sex,
age=age,
comment=comment,
)
else:
logger.debug(f"好友请求五分钟内重复, 已忽略", "好友请求", target=event.user_id)
@group_req.handle()
async def _(bot: Bot, event: GroupRequestEvent):
global exists_data
# 邀请
if event.sub_type == "invite":
if str(event.user_id) in bot.config.superusers:
try:
if await GroupInfo.get_group_info(event.group_id):
await GroupInfo.set_group_flag(event.group_id, 1)
else:
group_info = await bot.get_group_info(group_id=event.group_id)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
logger.debug(
f"超级用户自动同意加入群聊", "群聊请求", event.user_id, target=event.group_id
)
await bot.set_group_add_request(
flag=event.flag, sub_type="invite", approve=True
)
except ActionFailed:
pass
group_info = await bot.get_group_info(group_id=event.group_id)
await GroupInfo.update_or_create(
group_id=group_info["group_id"],
defaults={
"group_name": group_info["group_name"],
"max_member_count": group_info["max_member_count"],
"member_count": group_info["member_count"],
"group_flag": 1,
},
)
except ActionFailed as e:
logger.error(
"超级用户自动同意加入群聊发生错误",
"群聊请求",
event.user_id,
target=event.group_id,
e=e,
)
else:
user = await bot.get_stranger_info(user_id=event.user_id)
sex = user["sex"]
age = str(user["age"])
if exists_data["group"].get(f"{event.user_id}:{event.group_id}"):
if (
time.time()
- exists_data["group"][f"{event.user_id}:{event.group_id}"]
< 60 * 5
):
return
exists_data["group"][f"{event.user_id}:{event.group_id}"] = time.time()
nickname = await FriendUser.get_user_name(event.user_id)
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份入群申请*****\n"
f"申请人:{nickname}({event.user_id})\n"
f"群聊:{event.group_id}\n"
f"邀请日期:{str(datetime.now()).split('.')[0]}",
)
await bot.send_private_msg(
user_id=event.user_id,
message=f"想要邀请我偷偷入群嘛~已经提醒{NICKNAME}的管理员大人了\n"
"请确保已经群主或群管理沟通过!\n"
"等待管理员处理吧!",
)
requests_manager.add_request(
event.user_id,
"group",
event.flag,
invite_group=event.group_id,
nickname=nickname,
sex=sex,
age=age,
)
if time_manager.add_group_request(event.user_id, event.group_id):
logger.debug(
f"收录 用户[{event.user_id}] 群聊[{event.group_id}] 群聊请求", "群聊请求"
)
user = await bot.get_stranger_info(user_id=event.user_id)
sex = user["sex"]
age = str(user["age"])
nickname = await FriendUser.get_user_name(event.user_id)
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"*****一份入群申请*****\n"
f"申请人:{nickname}({event.user_id})\n"
f"群聊:{event.group_id}\n"
f"邀请日期:{datetime.now().replace(microsecond=0)}",
)
await bot.send_private_msg(
user_id=event.user_id,
message=f"想要邀请我偷偷入群嘛~已经提醒{NICKNAME}的管理员大人了\n"
"请确保已经群主或群管理沟通过!\n"
"等待管理员处理吧!",
)
requests_manager.add_request(
event.user_id,
"group",
event.flag,
invite_group=event.group_id,
nickname=nickname,
sex=sex,
age=age,
)
else:
logger.debug(
f"群聊请求五分钟内重复, 已忽略",
"群聊请求",
target=f"{event.user_id}:{event.group_id}",
)
@x.handle()
@ -145,5 +158,4 @@ async def _(event: MessageEvent):
minutes=5,
)
async def _():
global exists_data
exists_data = {"private": {}, "group": {}}
time_manager.clear()

View File

@ -0,0 +1,87 @@
import time
from dataclasses import dataclass
from typing import Dict
@dataclass
class PrivateRequest:
"""
好友请求
"""
user_id: int
time: float = time.time()
@dataclass
class GroupRequest:
"""
群聊请求
"""
user_id: int
group_id: int
time: float = time.time()
class RequestTimeManage:
"""
过滤五分钟以内的重复请求
"""
def __init__(self):
self._group: Dict[str, GroupRequest] = {}
self._user: Dict[int, PrivateRequest] = {}
def add_user_request(self, user_id: int) -> bool:
"""
添加请求时间
Args:
user_id (int): 用户id
Returns:
bool: 是否满足时间
"""
if user := self._user.get(user_id):
if time.time() - user.time < 60 * 5:
return False
self._user[user_id] = PrivateRequest(user_id)
return True
def add_group_request(self, user_id: int, group_id: int) -> bool:
"""
添加请求时间
Args:
user_id (int): 用户id
group_id (int): 邀请群聊
Returns:
bool: 是否满足时间
"""
key = f"{user_id}:{group_id}"
if group := self._group.get(key):
if time.time() - group.time < 60 * 5:
return False
self._group[key] = GroupRequest(user_id=user_id, group_id=group_id)
return True
def clear(self):
"""
清理过期五分钟请求
"""
now = time.time()
for user_id in self._user:
if now - self._user[user_id].time < 60 * 5:
del self._user[user_id]
for key in self._group:
if now - self._group[key].time < 60 * 5:
del self._group[key]
time_manager = RequestTimeManage()

View File

@ -1,121 +1,162 @@
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message, MessageEvent
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.rule import to_me
from models.group_member_info import GroupInfoUser
from models.friend_user import FriendUser
from models.ban_user import BanUser
from services.log import logger
from configs.config import NICKNAME, Config
from nonebot.params import CommandArg
import random
from typing import Any, Tuple
from nonebot import on_command, on_regex
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.internal.matcher import Matcher
from nonebot.internal.params import Depends
from nonebot.params import CommandArg, RegexGroup
from nonebot.rule import to_me
from configs.config import NICKNAME
from models.ban_user import BanUser
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.depends import GetConfig
__zx_plugin_name__ = "昵称系统"
__plugin_usage__ = f"""
usage
个人昵称系统群聊 私聊 昵称相互独立
个人昵称将替换真寻称呼你的名称群聊 私聊 昵称相互独立全局昵称设置将更改您目前所有群聊中及私聊的昵称
指令
以后叫我 [昵称]
以后叫我 [昵称]: 设置当前群聊/私聊的昵称
全局昵称设置 [昵称]: 设置当前所有群聊和私聊的昵称
{NICKNAME}我是谁
""".strip()
__plugin_des__ = "区区昵称,才不想叫呢!"
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁", "全局昵称设置 [昵称]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["昵称", "昵称系统"],
"cmd": ["昵称"],
}
__plugin_configs__ = {
"BLACK_WORD": {
"value": ["", "", "", ""],
"help": "昵称所屏蔽的关键词,会被替换为 *",
"default_value": None
"value": ["", "", "", ""],
"help": "昵称所屏蔽的关键词,已设置的昵称会被替换为 *,未设置的昵称会在设置时提示",
"default_value": None,
}
}
nickname = on_command(
"nickname",
aliases={"以后叫我", "以后请叫我", "称呼我", "以后请称呼我", "以后称呼我", "叫我", "请叫我"},
nickname = on_regex(
"(?:以后)?(?:叫我|请叫我|称呼我)(.*)",
rule=to_me(),
priority=5,
block=True,
)
my_nickname = on_command(
"my_name", aliases={"我叫什么", "我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
"我叫什么", aliases={"我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
)
global_nickname = on_regex("设置全局昵称(.*)", rule=to_me(), priority=5, block=True)
cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=True)
@nickname.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if not msg:
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
if len(msg) > 10:
await nickname.finish("昵称可不能超过10个字", at_sender=True)
if msg in bot.config.superusers:
await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True)
_tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
for x in msg:
_tmp += "*" if x in black_word else x
msg = _tmp
def CheckNickname():
"""
说明:
检查名称是否合法
"""
async def dependency(
bot: Bot,
matcher: Matcher,
event: MessageEvent,
reg_group: Tuple[Any, ...] = RegexGroup(),
black_word: Any = GetConfig(config="BLACK_WORD"),
):
(msg,) = reg_group
logger.debug(f"昵称检查: {msg}", "昵称设置", event.user_id)
if not msg:
await matcher.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
if str(event.user_id) in bot.config.superusers:
logger.debug(f"超级用户设置昵称, 跳过合法检测: {msg}", "昵称设置", event.user_id)
return
if len(msg) > 20:
await nickname.finish("昵称可不能超过20个字", at_sender=True)
if msg in bot.config.nickname:
await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True)
if black_word:
for x in msg:
if x in black_word:
logger.debug("昵称设置禁止字符: [{x}]", "昵称设置", event.user_id)
await nickname.finish(f"字符 [{x}] 为禁止字符!", at_sender=True)
for word in black_word:
if word in msg:
logger.debug("昵称设置禁止字符: [{word}]", "昵称设置", event.user_id)
await nickname.finish(f"字符 [{word}] 为禁止字符!", at_sender=True)
return Depends(dependency)
@global_nickname.handle(parameterless=[CheckNickname()])
async def _(
event: MessageEvent,
reg_group: Tuple[Any, ...] = RegexGroup(),
):
(msg,) = reg_group
await FriendUser.set_user_nickname(event.user_id, msg)
await GroupInfoUser.filter(user_qq=event.user_id).update(nickname=msg)
logger.info(f"设置全局昵称成功: {msg}", "设置全局昵称", event.user_id)
await global_nickname.send(f"设置全局昵称成功!亲爱的{msg}")
@nickname.handle(parameterless=[CheckNickname()])
async def _(
event: MessageEvent,
reg_group: Tuple[Any, ...] = RegexGroup(),
):
(msg,) = reg_group
if isinstance(event, GroupMessageEvent):
if await GroupInfoUser.set_group_member_nickname(
event.user_id, event.group_id, msg
):
if len(msg) < 5:
if random.random() < 0.3:
msg = "~".join(msg)
await nickname.send(
random.choice(
[
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
)
await GroupInfoUser.set_user_nickname(event.user_id, event.group_id, msg)
if len(msg) < 5:
if random.random() < 0.3:
msg = "~".join(msg)
await nickname.send(
random.choice(
[
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}")
else:
await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True)
logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败")
)
logger.info(f"设置群昵称成功: {msg}", "昵称设置", event.user_id, event.group_id)
else:
if await FriendUser.set_friend_nickname(event.user_id, msg):
await nickname.send(
random.choice(
[
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
)
await FriendUser.set_user_nickname(event.user_id, msg)
await nickname.send(
random.choice(
[
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
f"好突然,突然要叫你昵称什么的...{msg}..",
f"{NICKNAME}会好好记住{msg}的,放心吧",
f"好..好.,那窝以后就叫你{msg}了.",
]
)
logger.info(f"USER {event.user_id} 设置昵称 {msg}")
else:
await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True)
logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败")
)
logger.info(f"设置私聊昵称成功: {msg}", "昵称设置", event.user_id)
@my_nickname.handle()
async def _(event: GroupMessageEvent):
try:
nickname_ = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
except AttributeError:
nickname_ = ""
async def _(event: MessageEvent):
nickname_ = None
card = None
if isinstance(event, GroupMessageEvent):
nickname_ = await GroupInfoUser.get_user_nickname(event.user_id, event.group_id)
card = event.sender.card or event.sender.nickname
else:
nickname_ = await FriendUser.get_user_nickname(event.user_id)
card = event.sender.nickname
if nickname_:
await my_nickname.send(
random.choice(
@ -130,44 +171,20 @@ async def _(event: GroupMessageEvent):
)
)
else:
nickname_ = event.sender.card or event.sender.nickname
await my_nickname.send(
random.choice(
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "{}啊,有什么事吗?", "你是{}"]
).format(nickname_)
)
@my_nickname.handle()
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
if nickname_:
await my_nickname.send(
random.choice(
[
f"我肯定记得你啊,你是{nickname_}",
f"我不会忘记你的,你也不要忘记我!{nickname_}",
f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
f"嗯?你是失忆了嘛...{nickname_}..",
f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}QAQ",
f"哎?{nickname_}..怎么了吗..突然这样问..",
]
)
)
else:
nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"]
await my_nickname.send(
random.choice(
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "{}啊,有什么事吗?", "你是{}"]
).format(nickname_)
).format(card)
)
@cancel_nickname.handle()
async def _(event: GroupMessageEvent):
nickname_ = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
async def _(event: MessageEvent):
nickname_ = None
if isinstance(event, GroupMessageEvent):
nickname_ = await GroupInfoUser.get_user_nickname(event.user_id, event.group_id)
else:
nickname_ = await FriendUser.get_user_nickname(event.user_id)
if nickname_:
await cancel_nickname.send(
random.choice(
@ -180,28 +197,10 @@ async def _(event: GroupMessageEvent):
]
)
)
await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "")
await BanUser.ban(event.user_id, 9, 60)
else:
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
@cancel_nickname.handle()
async def _(event: PrivateMessageEvent):
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
if nickname_:
await cancel_nickname.send(
random.choice(
[
f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
f"窝知道了..{nickname_}..",
f"{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
f"可..可恶!{nickname_}!太可恶了!呜",
]
)
)
await FriendUser.get_user_name(event.user_id)
if isinstance(event, GroupMessageEvent):
await GroupInfoUser.set_user_nickname(event.user_id, event.group_id, "")
else:
await FriendUser.set_user_nickname(event.user_id, "")
await BanUser.ban(event.user_id, 9, 60)
else:
await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)

View File

@ -1,13 +1,17 @@
from nonebot import on_command, on_regex
from .data_source import show_plugin_repo, install_plugin, uninstall_plugin, download_json
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import CommandArg
from utils.message_builder import image
from nonebot.permission import SUPERUSER
from services.log import logger
from utils.message_builder import image
from .data_source import (
download_json,
install_plugin,
show_plugin_repo,
uninstall_plugin,
)
__zx_plugin_name__ = "插件商店 [Superuser]"
__plugin_usage__ = """
@ -28,23 +32,29 @@ show_repo = on_regex("^查看插件仓库$", priority=1, block=True, permission=
update_repo = on_regex("^更新插件仓库$", priority=1, block=True, permission=SUPERUSER)
install_plugin_matcher = on_command("安装插件", priority=1, block=True, permission=SUPERUSER)
install_plugin_matcher = on_command(
"安装插件", priority=1, block=True, permission=SUPERUSER
)
uninstall_plugin_matcher = on_command("卸载插件", priority=1, block=True, permission=SUPERUSER)
uninstall_plugin_matcher = on_command(
"卸载插件", priority=1, block=True, permission=SUPERUSER
)
@install_plugin_matcher.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
arg = arg.extract_plain_text().strip()
msg = await install_plugin(arg)
name = arg.extract_plain_text().strip()
msg = await install_plugin(name)
await install_plugin_matcher.send(msg)
logger.info(f"安装插件: {name}", "安装插件", event.user_id)
@uninstall_plugin_matcher.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
arg = arg.extract_plain_text().strip()
msg = await uninstall_plugin(arg)
name = arg.extract_plain_text().strip()
msg = await uninstall_plugin(name)
await install_plugin_matcher.send(msg)
logger.info(f"卸载插件: {name}", "卸载插件", event.user_id)
@update_repo.handle()
@ -53,16 +63,13 @@ async def _(bot: Bot, event: MessageEvent):
if code == 200:
await update_repo.finish("更新插件仓库信息成功!")
await update_repo.send("更新插件仓库信息失败!")
logger.info("更新插件仓库信息", "更新插件仓库信息", event.user_id)
@show_repo.handle()
async def _(bot: Bot, event: MessageEvent):
msg = await show_plugin_repo()
if isinstance(msg, int):
await show_repo.finish("文件下载失败或解压失败..")
await show_repo.send(image(b64=msg))
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看插件仓库"
)
await show_repo.send(image(msg))
logger.info("查看插件仓库", "查看插件仓库", event.user_id)

View File

@ -2,15 +2,15 @@ import os
import shutil
import zipfile
from pathlib import Path
from typing import Union, Tuple
from utils.manager import plugins_manager
from typing import Tuple, Union
import ujson as json
from configs.path_config import DATA_PATH, TEMP_PATH
from services import logger
from utils.http_utils import AsyncHttpx
from configs.path_config import TEMP_PATH, DATA_PATH
from utils.image_utils import text2image, BuildImage
from utils.image_utils import BuildImage, text2image
from utils.manager import plugins_manager
from utils.utils import is_number
path = DATA_PATH / "plugin_shop"
@ -48,7 +48,7 @@ async def install_plugin(name: str) -> str:
if zip_file.exists():
zip_file.unlink()
if await AsyncHttpx.download_file(url, zip_file):
logger.debug("开始解压插件压缩包...")
logger.debug("开始解压插件压缩包...", "安装插件", target=name)
# 解压
zf = zipfile.ZipFile(zip_file, "r")
extract_path = TEMP_PATH / f"{name}"
@ -58,32 +58,34 @@ async def install_plugin(name: str) -> str:
for file in zf.namelist():
zf.extract(file, extract_path)
zf.close()
logger.debug("解压插件压缩包完成...")
logger.debug("开始移动插件文件夹...")
logger.debug("解压插件压缩包完成...", "安装插件", target=name)
logger.debug("开始移动插件文件夹...", "安装插件", target=name)
if (extensive_plugin_path / f"{name}").exists():
logger.debug("extensive_plugin目录下文件夹已存在删除该目录插件文件夹...")
logger.debug(
"extensive_plugin目录下文件夹已存在删除该目录插件文件夹...", "安装插件", target=name
)
shutil.rmtree(
(extensive_plugin_path / f"{name}").absolute(), ignore_errors=True
)
extract_path.rename(extensive_plugin_path / f"{name}")
tmp = ""
prompt = ""
if "pyproject.toml" in os.listdir(extensive_plugin_path / f"{name}"):
tmp = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
prompt = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
os.system(
f"poetry run pip install -r {(extensive_plugin_path / f'{name}' / 'pyproject.toml').absolute()}"
)
elif "requirements.txt" in os.listdir(extensive_plugin_path / f"{name}"):
tmp = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
prompt = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
os.system(
f"poetry run pip install -r {(extensive_plugin_path / f'{name}' / 'requirements.txt').absolute()}"
)
with open(extensive_plugin_path / f"{name}" / "plugin_info.json", "w") as f:
json.dump(data[name], f, ensure_ascii=False, indent=4)
logger.debug("移动插件文件夹完成...")
logger.info(f"成功安装插件 {name} 成功!\n{tmp}")
logger.debug("移动插件文件夹完成...", "安装插件", target=name)
logger.info(f"成功安装插件 {name} 成功!\n{prompt}", "安装插件", target=name)
return f"成功安装插件 {name},请重启真寻!"
except Exception as e:
logger.error(f"安装插{name} 失败 {type(e)}{e}")
logger.error(f"安装插失败", "安装插件", target=name, e=e)
return f"安装插件 {name} 失败 {type(e)}{e}"
@ -138,7 +140,7 @@ async def show_plugin_repo() -> Union[int, str]:
version = f"<f font_color=#1a7e30>[{plugins_data[key].version}]</f>"
s = (
f'id{i+1}\n名称:{plugin_info[key]["plugin_name"]}'
f' \t\t{status}\n'
f" \t\t{status}\n"
f"模块:{key}\n"
f'作者:{plugin_info[key]["author"]}\n'
f'版本:{plugin_info[key]["version"]} \t\t{version}\n'

View File

@ -1,23 +1,16 @@
import random
from asyncpg.exceptions import (
DuplicateColumnError,
UndefinedColumnError,
PostgresSyntaxError,
)
from nonebot import Driver
from services.db_context import db
from models.group_info import GroupInfo
from models.bag_user import BagUser
from nonebot.adapters.onebot.v11 import Bot
from services.log import logger
from configs.path_config import TEXT_PATH
from asyncio.exceptions import TimeoutError
from typing import List
from utils.http_utils import AsyncHttpx
from utils.utils import GDict
from utils.utils import scheduler
import nonebot
from nonebot.adapters.onebot.v11 import Bot
from nonebot.drivers import Driver
from configs.path_config import TEXT_PATH
from models.bag_user import BagUser
from models.group_info import GroupInfo
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.utils import GDict, scheduler
try:
import ujson as json
@ -38,6 +31,7 @@ async def update_city():
data = {}
if not china_city.exists():
try:
logger.debug("开始更新城市列表...")
res = await AsyncHttpx.get(
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
)
@ -56,103 +50,97 @@ async def update_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 TimeoutError as e:
logger.warning("自动更新城市列表超时...", e=e)
except ValueError as e:
logger.warning("自动城市列表失败.....", e=e)
except Exception as e:
logger.error(f"自动城市列表未知错误 {type(e)}{e}")
logger.error(f"自动城市列表未知错误", e=e)
@driver.on_startup
async def _():
"""
数据库表结构变换
"""
_flag = []
sql_str = [
(
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;",
"group_info",
), # group_info表添加一个group_flag
(
"ALTER TABLE bag_users rename belonging_group To group_id;",
"bag_users",
), # 将 bag_users 的 belonging_group 改为 group_id
(
"ALTER TABLE group_info_users rename belonging_group To group_id;",
"group_info_users",
),
(
"ALTER TABLE sign_group_users rename belonging_group To group_id;",
"sign_group_users",
),
(
"ALTER TABLE open_cases_users rename belonging_group To group_id;",
"open_cases_users",
),
(
"ALTER TABLE bag_users ADD property json NOT NULL DEFAULT '{}';",
"bag_users",
), # bag_users 新增字段 property 替代 props
(
"ALTER TABLE genshin ADD auto_sign_time timestamp with time zone;",
"genshin"
), # 新增原神自动签到字段
(
"ALTER TABLE genshin ADD resin_remind boolean DEFAULT False;",
"genshin"
), # 新增原神自动签到字段
(
"ALTER TABLE genshin ADD resin_recovery_time timestamp with time zone;",
"genshin"
), # 新增原神自动签到字段
(
"ALTER TABLE genshin ADD bind_group Integer;",
"genshin"
), # 新增原神群号绑定字段
(
"ALTER TABLE genshin ADD login_ticket VARCHAR(255) DEFAULT '';",
"genshin"
), # 新增米游社login_ticket绑定字段
(
"ALTER TABLE genshin ADD stuid VARCHAR(255) DEFAULT '';",
"genshin"
), # 新增米游社stuid绑定字段
(
"ALTER TABLE genshin ADD stoken VARCHAR(255) DEFAULT '';",
"genshin"
), # 新增米游社stoken绑定字段
(
"ALTER TABLE chat_history ADD plain_text Text;",
"chat_history"
), # 新增纯文本
(
"ALTER TABLE goods_info ADD daily_limit Integer DEFAULT 0;",
"goods_info"
), # 新增纯文本
(
"ALTER TABLE goods_info ADD daily_purchase_limit Json DEFAULT '{}';",
"goods_info"
), # 新增纯文本
]
for sql in sql_str + GDict.get('run_sql', []):
try:
if isinstance(sql, str):
flag = f'{random.randint(1, 10000)}'
else:
flag = sql[1]
sql = sql[0]
query = db.text(sql)
await db.first(query)
logger.info(f"完成sql操作{sql}")
_flag.append(flag)
except (DuplicateColumnError, UndefinedColumnError):
pass
except PostgresSyntaxError:
logger.error(f"语法错误执行sql失败{sql}")
# bag_user 将文本转为字典格式
await __database_script(_flag)
# @driver.on_startup
# async def _():
# """
# 数据库表结构变换
# """
# _flag = []
# sql_str = [
# (
# "ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;",
# "group_info",
# ), # group_info表添加一个group_flag
# (
# "ALTER TABLE bag_users rename belonging_group To group_id;",
# "bag_users",
# ), # 将 bag_users 的 belonging_group 改为 group_id
# (
# "ALTER TABLE group_info_users rename belonging_group To group_id;",
# "group_info_users",
# ),
# (
# "ALTER TABLE sign_group_users rename belonging_group To group_id;",
# "sign_group_users",
# ),
# (
# "ALTER TABLE open_cases_users rename belonging_group To group_id;",
# "open_cases_users",
# ),
# (
# "ALTER TABLE bag_users ADD property json NOT NULL DEFAULT '{}';",
# "bag_users",
# ), # bag_users 新增字段 property 替代 props
# (
# "ALTER TABLE genshin ADD auto_sign_time timestamp with time zone;",
# "genshin",
# ), # 新增原神自动签到字段
# (
# "ALTER TABLE genshin ADD resin_remind boolean DEFAULT False;",
# "genshin",
# ), # 新增原神自动签到字段
# (
# "ALTER TABLE genshin ADD resin_recovery_time timestamp with time zone;",
# "genshin",
# ), # 新增原神自动签到字段
# ("ALTER TABLE genshin ADD bind_group Integer;", "genshin"), # 新增原神群号绑定字段
# (
# "ALTER TABLE genshin ADD login_ticket VARCHAR(255) DEFAULT '';",
# "genshin",
# ), # 新增米游社login_ticket绑定字段
# (
# "ALTER TABLE genshin ADD stuid VARCHAR(255) DEFAULT '';",
# "genshin",
# ), # 新增米游社stuid绑定字段
# (
# "ALTER TABLE genshin ADD stoken VARCHAR(255) DEFAULT '';",
# "genshin",
# ), # 新增米游社stoken绑定字段
# ("ALTER TABLE chat_history ADD plain_text Text;", "chat_history"), # 新增纯文本
# (
# "ALTER TABLE goods_info ADD daily_limit Integer DEFAULT 0;",
# "goods_info",
# ), # 新增纯文本
# (
# "ALTER TABLE goods_info ADD daily_purchase_limit Json DEFAULT '{}';",
# "goods_info",
# ), # 新增纯文本
# ]
# for sql in sql_str + GDict.get("run_sql", []):
# try:
# if isinstance(sql, str):
# flag = f"{random.randint(1, 10000)}"
# else:
# flag = sql[1]
# sql = sql[0]
# query = db.text(sql)
# await db.first(query)
# logger.info(f"完成sql操作{sql}")
# _flag.append(flag)
# except (DuplicateColumnError, UndefinedColumnError):
# pass
# except PostgresSyntaxError:
# logger.error(f"语法错误执行sql失败{sql}")
# bag_user 将文本转为字典格式
# await __database_script(_flag)
@driver.on_bot_connect
@ -161,51 +149,57 @@ async def _(bot: Bot):
版本某些需要的变换
"""
# 清空不存在的群聊信息并将已所有已存在的群聊group_flag设置为1认证所有已存在的群
if not await GroupInfo.get_group_info(114514):
if not await GroupInfo.get_or_none(group_id=114514):
# 标识符,该功能只需执行一次
await GroupInfo.add_group_info(114514, "114514", 114514, 114514, 1)
await GroupInfo.create(
group_id=114514,
group_name="114514",
max_member_count=114514,
member_count=114514,
group_flag=1,
)
group_list = await bot.get_group_list()
group_list = [g["group_id"] for g in group_list]
_gl = [x.group_id for x in await GroupInfo.get_all_group()]
_gl = [x.group_id for x in await GroupInfo.all()]
if 114514 in _gl:
_gl.remove(114514)
for group_id in _gl:
if group_id in group_list:
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 1)
if group := await GroupInfo.get_or_none(group_id=group_id):
await group.update_or_create(group_flag=1)
else:
group_info = await bot.get_group_info(group_id=group_id)
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
await GroupInfo.create(
group_id=group_info["group_id"],
group_name=group_info["group_name"],
max_member_count=group_info["max_member_count"],
member_count=group_info["member_count"],
group_flag=1,
)
logger.info(f"将群聊 {group_id} 添加认证...")
logger.info(f"添加群认证...", group_id=group_id)
else:
await GroupInfo.delete_group_info(group_id)
logger.info(f"移除不存在的群聊信息{group_id}")
await GroupInfo.filter(group_id=group_id).delete()
logger.info(f"移除不存在的群聊信息", group_id=group_id)
async def __database_script(_flag: List[str]):
# bag_user 将文本转为字典格式
if "bag_users" in _flag:
for x in await BagUser.get_all_users():
props = {}
if x.props:
for prop in [p for p in x.props.split(",") if p]:
if props.get(prop):
props[prop] += 1
else:
props[prop] = 1
logger.info(
f"__database_script USER {x.user_qq} GROUP {x.group_id} 更新数据 {props}"
)
await x.update(
property=props,
props="",
).apply()
# async def __database_script(_flag: List[str]):
# # bag_user 将文本转为字典格式
# if "bag_users" in _flag:
# for x in await BagUser.get_all_users():
# props = {}
# if x.props:
# for prop in [p for p in x.props.split(",") if p]:
# if props.get(prop):
# props[prop] += 1
# else:
# props[prop] = 1
# logger.info(
# f"__database_script USER {x.user_qq} GROUP {x.group_id} 更新数据 {props}"
# )
# await x.update(
# property=props,
# props="",
# ).apply()
# 自动更新城市列表

View File

@ -1,21 +1,40 @@
from configs.config import Config
from nonebot import Driver
from utils.decorator.shop import shop_register
from pathlib import Path
import nonebot
from nonebot.drivers import Driver
from configs.config import Config
from utils.decorator.shop import shop_register
driver: Driver = nonebot.get_driver()
Config.add_plugin_config(
"shop",
"IMPORT_DEFAULT_SHOP_GOODS",
True,
help_="导入商店自带的三个商品",
default_value=True
"shop", "IMPORT_DEFAULT_SHOP_GOODS", True, help_="导入商店自带的三个商品", default_value=True
)
nonebot.load_plugins("basic_plugins/shop")
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
@shop_register(
name=("好感度双倍加持卡Ⅰ", "好感度双倍加持卡Ⅱ", "好感度双倍加持卡Ⅲ"),
price=(30, 150, 250),
des=(
"下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
"下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)",
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
),
load_status=bool(Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS")),
icon=(
"favorability_card_1.png",
"favorability_card_2.png",
"favorability_card_3.png",
),
**{"好感度双倍加持卡_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
)
async def sign_card(user_id: int, group_id: int):
pass
@driver.on_bot_connect

View File

@ -1,16 +1,15 @@
from nonebot import on_command
from models.user_shop_gold_log import UserShopGoldLog
from services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.params import CommandArg
from utils.utils import is_number
from models.bag_user import BagUser
from services.db_context import db
from nonebot.adapters.onebot.v11.permission import GROUP
from models.goods_info import GoodsInfo
import time
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.params import CommandArg
from models.bag_user import BagUser
from models.goods_info import GoodsInfo
from models.user_shop_gold_log import UserShopGoldLog
from services.log import logger
from utils.utils import is_number
__zx_plugin_name__ = "商店 - 购买道具"
__plugin_usage__ = """
@ -71,39 +70,40 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
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)
flag, n = await GoodsInfo.check_user_daily_purchase(
goods, event.user_id, event.group_id, num
)
if flag:
await buy.finish(f"该次购买将超过每日次数限制,目前该道具还可以购买{n}次哦", at_sender=True)
if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
await GoodsInfo.add_user_daily_purchase(
goods, event.user_id, event.group_id, num
)
await 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} 成功!"
)
await UserShopGoldLog.add_shop_log(
event.user_id,
event.group_id,
0,
goods.goods_name,
num,
goods.goods_price * num * goods.goods_discount,
)
else:
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} "
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 失败!"
)
if (
await BagUser.get_gold(event.user_id, event.group_id)
) < goods.goods_price * num * goods.goods_discount:
await buy.finish("您的金币好像不太够哦", at_sender=True)
flag, n = await GoodsInfo.check_user_daily_purchase(
goods, event.user_id, event.group_id, num
)
if flag:
await buy.finish(f"该次购买将超过每日次数限制,目前该道具还可以购买{n}次哦", at_sender=True)
spend_gold = int(goods.goods_discount * goods.goods_price * num)
await BagUser.spend_gold(event.user_id, event.group_id, spend_gold)
await BagUser.add_property(event.user_id, event.group_id, goods.goods_name, num)
await GoodsInfo.add_user_daily_purchase(goods, event.user_id, event.group_id, num)
await buy.send(
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
at_sender=True,
)
logger.info(
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!",
"购买道具",
event.user_id,
event.group_id,
)
await UserShopGoldLog.create(
user_qq=event.user_id,
group_id=event.group_id,
type=0,
name=goods.goods_name,
num=num,
spend_gold=goods.goods_price * num * goods.goods_discount,
)
# 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} 失败!"
# )

View File

@ -1,9 +1,10 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, ActionFailed
from nonebot.params import CommandArg
from nonebot.adapters.onebot.v11 import ActionFailed, GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.data_utils import init_rank
from nonebot.params import CommandArg
from models.bag_user import BagUser
from utils.data_utils import init_rank
from utils.image_utils import text2image
from utils.message_builder import image
from utils.utils import is_number
@ -39,7 +40,9 @@ async def _(event: GroupMessageEvent):
try:
await my_gold.send(msg)
except ActionFailed:
await my_gold.send(image(b64=(await text2image(msg, color="#f9f6f2", padding=10)).pic2bs4()))
await my_gold.send(
image(b64=(await text2image(msg, color="#f9f6f2", padding=10)).pic2bs4())
)
@gold_rank.handle()
@ -49,9 +52,11 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
num = int(num)
else:
num = 10
all_users = await BagUser.get_all_users(event.group_id)
all_users = await BagUser.filter(group_id=event.group_id)
all_user_id = [user.user_qq for user in all_users]
all_user_data = [user.gold for user in all_users]
rank_image = await init_rank("金币排行", all_user_id, all_user_data, event.group_id, num)
rank_image = await init_rank(
"金币排行", all_user_id, all_user_data, event.group_id, num
)
if rank_image:
await gold_rank.finish(image(b64=rank_image.pic2bs4()))

View File

@ -1,12 +1,12 @@
from nonebot import on_command
from utils.message_builder import image
from ._data_source import create_bag_image
from services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from models.bag_user import BagUser
from nonebot.adapters.onebot.v11.permission import GROUP
from models.bag_user import BagUser
from services.log import logger
from utils.message_builder import image
from ._data_source import create_bag_image
__zx_plugin_name__ = "商店 - 我的道具"
__plugin_usage__ = """
@ -17,7 +17,7 @@ usage
""".strip()
__plugin_des__ = "商店 - 我的道具"
__plugin_cmd__ = ["我的道具"]
__plugin_type__ = ('商店',)
__plugin_type__ = ("商店",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
@ -36,10 +36,6 @@ async def _(event: GroupMessageEvent):
props = await BagUser.get_property(event.user_id, event.group_id)
if props:
await my_props.send(image(b64=await create_bag_image(props)))
# rst = ""
# for i, p in enumerate(props.keys()):
# rst += f"{i+1}.{p}\t×{props[p]}\n"
# await my_props.send("\n" + rst[:-1], at_sender=True)
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
else:
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)

View File

@ -1,26 +0,0 @@
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}")

View File

@ -1,14 +1,24 @@
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info, GoodsInfo
from nonebot.adapters.onebot.v11 import MessageEvent, Message
from nonebot import on_command
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from nonebot.permission import SUPERUSER
from utils.utils import is_number, scheduler
from nonebot.params import CommandArg
from services.log import logger
import os
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Message, MessageEvent
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
from configs.path_config import IMAGE_PATH
from models.bag_user import BagUser
from services.log import logger
from utils.message_builder import image
from utils.utils import is_number, scheduler
from .data_source import (
GoodsInfo,
create_shop_help,
delete_goods,
parse_goods_info,
register_goods,
update_goods,
)
__zx_plugin_name__ = "商店"
__plugin_usage__ = """
@ -37,7 +47,7 @@ __plugin_cmd__ = [
"删除商品 [名称或序号] [_superuser]",
"修改商品 name:[名称或序号] price:[价格] des:[描述] discount:[折扣] limit_time:[限时] [_superuser]",
]
__plugin_type__ = ('商店',)
__plugin_type__ = ("商店",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
@ -46,9 +56,7 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["商店"],
}
__plugin_block_limit__ = {
"limit_type": "group"
}
__plugin_block_limit__ = {"limit_type": "group"}
shop_help = on_command("商店", priority=5, block=True)
@ -75,12 +83,15 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
if not data.get("name") or not data.get("price") or not data.get("des"):
await shop_add_goods.finish("name:price:des 参数不可缺少!")
if await register_goods(**data):
await shop_add_goods.send(f"添加商品 {data['name']} 成功!\n"
f"名称:{data['name']}\n"
f"价格:{data['price']}金币\n"
f"简介:{data['des']}\n"
f"折扣:{data.get('discount')}\n"
f"限时:{data.get('limit_time')}", at_sender=True)
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)
@ -133,7 +144,19 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
)
async def _():
try:
await GoodsInfo.reset_daily_purchase()
await GoodsInfo.all().update(daily_purchase_limit={})
logger.info("商品每日限购次数重置成功...")
except Exception as e:
logger.error(f"商品每日限购次数重置发生错误 {type(e)}{e}")
logger.error(f"商品每日限购次数重置出错 {type(e)}{e}")
@scheduler.scheduled_job(
"cron",
hour=0,
minute=1,
)
async def _():
try:
await BagUser.all().update(get_today_gold=0, spend_today_gold=0)
except Exception as e:
logger.error(f"重置每日金币", "定时任务", e=e)

View File

@ -1,18 +1,18 @@
import time
from typing import Optional, Tuple, Union
from PIL import Image
from configs.path_config import IMAGE_PATH
from models.goods_info import GoodsInfo
from utils.image_utils import BuildImage, text2image
from utils.utils import is_number
from configs.path_config import IMAGE_PATH
from typing import Optional, Union, Tuple
from utils.utils import GDict
import time
from utils.utils import GDict, is_number
icon_path = IMAGE_PATH / 'shop_icon'
icon_path = IMAGE_PATH / "shop_icon"
GDict['run_sql'].append("ALTER TABLE goods_info ADD is_passive boolean DEFAULT False;")
GDict['run_sql'].append("ALTER TABLE goods_info ADD icon VARCHAR(255);")
GDict["run_sql"].append("ALTER TABLE goods_info ADD is_passive boolean DEFAULT False;")
GDict["run_sql"].append("ALTER TABLE goods_info ADD icon VARCHAR(255);")
# 创建商店界面
@ -43,17 +43,31 @@ async def create_shop_help() -> str:
await name_image.atext((390, 0), "售价:", center_type="by_height")
if goods.goods_discount != 1:
discount_price = int(goods.goods_discount * goods.goods_price)
old_price_image = BuildImage(0, 0, plain_text=str(goods.goods_price), font_color=(194, 194, 194), font="CJGaoDeGuo.otf", font_size=15)
await old_price_image.aline((0, int(old_price_image.h / 2), old_price_image.w + 1, int(old_price_image.h / 2)), (0, 0, 0))
await name_image.apaste(
old_price_image, (440, 0), True
old_price_image = BuildImage(
0,
0,
plain_text=str(goods.goods_price),
font_color=(194, 194, 194),
font="CJGaoDeGuo.otf",
font_size=15,
)
await name_image.atext(
(440, 15), str(discount_price), (255, 255, 255)
await old_price_image.aline(
(
0,
int(old_price_image.h / 2),
old_price_image.w + 1,
int(old_price_image.h / 2),
),
(0, 0, 0),
)
await name_image.apaste(old_price_image, (440, 0), True)
await name_image.atext((440, 15), str(discount_price), (255, 255, 255))
else:
await name_image.atext(
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
(440, 0),
str(goods.goods_price),
(255, 255, 255),
center_type="by_height",
)
await name_image.atext(
(
@ -68,38 +82,48 @@ async def create_shop_help() -> str:
font_img = BuildImage(
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
)
p = font_img.getsize('简介:')[0] + 20
p = font_img.getsize("简介:")[0] + 20
if goods.goods_description:
des_list = goods.goods_description.split('\n')
desc = ''
des_list = goods.goods_description.split("\n")
desc = ""
for des in des_list:
if font_img.getsize(des)[0] > font_img.w - p - 20:
msg = ''
tmp = ''
msg = ""
tmp = ""
for i in range(len(des)):
if font_img.getsize(tmp)[0] < font_img.w - p - 20:
tmp += des[i]
else:
msg += tmp + '\n'
msg += tmp + "\n"
tmp = des[i]
desc += msg
if tmp:
desc += tmp
else:
desc += des + '\n'
if desc[-1] == '\n':
desc += des + "\n"
if desc[-1] == "\n":
desc = desc[:-1]
des_image = await text2image(desc, color="#a29ad6")
goods_image = BuildImage(
600, (50 + des_image.h) if des_image else 50, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
600,
(50 + des_image.h) if des_image else 50,
font_size=20,
color="#a29ad6",
font="CJGaoDeGuo.otf",
)
if des_image:
await goods_image.atext((15, 50), '简介:')
await goods_image.atext((15, 50), "简介:")
await goods_image.apaste(des_image, (p, 50))
await name_image.acircle_corner(5)
await goods_image.apaste(name_image, (0, 5), True, center_type="by_width")
await goods_image.acircle_corner(20)
bk = BuildImage(1180, (50 + des_image.h) if des_image else 50, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
bk = BuildImage(
1180,
(50 + des_image.h) if des_image else 50,
font_size=15,
color="#f9f6f2",
font="CJGaoDeGuo.otf",
)
if goods.icon and (icon_path / goods.icon).exists():
icon = BuildImage(70, 70, background=icon_path / goods.icon)
await bk.apaste(icon)
@ -129,7 +153,9 @@ async def create_shop_help() -> str:
_w += 140
if goods.goods_discount != 1:
n += 140
_discount_logo = BuildImage(30, 30, background=f"{IMAGE_PATH}/other/discount.png")
_discount_logo = BuildImage(
30, 30, background=f"{IMAGE_PATH}/other/discount.png"
)
await bk.apaste(_discount_logo, (_w + 50, 10), True)
await bk.apaste(
BuildImage(0, 0, plain_text="折扣!", font_size=23, font="CJGaoDeGuo.otf"),
@ -137,14 +163,23 @@ async def create_shop_help() -> str:
True,
)
await bk.apaste(
BuildImage(0, 0, plain_text=f"{10 * goods.goods_discount:.1f}", font_size=30, font="CJGaoDeGuo.otf", font_color=(85, 156, 75)),
BuildImage(
0,
0,
plain_text=f"{10 * goods.goods_discount:.1f}",
font_size=30,
font="CJGaoDeGuo.otf",
font_color=(85, 156, 75),
),
(_w + 50, 44),
True,
)
_w += 140
if goods.daily_limit != 0:
n += 140
_daily_limit_logo = BuildImage(35, 35, background=f"{IMAGE_PATH}/other/daily_limit.png")
_daily_limit_logo = BuildImage(
35, 35, background=f"{IMAGE_PATH}/other/daily_limit.png"
)
await bk.apaste(_daily_limit_logo, (_w + 50, 10), True)
await bk.apaste(
BuildImage(0, 0, plain_text="限购!", font_size=23, font="CJGaoDeGuo.otf"),
@ -152,7 +187,13 @@ async def create_shop_help() -> str:
True,
)
await bk.apaste(
BuildImage(0, 0, plain_text=f"{goods.daily_limit}", font_size=30, font="CJGaoDeGuo.otf"),
BuildImage(
0,
0,
plain_text=f"{goods.daily_limit}",
font_size=30,
font="CJGaoDeGuo.otf",
),
(_w + 72, 45),
True,
)
@ -220,22 +261,30 @@ async def register_goods(
:param icon: 图标
:return: 是否添加成功
"""
if not await GoodsInfo.get_goods_info(name):
limit_time = float(limit_time) if limit_time else limit_time
if not await GoodsInfo.get_or_none(goods_name=name):
limit_time_ = float(limit_time) if limit_time else limit_time
discount = discount if discount is not None else 1
limit_time = (
int(time.time() + limit_time * 60 * 60)
if limit_time is not None and limit_time != 0
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, daily_limit, is_passive, icon
await GoodsInfo.create(
goods_name=name,
goods_price=int(price),
goods_description=des,
goods_discount=float(discount),
goods_limit_time=limit_time_,
daily_limit=daily_limit,
is_passive=is_passive,
icon=icon,
)
return True
return False
# 删除商品
async def delete_goods(name: str, id_: int) -> "str, str, int":
async def delete_goods(name: str, id_: int) -> Tuple[str, str, int]:
"""
删除商品
:param name: 商品名称
@ -256,6 +305,7 @@ async def delete_goods(name: str, id_: int) -> "str, str, int":
return f"删除商品 {name} 成功!", name, 200
else:
return f"删除商品 {name} 失败!", name, 999
return "获取商品失败", "", 999
# 更新商品信息
@ -272,7 +322,7 @@ async def update_goods(**kwargs) -> Tuple[bool, str, str]:
return False, "序号错误,没有该序号的商品...", ""
goods = goods_lst[int(kwargs["name"]) - 1]
else:
goods = await GoodsInfo.get_goods_info(kwargs["name"])
goods = await GoodsInfo.filter(goods_name=kwargs["name"]).first()
if not goods:
return False, "名称错误,没有该名称的商品...", ""
name: str = goods.goods_name
@ -295,14 +345,22 @@ async def update_goods(**kwargs) -> Tuple[bool, str, str]:
discount = kwargs["discount"]
if kwargs.get("limit_time"):
kwargs["limit_time"] = float(kwargs["limit_time"])
new_time = time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime(time.time() + kwargs["limit_time"] * 60 * 60),
) if kwargs["limit_time"] != 0 else 0
new_time = (
time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime(time.time() + kwargs["limit_time"] * 60 * 60),
)
if kwargs["limit_time"] != 0
else 0
)
tmp += f"限时至: {new_time}\n" if new_time else "取消了限时\n"
limit_time = kwargs["limit_time"]
if kwargs.get("daily_limit"):
tmp += f'每日购买限制:{daily_limit} --> {kwargs["daily_limit"]}\n' if daily_limit else "取消了购买限制\n"
tmp += (
f'每日购买限制:{daily_limit} --> {kwargs["daily_limit"]}\n'
if daily_limit
else "取消了购买限制\n"
)
daily_limit = int(kwargs["daily_limit"])
if kwargs.get("is_passive"):
tmp += f'被动道具:{is_passive} --> {kwargs["is_passive"]}\n'
@ -318,9 +376,13 @@ async def update_goods(**kwargs) -> Tuple[bool, str, str]:
else 0
),
daily_limit,
is_passive
is_passive,
)
return (
True,
name,
tmp[:-1],
)
return True, name, tmp[:-1],
def parse_goods_info(msg: str) -> Union[dict, str]:

View File

@ -1,19 +1,17 @@
from typing import Any, Tuple
from nonebot import on_command, on_regex
from models.user_shop_gold_log import UserShopGoldLog
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.params import CommandArg, RegexGroup
from models.bag_user import BagUser
from models.user_shop_gold_log import UserShopGoldLog
from services.log import logger
from utils.decorator.shop import NotMeetUseConditionsException
from utils.utils import is_number
from models.bag_user import BagUser
from nonebot.adapters.onebot.v11.permission import GROUP
from services.db_context import db
from .data_source import effect, register_use, func_manager, build_params
from .data_source import build_params, effect, func_manager, register_use
__zx_plugin_name__ = "商店 - 使用道具"
__plugin_usage__ = """
@ -75,17 +73,25 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
if prop_n not in property_.keys():
await use_props.finish("道具名称错误!", at_sender=True)
name = prop_n
if not name:
await use_props.finish("未获取到道具名称", at_sender=True)
_user_prop_count = property_[name]
if num > _user_prop_count:
await use_props.finish(f"道具数量不足,无法使用{num}次!")
if num > (n := func_manager.get_max_num_limit(name)):
await use_props.finish(f"该道具单次只能使用 {n} 个!")
model, kwargs = build_params(bot, event, name, num, text)
try:
await func_manager.run_handle(type_="before_handle", param=model, **kwargs)
except NotMeetUseConditionsException as e:
await use_props.finish(e.get_info(), at_sender=True)
async with db.transaction():
model, kwargs = build_params(bot, event, name, num, text)
except KeyError:
logger.warning(f"{name} 未注册使用函数")
await use_props.finish(f"{name} 未注册使用方法")
else:
try:
await func_manager.run_handle(
type_="before_handle", param=model, **kwargs
)
except NotMeetUseConditionsException as e:
await use_props.finish(e.get_info(), at_sender=True)
if await BagUser.delete_property(event.user_id, event.group_id, name, num):
if func_manager.check_send_success_message(name):
await use_props.send(f"使用道具 {name} {num} 次成功!", at_sender=True)
@ -94,14 +100,18 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次成功"
)
await UserShopGoldLog.add_shop_log(
event.user_id, event.group_id, 1, name, num
await UserShopGoldLog.create(
user_qq=event.user_id,
group_id=event.group_id,
type=1,
name=name,
num=num,
)
else:
await use_props.send(f"使用道具 {name} {num} 次失败!", at_sender=True)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次失败"
)
await func_manager.run_handle(type_="after_handle", param=model, **kwargs)
await func_manager.run_handle(type_="after_handle", param=model, **kwargs)
else:
await use_props.send("您的背包里没有任何的道具噢", at_sender=True)

View File

@ -108,7 +108,7 @@ class GoodsUseFuncManager:
)
async def run_handle(self, goods_name: str, type_: str, param: ShopParam, **kwargs):
if self._data[goods_name].get(type_):
if self._data.get(goods_name) and self._data[goods_name].get(type_):
for func in self._data[goods_name].get(type_):
args = inspect.signature(func).parameters
if args and list(args.keys())[0] != "kwargs":
@ -170,7 +170,6 @@ def build_params(
:param goods_name: 商品名称
:param num: 数量
:param text: 其他信息
:return:
"""
_kwargs = func_manager.get_kwargs(goods_name)
return (

View File

@ -1,11 +1,5 @@
import nonebot
from pathlib import Path
import nonebot
nonebot.load_plugins(str(Path(__file__).parent.resolve()))

View File

@ -1,14 +1,17 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.adapters.onebot.v11 import Bot, Message
from nonebot.params import Command, CommandArg
from typing import Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.utils import is_number
from models.group_info import GroupInfo
from services.log import logger
from utils.depends import OneCommand
from utils.manager import requests_manager
from utils.message_builder import image
from models.group_info import GroupInfo
from utils.utils import is_number
__zx_plugin_name__ = "显示所有好友群组 [Superuser]"
__plugin_usage__ = """
@ -76,8 +79,7 @@ async def _(bot: Bot):
@friend_handle.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(bot: Bot, cmd: str = OneCommand(), arg: Message = CommandArg()):
id_ = arg.extract_plain_text().strip()
if is_number(id_):
id_ = int(id_)
@ -97,8 +99,9 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
@group_handle.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(
bot: Bot, event: MessageEvent, cmd: str = OneCommand(), arg: Message = CommandArg()
):
id_ = arg.extract_plain_text().strip()
flag = None
if is_number(id_):
@ -106,20 +109,21 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
if cmd[:2] == "同意":
rid = requests_manager.get_group_id(id_)
if rid:
if await GroupInfo.get_group_info(rid):
await GroupInfo.set_group_flag(rid, 1)
if group := await GroupInfo.filter(group_id=rid).first():
await group.update_or_create(group_flag=1)
else:
group_info = await bot.get_group_info(group_id=rid)
await GroupInfo.add_group_info(
rid,
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
await GroupInfo.create(
group_id=rid,
group_name=group_info["group_name"],
max_member_count=group_info["max_member_count"],
member_count=group_info["member_count"],
group_flag=1,
)
flag = await requests_manager.approve(bot, id_, "group")
else:
await group_handle.send("同意群聊请求失败未找到此id的请求..")
logger.info("同意群聊请求失败未找到此id的请求..", cmd, event.user_id)
else:
flag = await requests_manager.refused(bot, id_, "group")
if flag == 1:
@ -139,15 +143,15 @@ async def _():
for type_ in ["private", "group"]:
msg = await requests_manager.show(type_)
if msg:
_str += image(b64=msg)
_str += image(msg)
else:
_str += "没有任何好友请求.." if type_ == "private" else "没有任何群聊请求.."
if type_ == "private":
_str += '\n--------------------\n'
_str += "\n--------------------\n"
await cls_request.send(Message(_str))
@clear_request.handle()
async def _():
requests_manager.clear()
await clear_request.send("已清空所有好友/群聊请求..")
await clear_request.send("已清空所有好友/群聊请求..")

View File

@ -1,13 +1,15 @@
import asyncio
import os
import time
from nonebot import on_command
from nonebot.permission import SUPERUSER
from configs.path_config import TEMP_PATH
from nonebot.rule import to_me
from utils.utils import scheduler
from configs.path_config import TEMP_PATH
from services.log import logger
from utils.manager import resources_manager
import asyncio
import time
import os
from utils.utils import scheduler
__zx_plugin_name__ = "清理临时数据 [Superuser]"
__plugin_usage__ = """
@ -37,22 +39,29 @@ async def _():
await clear_data.send("开始清理临时数据....")
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
logger.info("清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
def _clear_data() -> float:
logger.debug("开始清理临时文件...")
size = 0
for dir_ in resources_manager.get_temp_data_dir():
if dir_.exists():
for file in os.listdir(dir_):
file = dir_ / file
if file.is_file():
try:
if time.time() - os.path.getatime(file) > 300:
file_size = os.path.getsize(file)
file.unlink()
size += file_size
except Exception as e:
logger.error(f"清理临时数据错误...{type(e)}{e}")
dir_list = [dir_ for dir_ in resources_manager.get_temp_data_dir() if dir_.exists()]
for dir_ in dir_list:
logger.debug(f"尝试清理文件夹: {dir_.absolute()}", "清理临时数据")
dir_size = 0
for file in os.listdir(dir_):
file = dir_ / file
if file.is_file():
try:
if time.time() - os.path.getatime(file) > 10:
file_size = os.path.getsize(file)
file.unlink()
size += file_size
dir_size += file_size
logger.debug(f"移除临时文件: {file.absolute()}", "清理临时数据")
except Exception as e:
logger.error(f"清理临时数据错误,临时文件夹: {dir_.absolute()}...", "清理临时数据", e=e)
logger.debug("清理临时文件夹大小: {:.2f}MB".format(size / 1024 / 1024), "清理临时数据")
return float(size)

View File

@ -1,13 +1,15 @@
from nonebot.adapters.onebot.v11 import Message, Bot, MessageEvent
import asyncio
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.message_builder import custom_forward_msg
from services.db_context import db
from nonebot.params import CommandArg
from services.log import logger
from tortoise import Tortoise
import asyncio
from services.db_context import TestSQL
from services.log import logger
from utils.message_builder import custom_forward_msg
__zx_plugin_name__ = "执行sql [Superuser]"
__plugin_usage__ = """
@ -18,9 +20,7 @@ usage
查看所有表
""".strip()
__plugin_des__ = "执行一段sql语句"
__plugin_cmd__ = [
"exec [sql语句]",
]
__plugin_cmd__ = ["exec [sql语句]", "查看所有表"]
__plugin_version__ = 0.2
__plugin_author__ = "HibiKier"
@ -32,55 +32,61 @@ tables = on_command("查看所有表", rule=to_me(), permission=SUPERUSER, prior
@exec_.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
sql = arg.extract_plain_text().strip()
async with db.transaction():
if not sql:
await exec_.finish("未接受到sql语句")
db = Tortoise.get_connection("default")
# try:
# 判断是否为SELECT语句
if sql.lower().startswith("select"):
pass
# # 分割语句
try:
# 判断是否为SELECT语句
if sql.lower().startswith("select"):
# 分割语句
try:
page = int(sql.split(" ")[-1]) - 1
sql_list = sql.split(" ")[:-1]
except ValueError:
page = 0
sql_list = sql.split(" ")
# 拼接语句
sql = " ".join(sql_list)
query = db.text(sql)
res = await db.all(query)
msg_list = [f"{page+1}页查询结果:"]
# logger.info(res)
# 获取所有字段
keys = res[0].keys()
# 每页10条
for i in res[page * 10 : (page + 1) * 10]:
msg = ""
for key in keys:
msg += f"{key}: {i[key]}\n"
msg += f"{page+1}页第{res.index(i)+1}"
msg_list.append(msg)
# 检查是私聊还是群聊
try:
forward_msg_list = custom_forward_msg(msg_list, bot.self_id)
await bot.send_group_forward_msg(group_id=event.group_id, messages=forward_msg_list)
except:
for msg in msg_list:
await exec_.send(msg)
await asyncio.sleep(0.2)
return
query = db.text(sql)
await db.first(query)
await exec_.send("执行 sql 语句成功.")
except Exception as e:
await exec_.send(f"执行 sql 语句失败 {type(e)}{e}")
logger.error(f"执行 sql 语句失败 {type(e)}{e}")
page = int(sql.split(" ")[-1]) - 1
sql_list = sql.split(" ")[:-1]
except ValueError:
page = 0
sql_list = sql.split(" ")
# 拼接语句
sql = " ".join(sql_list)
res = await db.execute_query_dict(sql)
msg_list = [f"{page+1}页查询结果:"]
# logger.info(res)
# 获取所有字段
keys = res[0].keys()
# 每页10条
for i in res[page * 10 : (page + 1) * 10]:
msg = ""
for key in keys:
msg += f"{key}: {i[key]}\n"
msg += f"{page+1}页第{res.index(i)+1}"
msg_list.append(msg)
# 检查是私聊还是群聊
if isinstance(event, GroupMessageEvent):
forward_msg_list = custom_forward_msg(msg_list, bot.self_id)
await bot.send_group_forward_msg(
group_id=event.group_id, messages=forward_msg_list
)
else:
for msg in msg_list:
await exec_.send(msg)
await asyncio.sleep(0.2)
return
else:
await TestSQL.raw(sql)
await exec_.send("执行 sql 语句成功.")
# except Exception as e:
# await exec_.send(f"执行 sql 语句失败 {type(e)}{e}")
# logger.error(f"执行 sql 语句失败 {type(e)}{e}")
@tables.handle()
async def _(bot: Bot, event: MessageEvent):
# 获取所有表
query = db.text("select tablename from pg_tables where schemaname = 'public'")
res = await db.all(query)
db = Tortoise.get_connection("default")
query = await db.execute_query_dict(
"select tablename from pg_tables where schemaname = 'public'"
)
msg = "数据库中的所有表名:\n"
for tablename in res:
for tablename in query:
msg += str(tablename["tablename"]) + "\n"
await tables.finish(msg)

View File

@ -1,35 +1,39 @@
from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent,
GROUP,
GroupMessageEvent,
Message,
ActionFailed,
)
from nonebot import on_command, on_regex
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from nonebot.rule import to_me
from utils.utils import is_number
from utils.manager import group_manager, plugins2settings_manager
from models.group_info import GroupInfo
from services.log import logger
from configs.config import NICKNAME
from nonebot.params import Command, CommandArg
from typing import Tuple
from nonebot import on_command, on_regex
from nonebot.adapters.onebot.v11 import (
GROUP,
Bot,
GroupMessageEvent,
Message,
MessageEvent,
)
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from configs.config import NICKNAME
from models.group_info import GroupInfo
from services.log import logger
from utils.depends import OneCommand
from utils.image_utils import text2image
from utils.manager import group_manager, plugins2settings_manager
from utils.message_builder import image
from utils.utils import is_number
__zx_plugin_name__ = "管理群操作 [Superuser]"
__plugin_usage__ = """
usage
群权限 | 群白名单 | 退出群 操作
指令
退群 [group_id]
退群添加/删除群白名单添加/删除群认证当在群聊中这五个命令且没有指定群号时默认指定当前群聊
指令:
退群 ?[group_id]
修改群权限 [group_id] [等级]
添加群白名单 *[group_id]
删除群白名单 *[group_id]
添加群认证 *[group_id]
删除群认证 *[group_id]
修改群权限 [等级]: 该命令仅在群聊时生效默认修改当前群聊
添加群白名单 ?*[group_id]
删除群白名单 ?*[group_id]
添加群认证 ?*[group_id]
删除群认证 ?*[group_id]
查看群白名单
""".strip()
__plugin_des__ = "管理群操作"
@ -53,7 +57,7 @@ my_group_level = on_command(
"查看群权限", aliases={"群权限"}, priority=5, permission=GROUP, block=True
)
what_up_group_level = on_regex(
".*?(提高|提升|升高|增加|加上)(.*?)群权限.*?",
"(:?提高|提升|升高|增加|加上).*?群权限",
rule=to_me(),
priority=5,
permission=GROUP,
@ -73,47 +77,57 @@ group_auth = on_command(
@del_group.handle()
async def _(bot: Bot, arg: Message = CommandArg()):
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
group_id = arg.extract_plain_text().strip()
if not group_id and isinstance(event, GroupMessageEvent):
group_id = event.group_id
if group_id:
if is_number(group_id):
group_list = [x["group_id"] for x in await bot.get_group_list()]
group_id = int(group_id)
if group_id not in group_list:
logger.debug("群聊不存在", "退群", event.user_id, target=group_id)
await del_group.finish(f"{NICKNAME}未在该群聊中...")
try:
await bot.set_group_leave(group_id=int(group_id))
logger.info(f"退出群聊 {group_id} 成功")
await bot.set_group_leave(group_id=group_id)
logger.info(f"{NICKNAME}退出群聊成功", "退群", event.user_id, target=group_id)
await del_group.send(f"退出群聊 {group_id} 成功", at_sender=True)
group_manager.delete_group(int(group_id))
await GroupInfo.delete_group_info(int(group_id))
group_manager.delete_group(group_id)
await GroupInfo.filter(group_id=group_id).delete()
except Exception as e:
logger.info(f"退出群聊 {group_id} 失败 e:{e}")
logger.error(f"退出群聊失败", "退群", event.user_id, target=group_id, e=e)
await del_group.send(f"退出群聊 {group_id} 失败", at_sender=True)
else:
await del_group.finish(f"请输入正确的群号", at_sender=True)
await del_group.send(f"请输入正确的群号", at_sender=True)
else:
await del_group.finish(f"请输入群号", at_sender=True)
await del_group.send(f"请输入群号", at_sender=True)
@add_group_level.handle()
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
msg = msg.split()
group_id = 0
level = 0
if isinstance(event, GroupMessageEvent) and len(msg) == 1:
msg = [event.group_id, msg[0]]
if not msg:
await add_group_level.finish("用法:修改群权限 [group] [level]")
msg = msg.split()
await add_group_level.finish("缺失参数...")
if len(msg) < 2:
await add_group_level.finish("参数不完全..[group] [level]")
await add_group_level.finish("缺失参数...")
if is_number(msg[0]) and is_number(msg[1]):
group_id = msg[0]
group_id = int(msg[0])
level = int(msg[1])
else:
await add_group_level.finish("参数错误...group和level必须是数字..")
await add_group_level.finish("参数错误...群号和等级必须是数字..")
old_level = group_manager.get_group_level(group_id)
group_manager.set_group_level(group_id, level)
await add_group_level.send("修改成功...", at_sender=True)
if level > -1:
await bot.send_group_msg(
group_id=int(group_id), message=f"管理员修改了此群权限:{old_level} -> {level}"
group_id=group_id, message=f"管理员修改了此群权限:{old_level} -> {level}"
)
logger.info(f"{event.user_id} 修改了 {group_id} 的权限:{level}")
logger.info(f"修改群权限:{level}", "修改群权限", event.user_id, target=group_id)
@my_group_level.handle()
@ -127,78 +141,104 @@ async def _(event: GroupMessageEvent):
if plugin_name == "pixiv":
plugin_name = "搜图 p站排行"
tmp += f"{plugin_name}\n"
if tmp:
tmp = "\n目前无法使用的功能:\n" + tmp
await my_group_level.finish(f"当前群权限:{level}{tmp}")
if not tmp:
await my_group_level.finish(f"当前群权限:{level}")
await my_group_level.finish(
f"当前群权限:{level}\n目前无法使用的功能:\n"
+ image(await text2image(tmp, padding=10, color="#f9f6f2"))
)
@what_up_group_level.handle()
async def _():
await what_up_group_level.finish(
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限"
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.超级管理员修改权限"
)
@manager_group_whitelist.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(
bot: Bot, event: MessageEvent, cmd: str = OneCommand(), arg: Message = CommandArg()
):
msg = arg.extract_plain_text().strip().split()
if not msg and isinstance(event, GroupMessageEvent):
msg = [event.group_id]
if not msg:
await manager_group_whitelist.finish("请输入群号")
all_group = [g["group_id"] for g in await bot.get_group_list()]
error_group = []
group_list = []
for group in msg:
if is_number(group) and int(group) in all_group:
group_list.append(int(group))
for group_id in msg:
if is_number(group_id) and int(group_id) in all_group:
group_list.append(int(group_id))
else:
logger.debug(f"群号不合法或不存在", cmd, target=group_id)
error_group.append(group_id)
if group_list:
for group in group_list:
for group_id in group_list:
if cmd in ["添加群白名单"]:
group_manager.add_group_white_list(group)
group_manager.add_group_white_list(group_id)
else:
group_manager.delete_group_white_list(group)
group_manager.delete_group_white_list(group_id)
group_list = [str(x) for x in group_list]
await manager_group_whitelist.send("已成功将 " + "\n".join(group_list) + " " + cmd)
else:
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
group_manager.save()
if error_group:
await manager_group_whitelist.send("以下群聊不合法或不存在:\n" + "\n".join(error_group))
@show_group_whitelist.handle()
async def _():
x = group_manager.get_group_white_list()
x = [str(g) for g in x]
if x:
await show_group_whitelist.send("目前的群白名单:\n" + "\n".join(x))
else:
await show_group_whitelist.send("没有任何群在群白名单...")
group = [str(g) for g in group_manager.get_group_white_list()]
if not group:
await show_group_whitelist.finish("没有任何群在群白名单...")
await show_group_whitelist.send("目前的群白名单:\n" + "\n".join(group))
@group_auth.handle()
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(
bot: Bot, event: MessageEvent, cmd: str = OneCommand(), arg: Message = CommandArg()
):
msg = arg.extract_plain_text().strip().split()
if isinstance(event, GroupMessageEvent) and not msg:
msg = [event.group_id]
if not msg:
await manager_group_whitelist.finish("请输入群号")
error_group = []
all_group = [g["group_id"] for g in await bot.get_group_list()]
for group_id in msg:
if not is_number(group_id):
await group_auth.send(f"{group_id}非纯数字,已跳过该项..")
group_id = int(group_id)
if cmd[:2] == "添加":
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 1)
else:
if is_number(group_id) and group_id in all_group:
if cmd[:2] == "添加":
try:
group_info = await bot.get_group_info(group_id=group_id)
except ActionFailed:
group_info = {
"group_id": group_id,
"group_name": "_",
"max_member_count": -1,
"member_count": -1,
}
await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
await GroupInfo.update_or_create(
group_id=group_info["group_id"],
defaults={
"group_flag": 1,
"group_name": group_info["group_name"],
"max_member_count": group_info["max_member_count"],
"member_count": group_info["member_count"],
},
)
except Exception as e:
await group_auth.send(f"添加群认证 {group_id} 发生错误!")
logger.error(f"添加群认证发生错误", cmd, target=group_id, e=e)
else:
await group_auth.send(f"已为 {group_id} {cmd[:2]}群认证..")
logger.info(f"添加群认证成功", cmd, target=group_id)
else:
if group := await GroupInfo.filter(group_id=group_id).first():
await group.update_or_create(
group_id=group_id, defaults={"group_flag": 0}
)
await group_auth.send(f"已删除 {group_id} 群认证..")
logger.info(f"删除群认证成功", cmd, target=group_id)
else:
await group_auth.send(f"未查找到群聊: {group_id}")
logger.info(f"未找到群聊", cmd, target=group_id)
else:
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 0)
await group_auth.send(f"已为 {group_id} {cmd[:2]}群认证..")
logger.debug(f"群号不合法或不存在", cmd, target=group_id)
error_group.append(str(group_id))
if error_group:
await manager_group_whitelist.send("以下群聊不合法或不存在:\n" + "\n".join(error_group))

View File

@ -1,21 +1,21 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.manager import (
plugins2cd_manager,
plugins2settings_manager,
plugins2block_manager,
group_manager,
)
from configs.config import Config
from services.log import logger
from utils.manager import (
group_manager,
plugins2block_manager,
plugins2cd_manager,
plugins2settings_manager,
)
from utils.utils import scheduler
__zx_plugin_name__ = "重载插件配置 [Superuser]"
__zx_plugin_name__ = "重载配置 [Superuser]"
__plugin_usage__ = """
usage
重载插件配置
重载配置
plugins2settings,
plugins2cd
plugins2block
@ -23,23 +23,15 @@ usage
指令
重载插件配置
""".strip()
__plugin_des__ = "重载插件配置"
__plugin_des__ = "重载配置"
__plugin_cmd__ = [
"重载插件配置",
"重载配置",
]
__plugin_version__ = 0.1
__plugin_version__ = 0.2
__plugin_author__ = "HibiKier"
__plugin_configs__ = {
"AUTO_RELOAD": {
"value": False,
"help": "自动重载配置文件",
"default_value": False
},
"AUTO_RELOAD_TIME": {
"value": 180,
"help": "控制自动重载配置文件时长",
"default_value": 180
}
"AUTO_RELOAD": {"value": False, "help": "自动重载配置文件", "default_value": False},
"AUTO_RELOAD_TIME": {"value": 180, "help": "控制自动重载配置文件时长", "default_value": 180},
}
@ -59,7 +51,7 @@ async def _():
@scheduler.scheduled_job(
'interval',
"interval",
seconds=Config.get_config("reload_setting", "AUTO_RELOAD_TIME", 180),
)
async def _():

View File

@ -1,12 +1,16 @@
from typing import List, Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.exception import ActionFailed
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
from models.level_user import LevelUser
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
from utils.utils import get_message_at, is_number
from services.log import logger
from utils.depends import AtList, OneCommand
from utils.message_builder import at
from nonebot.params import Command, CommandArg
from typing import Tuple
from utils.utils import is_number
__zx_plugin_name__ = "用户权限管理 [Superuser]"
__plugin_usage__ = """
@ -16,12 +20,14 @@ usage
添加权限 [at] [权限]
添加权限 [qq] [group_id] [权限]
删除权限 [at]
删除权限 [qq] [group_id]
""".strip()
__plugin_des__ = "增删改用户的权限"
__plugin_cmd__ = [
"添加权限 [at] [权限]",
"添加权限 [qq] [group_id] [权限]",
"删除权限 [at]",
"删除权限 [qq] [group_id]",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
@ -40,21 +46,22 @@ super_cmd = on_command(
async def _(
bot: Bot,
event: MessageEvent,
cmd: Tuple[str, ...] = Command(),
cmd: str = OneCommand(),
arg: Message = CommandArg(),
at_list: List[int] = AtList(),
):
group_id = event.group_id if isinstance(event, GroupMessageEvent) else -1
level = None
args = arg.extract_plain_text().strip().split()
qq = get_message_at(event.json())
flag = 2
qq = None
try:
if qq:
qq = qq[0]
if cmd[0][:2] == "添加" and args and is_number(args[0]):
if at_list:
qq = at_list[0]
if cmd[:2] == "添加" and args and is_number(args[0]):
level = int(args[0])
else:
if cmd[0][:2] == "添加":
if cmd[:2] == "添加":
if (
len(args) > 2
and is_number(args[0])
@ -69,33 +76,39 @@ async def _(
qq = int(args[0])
group_id = int(args[1])
flag = 1
level = -1 if cmd[0][:2] == "删除" else level
level = -1 if cmd[:2] == "删除" else level
if group_id == -1 or not level or not qq:
raise IndexError()
except IndexError:
await super_cmd.finish(__plugin_usage__)
if not qq:
await super_cmd.finish("未指定对象...")
try:
if cmd[0][:2] == "添加":
if await LevelUser.set_level(qq, group_id, level, 1):
result = f"添加管理成功, 权限: {level}"
else:
result = f"管理已存在, 更新权限: {level}"
if cmd[:2] == "添加":
await LevelUser.set_level(qq, group_id, level, 1)
result = f"设置权限成功, 权限: {level}"
else:
if await LevelUser.delete_level(qq, event.group_id):
if await LevelUser.delete_level(qq, group_id):
result = "删除管理成功!"
else:
result = "该账号无管理权限!"
if flag == 2:
await super_cmd.send(result)
elif flag == 1:
await bot.send_group_msg(
group_id=group_id,
message=Message(
f"{at(qq)}管理员修改了你的权限"
f"\n--------\n你当前的权限等级:{level if level != -1 else 0}"
),
)
try:
await bot.send_group_msg(
group_id=group_id,
message=Message(
f"{at(qq)}管理员修改了你的权限"
f"\n--------\n你当前的权限等级:{level if level != -1 else 0}"
),
)
except ActionFailed:
pass
await super_cmd.send("修改成功")
logger.info(
f"修改权限: {level if level != -1 else 0}", cmd, event.user_id, group_id, qq
)
except Exception as e:
await super_cmd.send("执行指令失败!")
logger.error(f"执行指令失败 e{e}")
logger.error(f"执行指令失败", cmd, event.user_id, group_id, qq, e=e)

View File

@ -1,58 +0,0 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message
from nonebot.rule import to_me
from utils.utils import is_number
from services.log import logger
from utils.manager import group_manager
from nonebot.params import Command, CommandArg
from typing import Tuple
__zx_plugin_name__ = "超级用户被动开关 [Superuser]"
__plugin_usage__ = """
usage
超级用户被动开关
指令
开启/关闭广播通知
""".strip()
__plugin_des__ = "超级用户被动开关"
__plugin_cmd__ = [
"开启/关闭广播通知",
]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
oc_gb = on_command(
"开启广播通知",
aliases={"关闭广播通知"},
rule=to_me(),
permission=SUPERUSER,
priority=1,
block=True,
)
@oc_gb.handle()
async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
group = arg.extract_plain_text().strip()
if group:
if is_number(group):
group = int(group)
for g in await bot.get_group_list():
if g["group_id"] == group:
break
else:
await oc_gb.finish("没有加入这个群...", at_sender=True)
if cmd == "开启广播通知":
logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播")
await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True)
else:
logger.info(f"USER {event.user_id} 关闭了 GROUP {group} 的广播")
await oc_gb.finish(await group_manager.close_group_task(group, "broadcast"), at_sender=True)
else:
await oc_gb.finish("请输入正确的群号", at_sender=True)
else:
await oc_gb.finish("请输入要关闭广播的群号", at_sender=True)

View File

@ -1,11 +1,11 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.utils import get_bot
from services.log import logger
from models.group_info import GroupInfo
from models.friend_user import FriendUser
from models.friend_user import FriendUser
from models.group_info import GroupInfo
from services.log import logger
__zx_plugin_name__ = "更新群/好友信息 [Superuser]"
__plugin_usage__ = """
@ -32,39 +32,46 @@ update_friend_info = on_command(
@update_group_info.handle()
async def _():
bot = get_bot()
async def _(bot: Bot, event: MessageEvent):
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
num = 0
rst = ""
for g in gl:
group_info = await bot.get_group_info(group_id=g)
if await GroupInfo.add_group_info(
group_info["group_id"],
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
):
try:
group_info = await bot.get_group_info(group_id=g)
await GroupInfo.update_or_create(
group_id=group_info["group_id"],
defaults={
"group_name": group_info["group_name"],
"max_member_count": group_info["max_member_count"],
"member_count": group_info["member_count"],
},
)
num += 1
logger.info(f"自动更新群组 {g} 信息成功")
else:
logger.info(f"自动更新群组 {g} 信息失败")
rst += f"{g} 更新失败\n"
await update_group_info.send(f"成功更新了 {num} 个群的信息\n{rst[:-1]}")
logger.debug(
"群聊信息更新成功", "更新群信息", event.user_id, target=group_info["group_id"]
)
except Exception as e:
logger.error(f"更新群聊信息失败", "更新群信息", event.user_id, target=g, e=e)
await update_group_info.send(f"成功更新了 {len(gl)} 个群的信息")
logger.info(f"更新群聊信息完成,共更新了 {len(gl)} 个群的信息", "更新群信息", event.user_id)
@update_friend_info.handle()
async def _():
async def _(bot: Bot, event: MessageEvent):
num = 0
rst = ""
fl = await get_bot().get_friend_list()
error_list = []
fl = await bot.get_friend_list()
for f in fl:
if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
try:
await FriendUser.update_or_create(
user_id=f["user_id"], defaults={"nickname": f["nickname"]}
)
logger.debug(f"更新好友信息成功", "更新好友信息", event.user_id, target=f["user_id"])
num += 1
else:
logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
rst += f'{f["user_id"]} 更新失败\n'
await update_friend_info.send(f"成功更新了 {num} 个好友的信息\n{rst[:-1]}")
except Exception as e:
logger.error(f"更新好友信息失败", "更新好友信息", event.user_id, target=f["user_id"], e=e)
await update_friend_info.send(f"成功更新了 {num} 个好友的信息")
if error_list:
await update_friend_info.send(f"以下好友更新失败:\n" + "\n".join(error_list))
logger.info(f"更新好友信息完成,共更新了 {num} 个群的信息", "更新好友信息", event.user_id)

View File

@ -1,11 +1,12 @@
from nonebot import on_command
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from utils.message_builder import image
from .data_source import create_help_image, SUPERUSER_HELP_IMAGE
from .data_source import SUPERUSER_HELP_IMAGE, create_help_image
__zx_plugin_name__ = '超级用户帮助 [Superuser]'
__zx_plugin_name__ = "超级用户帮助 [Superuser]"
if SUPERUSER_HELP_IMAGE.exists():
@ -20,5 +21,4 @@ super_help = on_command(
async def _():
if not SUPERUSER_HELP_IMAGE.exists():
await create_help_image()
x = image(SUPERUSER_HELP_IMAGE)
await super_help.finish(x)
await super_help.finish(image(SUPERUSER_HELP_IMAGE))

View File

@ -1,6 +1,6 @@
from nonebot import on_command
from utils.message_builder import image
from utils.message_builder import image
__zx_plugin_name__ = "更新信息"
__plugin_usage__ = """
@ -26,8 +26,7 @@ update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, b
@update_info.handle()
async def _():
img = image("update_info.png")
if img:
if img := image("update_info.png"):
await update_info.finish(image("update_info.png"))
else:
await update_info.finish("目前没有更新信息哦")

View File

@ -1,11 +1,18 @@
from typing import Optional
import platform
from pathlib import Path
from typing import Optional
from .utils import ConfigsManager
import platform
if platform.system() == "Linux":
import os
hostip = os.popen("cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }'").read().replace("\n","")
hostip = (
os.popen("cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }'")
.read()
.replace("\n", "")
)
# 回复消息名称
NICKNAME: str = "小真寻"
@ -14,7 +21,7 @@ NICKNAME: str = "小真寻"
# 如果填写了bind就不需要再填写后面的字段了#
# 示例:"bind": "postgresql://user:password@127.0.0.1:5432/database"
bind: str = "" # 数据库连接链接
sql_name: str = "postgresql"
sql_name: str = "postgres"
user: str = "" # 数据用户名
password: str = "" # 数据库密码
address: str = "" # 数据库地址

View File

@ -1,8 +1,9 @@
import copy
from typing import Optional, Any, Union
from pathlib import Path
from ruamel.yaml import YAML
from typing import Any, Optional, Union
from ruamel import yaml
from ruamel.yaml import YAML
from ruamel.yaml.scanner import ScannerError
@ -50,7 +51,7 @@ class ConfigsManager:
*,
name: Optional[str] = None,
help_: Optional[str] = None,
default_value: Optional[str] = None,
default_value: Optional[Any] = None,
_override: bool = False,
):
"""

View File

@ -1,24 +1,37 @@
from services.db_context import db
from typing import Dict
from typing import Optional, List
from services.log import logger
from tortoise import fields
from services.db_context import Model
from .goods_info import GoodsInfo
class BagUser(db.Model):
__tablename__ = "bag_users"
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
gold = db.Column(db.Integer(), default=100)
props = db.Column(db.TEXT(), nullable=False, default="") # 旧道具字段(废弃)
spend_total_gold = db.Column(db.Integer(), default=0)
get_total_gold = db.Column(db.Integer(), default=0)
get_today_gold = db.Column(db.Integer(), default=0)
spend_today_gold = db.Column(db.Integer(), default=0)
property = db.Column(db.JSON(), nullable=False, default={}) # 新道具字段
class BagUser(Model):
_idx1 = db.Index("bag_group_users_idx1", "user_qq", "group_id", unique=True)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
gold = fields.IntField(default=100)
"""金币数量"""
spend_total_gold = fields.IntField(default=0)
"""花费金币总数"""
get_total_gold = fields.IntField(default=0)
"""获取金币总数"""
get_today_gold = fields.IntField(default=0)
"""今日获取金币"""
spend_today_gold = fields.IntField(default=0)
"""今日获取金币"""
property: Dict[str, int] = fields.JSONField(default={})
"""道具"""
class Meta:
table = "bag_users"
table_description = "用户道具数据表"
unique_together = ("user_qq", "group_id")
@classmethod
async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
@ -29,13 +42,7 @@ class BagUser(db.Model):
:param user_qq: qq号
:param group_id: 所在群号
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first()
if not user:
user = await cls.create(
user_qq=user_qq,
group_id=group_id,
)
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
return (
f"当前金币:{user.gold}\n今日获取金币:{user.get_today_gold}\n今日花费金币:{user.spend_today_gold}"
f"\n今日收益:{user.get_today_gold - user.spend_today_gold}"
@ -51,19 +58,13 @@ class BagUser(db.Model):
:param user_qq: qq号
:param group_id: 所在群号
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first()
if user:
return user.gold
else:
await cls.create(
user_qq=user_qq,
group_id=group_id,
)
return 100
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
return user.gold
@classmethod
async def get_property(cls, user_qq: int, group_id: int, only_active: bool = False) -> Dict[str, int]:
async def get_property(
cls, user_qq: int, group_id: int, only_active: bool = False
) -> Dict[str, int]:
"""
说明:
获取当前道具
@ -72,22 +73,18 @@ class BagUser(db.Model):
:param group_id: 所在群号
:param only_active: 仅仅获取主动使用的道具
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first()
if user:
if only_active and user.property:
data = {}
name_list = [x.goods_name for x in await GoodsInfo.get_all_goods() if not x.is_passive]
for key in [x for x in user.property.keys() if x in name_list]:
data[key] = user.property[key]
return data
return user.property
else:
await cls.create(
user_qq=user_qq,
group_id=group_id,
)
return {}
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
if only_active and user.property:
data = {}
name_list = [
x.goods_name
for x in await GoodsInfo.get_all_goods()
if not x.is_passive
]
for key in [x for x in user.property if x in name_list]:
data[key] = user.property[key]
return data
return user.property
@classmethod
async def add_gold(cls, user_qq: int, group_id: int, num: int):
@ -99,23 +96,11 @@ class BagUser(db.Model):
:param group_id: 所在群号
:param num: 金币数量
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
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,
group_id=group_id,
gold=100 + num,
get_total_gold=num,
get_today_gold=num,
)
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
user.gold = user.gold + num
user.get_total_gold = user.get_total_gold + num
user.get_today_gold = user.get_today_gold + num
await user.save(update_fields=["gold", "get_today_gold", "get_total_gold"])
@classmethod
async def spend_gold(cls, user_qq: int, group_id: int, num: int):
@ -127,26 +112,14 @@ class BagUser(db.Model):
:param group_id: 所在群号
:param num: 金币数量
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
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,
group_id=group_id,
gold=100 - num,
spend_total_gold=num,
spend_today_gold=num,
)
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
user.gold = user.gold - num
user.spend_total_gold = user.spend_total_gold + num
user.spend_today_gold = user.spend_today_gold + num
await user.save(update_fields=["gold", "spend_total_gold", "spend_today_gold"])
@classmethod
async def add_property(cls, user_qq: int, group_id: int, name: str):
async def add_property(cls, user_qq: int, group_id: int, name: str, num: int = 1):
"""
说明:
增加道具
@ -154,19 +127,15 @@ class BagUser(db.Model):
:param user_qq: qq号
:param group_id: 所在群号
:param name: 道具名称
:param num: 道具数量
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
if user:
p = user.property
if p.get(name) is None:
p[name] = 1
else:
p[name] += 1
await user.update(property=p).apply()
else:
await cls.create(user_qq=user_qq, group_id=group_id, property={name: 1})
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
property_ = user.property
if property_.get(name) is None:
property_[name] = 0
property_[name] += num
user.property = property_
await user.save(update_fields=["property"])
@classmethod
async def delete_property(
@ -181,54 +150,15 @@ class BagUser(db.Model):
:param name: 道具名称
:param num: 使用个数
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
if user:
property_ = user.property
if name in property_:
if property_.get(name) == num:
del property_[name]
else:
property_[name] -= num
await user.update(property=property_).apply()
return True
return False
@classmethod
async def buy_property(
cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int
) -> bool:
"""
说明:
购买道具
参数:
:param user_qq: 用户qq
:param group_id: 所在群聊
:param goods: 商品
:param goods_num: 商品数量
"""
try:
# 折扣后金币
spend_gold = goods.goods_discount * goods.goods_price * goods_num
await BagUser.spend_gold(user_qq, group_id, spend_gold)
for _ in range(goods_num):
await BagUser.add_property(user_qq, group_id, goods.goods_name)
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
property_ = user.property
if name in property_:
if (n := property_.get(name, 0)) < num:
return False
if n == num:
del property_[name]
else:
property_[name] -= num
await user.save(update_fields=["property"])
return True
except Exception as e:
logger.error(f"buy_property 发生错误 {type(e)}{e}")
return False
@classmethod
async def get_all_users(cls, group_id: Optional[int] = None) -> List["BagUser"]:
"""
说明:
获取所有用户数据
参数:
:param group_id: 群号
"""
if not group_id:
query = await cls.query.gino.all()
else:
query = await cls.query.where((cls.group_id == group_id)).gino.all()
return query

View File

@ -1,16 +1,26 @@
from services.db_context import db
import time
from typing import Union
from tortoise import fields
from services.db_context import Model
from services.log import logger
class BanUser(db.Model):
__tablename__ = "ban_users"
class BanUser(Model):
user_qq = db.Column(db.BigInteger(), nullable=False, primary_key=True)
ban_level = db.Column(db.Integer(), nullable=False)
ban_time = db.Column(db.BigInteger())
duration = db.Column(db.BigInteger())
user_qq = fields.IntField(pk=True)
"""用户id"""
ban_level = fields.IntField()
"""使用ban命令的用户等级"""
ban_time = fields.BigIntField()
"""ban开始的时间"""
duration = fields.BigIntField()
"""ban时长"""
_idx1 = db.Index("ban_group_users_idx1", "user_qq", unique=True)
class Meta:
table = "ban_users"
table_description = ".ban/b了 封禁人员数据表"
@classmethod
async def check_ban_level(cls, user_qq: int, level: int) -> bool:
@ -21,30 +31,34 @@ class BanUser(db.Model):
:param user_qq: unban用户的qq号
:param level: ban掉目标用户的权限等级
"""
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
if not user:
return False
if user.ban_level > level:
return True
user = await cls.filter(user_qq=user_qq).first()
if user:
logger.debug(
f"检测用户被ban等级user_level: {user.ban_level}level: {level}",
target=user_qq,
)
return bool(user and user.ban_level > level)
return False
@classmethod
async def check_ban_time(cls, user_qq: int) -> str:
async def check_ban_time(cls, user_qq: int) -> Union[str, int]:
"""
说明:
检测用户被ban时长
参数:
:param user_qq: qq号
"""
query = cls.query.where((cls.user_qq == user_qq))
user = await query.gino.first()
if not user:
return ""
if time.time() - (user.ban_time + user.duration) > 0 and user.duration != -1:
return ""
if user.duration == -1:
return ""
return time.time() - user.ban_time - user.duration
logger.debug(f"获取用户ban时长", target=user_qq)
if user := await cls.filter(user_qq=user_qq).first():
if (
time.time() - (user.ban_time + user.duration) > 0
and user.duration != -1
):
return ""
if user.duration == -1:
return ""
return int(time.time() - user.ban_time - user.duration)
return ""
@classmethod
async def is_ban(cls, user_qq: int) -> bool:
@ -54,28 +68,29 @@ class BanUser(db.Model):
参数:
:param user_qq: qq号
"""
logger.debug(f"检测是否被ban", target=user_qq)
if await cls.check_ban_time(user_qq):
return True
else:
await cls.unban(user_qq)
return False
return False
@classmethod
async def is_super_ban(cls, user_qq: int) -> bool:
"""
说明:
判断用户是否被ban
判断用户是否被超级用户ban / b了
参数:
:param user_qq: qq号
"""
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
if not user:
return False
if user.ban_level == 10:
return True
logger.debug(f"检测是否被超级用户权限封禁", target=user_qq)
if user := await cls.filter(user_qq=user_qq).first():
if user.ban_level == 10:
return True
return False
@classmethod
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
async def ban(cls, user_qq: int, ban_level: int, duration: int):
"""
说明:
ban掉目标用户
@ -84,22 +99,15 @@ class BanUser(db.Model):
:param ban_level: 使用ban命令用户的权限
:param duration: ban时长
"""
query = cls.query.where((cls.user_qq == user_qq))
query = query.with_for_update()
user = await query.gino.first()
if not await cls.check_ban_time(user_qq):
logger.debug(f"封禁用户,等级:{ban_level},时长: {duration}", target=user_qq)
if await cls.filter(user_qq=user_qq).first():
await cls.unban(user_qq)
user = None
if user is None:
await cls.create(
user_qq=user_qq,
ban_level=ban_level,
ban_time=time.time(),
duration=duration,
)
return True
else:
return False
await cls.create(
user_qq=user_qq,
ban_level=ban_level,
ban_time=time.time(),
duration=duration,
)
@classmethod
async def unban(cls, user_qq: int) -> bool:
@ -109,11 +117,8 @@ class BanUser(db.Model):
参数:
:param user_qq: qq号
"""
query = cls.query.where((cls.user_qq == user_qq))
query = query.with_for_update()
user = await query.gino.first()
if user is None:
return False
else:
await cls.delete.where((cls.user_qq == user_qq)).gino.status()
logger.debug("解除封禁", target=user_qq)
if user := await cls.filter(user_qq=user_qq).first():
await user.delete()
return True
return False

View File

@ -1,81 +1,30 @@
from datetime import datetime, timedelta
from typing import List, Literal, Optional, Tuple, Union
from typing import Any, List, Literal, Optional, Tuple, Union
from services.db_context import db
from tortoise import fields
from tortoise.functions import Count
from services.db_context import Model
class ChatHistory(db.Model):
__tablename__ = "chat_history"
class ChatHistory(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger())
text = db.Column(db.Text())
plain_text = db.Column(db.Text())
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
text = fields.TextField()
"""文本内容"""
plain_text = fields.TextField()
"""纯文本"""
create_time = fields.DatetimeField(auto_now_add=True)
"""创建时间"""
@classmethod
async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str, plain_text: str):
await cls.create(
user_qq=user_qq, group_id=group_id, text=text, plain_text=plain_text, create_time=datetime.now()
)
@classmethod
async def get_user_msg(
cls,
uid: int,
msg_type: Optional[Literal["private", "group"]],
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取用户消息
参数:
:param uid: 用户qq
:param msg_type: 消息类型私聊或群聊
:param days: 限制日期
"""
return await cls._get_msg(uid, None, "user", msg_type, days).gino.all()
@classmethod
async def get_group_user_msg(
cls,
uid: int,
gid: int,
limit: int = 10,
date_scope: Tuple[datetime, datetime] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊指定用户聊天记录
参数:
:param uid: qq
:param gid: 群号
:param limit: 获取数量
:param date_scope: 日期范围默认None为全搜索
"""
return (
await cls._get_msg(uid, gid, "group", days=date_scope)
.limit(limit)
.gino.all()
)
@classmethod
async def get_group_user_msg_count(cls, uid: int, gid: int) -> Optional[int]:
"""
说明:
查询群聊指定用户的聊天记录数量
参数:
:param uid: qq
:param gid: 群号
"""
if x := await db.first(
db.text(
f"SELECT COUNT(id) as sum FROM public.chat_history WHERE user_qq = {uid} AND group_id = {gid}"
)
):
return x[0]
return None
class Meta:
table = "chat_history"
table_description = "聊天记录数据表"
@classmethod
async def get_group_msg_rank(
@ -84,7 +33,7 @@ class ChatHistory(db.Model):
limit: int = 10,
order: str = "DESC",
date_scope: Optional[Tuple[datetime, datetime]] = None,
) -> Optional[Tuple[int, int]]:
) -> List["ChatHistory"]:
"""
说明:
获取排行数据
@ -94,89 +43,39 @@ class ChatHistory(db.Model):
:param order: 排序类型descdes
:param date_scope: 日期范围
"""
sql = f"SELECT user_qq, COUNT(id) as sum FROM public.chat_history WHERE group_id = {gid} "
if date_scope:
sql += f"AND create_time BETWEEN '{date_scope[0]}' AND '{date_scope[1]}' "
sql += f"GROUP BY user_qq ORDER BY sum {order if order and order.upper() != 'DES' else ''} LIMIT {limit}"
return await db.all(db.text(sql))
return list(
await cls.filter(group_id=gid, create_time__range=date_scope)
.annotate(count=Count("user_qq"))
.order_by(order)
.group_by("user_qq")
.limit(limit)
.values_list("user_qq", "count")
)
@classmethod
async def get_group_first_msg_datetime(cls, gid: int) -> Optional[datetime]:
async def get_group_first_msg_datetime(cls, group_id: int) -> Optional[datetime]:
"""
说明:
获取群第一条记录消息时间
参数:
:param gid:
:param group_id: 群聊id
"""
if (
msg := await cls.query.where(cls.group_id == gid)
.order_by(cls.create_time)
.gino.first()
message := await cls.filter(group_id=group_id)
.order_by("create_time")
.first()
):
return msg.create_time
return None
return message.create_time
@classmethod
async def get_user_msg_count(
cls,
uid: int,
msg_type: Optional[Literal["private", "group"]],
days: Optional[int] = None,
) -> int:
"""
说明:
获取用户消息数量
参数:
:param uid: 用户qq
:param msg_type: 消息类型私聊或群聊
:param days: 限制日期
"""
return (
await cls._get_msg(uid, None, "user", msg_type, days, True).gino.first()
)[0]
@classmethod
async def get_group_msg(
cls,
gid: int,
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊消息
参数:
:param gid: 用户qq
:param days: 限制日期
"""
return await cls._get_msg(None, gid, "group", None, days).gino.all()
@classmethod
async def get_group_msg_count(
cls,
gid: int,
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
获取群聊消息数量
参数:
:param gid: 用户qq
:param days: 限制日期
"""
return (await cls._get_msg(None, gid, "group", None, days, True).gino.first())[
0
]
@classmethod
def _get_msg(
async def get_message(
cls,
uid: Optional[int],
gid: Optional[int],
type_: Literal["user", "group"],
msg_type: Optional[Literal["private", "group"]] = None,
days: Optional[Union[int, Tuple[datetime, datetime]]] = None,
is_select_count: bool = False,
):
) -> List["ChatHistory"]:
"""
说明:
获取消息查询query
@ -187,28 +86,21 @@ class ChatHistory(db.Model):
:param msg_type: 消息类型用户或群聊
:param days: 限制日期
"""
if is_select_count:
setattr(ChatHistory, "count", db.func.count(cls.id).label("count"))
query = cls.select("count")
else:
query = cls.query
if type_ == "user":
query = query.where(cls.user_qq == uid)
query = cls.filter(user_qq=uid)
if msg_type == "private":
query = query.where(cls.group_id == None)
query = query.filter(group_id__isnull=True)
elif msg_type == "group":
query = query.where(cls.group_id != None)
query = query.filter(group_id__not_isnull=True)
else:
query = query.where(cls.group_id == gid)
query = cls.filter(group_id=gid)
if uid:
query = query.where(cls.user_qq == uid)
query = query.filter(user_qq=uid)
if days:
if isinstance(days, int):
query = query.where(
cls.create_time >= datetime.now() - timedelta(days=days)
query = query.filter(
create_time__gte=datetime.now() - timedelta(days=days)
)
elif isinstance(days, tuple):
query = query.where(cls.create_time >= days[0]).where(
cls.create_time <= days[1]
)
return query
query = query.filter(create_at__range=days)
return await query.all()

View File

@ -1,16 +1,23 @@
from services.db_context import db
from tortoise import fields
from configs.config import Config
from services.db_context import Model
class FriendUser(db.Model):
__tablename__ = "friend_users"
class FriendUser(Model):
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.BigInteger(), nullable=False)
user_name = db.Column(db.Unicode(), nullable=False, default="")
nickname = db.Column(db.Unicode())
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_id = fields.BigIntField(unique=True)
"""用户id"""
user_name = fields.CharField(max_length=255, default="")
"""用户名称"""
nickname = fields.CharField(max_length=255, null=True)
"""私聊下自定义昵称"""
_idx1 = db.Index("friend_users_idx1", "user_id", unique=True)
class Meta:
table = "friend_users"
table_description = "好友信息数据表"
@classmethod
async def get_user_name(cls, user_id: int) -> str:
@ -20,77 +27,29 @@ class FriendUser(db.Model):
参数:
:param user_id: qq号
"""
query = cls.query.where(cls.user_id == user_id)
user = await query.gino.first()
if user:
if user := await cls.get_or_none(user_id=user_id):
return user.user_name
else:
return ""
return ""
@classmethod
async def add_friend_info(cls, user_id: int, user_name: str) -> bool:
"""
说明:
添加好友信息
参数:
:param user_id: qq号
:param user_name: 用户名称
"""
try:
query = cls.query.where(cls.user_id == user_id)
user = await query.with_for_update().gino.first()
if not user:
await cls.create(
user_id=user_id,
user_name=user_name,
)
else:
await user.update(
user_name=user_name,
).apply()
return True
except Exception:
return False
@classmethod
async def delete_friend_info(cls, user_id: int) -> bool:
"""
说明:
删除好友信息
参数:
:param user_id: qq号
"""
try:
query = cls.query.where(cls.user_id == user_id)
user = await query.with_for_update().gino.first()
if user:
await user.delete()
return True
except Exception:
return False
@classmethod
async def get_friend_nickname(cls, user_id: int) -> str:
async def get_user_nickname(cls, user_id: int) -> str:
"""
说明:
获取用户昵称
参数:
:param user_id: qq号
"""
query = cls.query.where(cls.user_id == user_id)
user = await query.gino.first()
if user:
if user := await cls.get_or_none(user_id=user_id):
if user.nickname:
_tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
if black_word := Config.get_config("nickname", "BLACK_WORD"):
for x in user.nickname:
_tmp += "*" if x in black_word else x
return _tmp
return ""
@classmethod
async def set_friend_nickname(cls, user_id: int, nickname: str) -> bool:
async def set_user_nickname(cls, user_id: int, nickname: str):
"""
说明:
设置用户昵称
@ -98,18 +57,4 @@ class FriendUser(db.Model):
:param user_id: qq号
:param nickname: 昵称
"""
try:
query = cls.query.where(cls.user_id == user_id)
user = await query.with_for_update().gino.first()
if not user:
await cls.create(
user_id=user_id,
nickname=nickname,
)
else:
await user.update(
nickname=nickname,
).apply()
return True
except Exception:
return False
await cls.update_or_create(user_id=user_id, defaults={"nickname": nickname})

View File

@ -1,38 +1,50 @@
from services.db_context import db
from typing import Optional, List, Tuple
from services.log import logger
from typing import Dict, List, Optional, Tuple
from tortoise import fields
from services.db_context import Model
class GoodsInfo(db.Model):
class GoodsInfo(Model):
__tablename__ = "goods_info"
id = db.Column(db.Integer(), primary_key=True)
goods_name = db.Column(db.TEXT(), nullable=False) # 名称
goods_price = db.Column(db.Integer(), nullable=False) # 价格
goods_description = db.Column(db.TEXT(), nullable=False) # 商品描述
goods_discount = db.Column(db.Numeric(scale=3, asdecimal=False), default=1) # 打折
goods_limit_time = db.Column(db.BigInteger(), default=0) # 限时
daily_limit = db.Column(db.Integer(), nullable=False, default=0) # 每日购买限制
daily_purchase_limit = db.Column(
db.JSON(), nullable=False, default={}
) # 每日购买限制数据存储
is_passive = db.Column(db.Boolean(), nullable=False, default=0) # 是否为被动
icon = db.Column(db.String(), default=0) # 图标
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
goods_name = fields.CharField(255, unique=True)
"""商品名称"""
goods_price = fields.IntField()
"""价格"""
goods_description = fields.TextField()
"""描述"""
goods_discount = fields.FloatField(default=1)
"""折扣"""
goods_limit_time = fields.BigIntField(default=0)
"""限时"""
daily_limit = fields.IntField(default=0)
"""每日限购"""
daily_purchase_limit: Dict[str, Dict[str, int]] = fields.JSONField(default={})
"""用户限购记录"""
is_passive = fields.BooleanField(default=False)
"""是否为被动道具"""
icon = fields.TextField(null=True)
"""图标路径"""
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
class Meta:
table = "goods_info"
table_description = "商品数据表"
@classmethod
async def add_goods(
cls,
goods_name: str,
goods_price: int,
goods_description: str,
goods_discount: float = 1,
goods_limit_time: int = 0,
daily_limit: int = 0,
is_passive: bool = False,
icon: Optional[str] = None,
) -> bool:
cls,
goods_name: str,
goods_price: int,
goods_description: str,
goods_discount: float = 1,
goods_limit_time: int = 0,
daily_limit: int = 0,
is_passive: bool = False,
icon: Optional[str] = None,
):
"""
说明:
添加商品
@ -46,22 +58,17 @@ class GoodsInfo(db.Model):
:param is_passive: 是否为被动道具
:param icon: 图标
"""
try:
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,
daily_limit=daily_limit,
is_passive=is_passive,
icon=icon
)
return True
except Exception as e:
logger.error(f"GoodsInfo add_goods {goods_name} 发生错误 {type(e)}{e}")
return False
if not await cls.filter(goods_name=goods_name).first():
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,
daily_limit=daily_limit,
is_passive=is_passive,
icon=icon,
)
@classmethod
async def delete_goods(cls, goods_name: str) -> bool:
@ -71,28 +78,23 @@ class GoodsInfo(db.Model):
参数:
:param goods_name: 商品名称
"""
query = (
await cls.query.where(cls.goods_name == goods_name)
.with_for_update()
.gino.first()
)
if not query:
return False
await query.delete()
return True
if goods := await cls.get_or_none(goods_name=goods_name):
await goods.delete()
return True
return False
@classmethod
async def update_goods(
cls,
goods_name: str,
goods_price: Optional[int] = None,
goods_description: Optional[str] = None,
goods_discount: Optional[float] = None,
goods_limit_time: Optional[int] = None,
daily_limit: Optional[int] = None,
is_passive: Optional[bool] = None,
icon: Optional[str] = None,
) -> bool:
cls,
goods_name: str,
goods_price: Optional[int] = None,
goods_description: Optional[str] = None,
goods_discount: Optional[float] = None,
goods_limit_time: Optional[int] = None,
daily_limit: Optional[int] = None,
is_passive: Optional[bool] = None,
icon: Optional[str] = None,
):
"""
说明:
更新商品信息
@ -106,37 +108,25 @@ class GoodsInfo(db.Model):
:param is_passive: 是否为被动
:param icon: 图标
"""
try:
query = (
await cls.query.where(cls.goods_name == goods_name)
.with_for_update()
.gino.first()
if goods := await cls.get_or_none(goods_name=goods_name):
await cls.update_or_create(
goods_name=goods_name,
defaults={
"goods_price": goods_price or goods.goods_price,
"goods_description": goods_description or goods.goods_description,
"goods_discount": goods_discount or goods.goods_discount,
"goods_limit_time": goods_limit_time
if goods_limit_time is not None
else goods.goods_limit_time,
"daily_limit": daily_limit
if daily_limit is not None
else goods.daily_limit,
"is_passive": is_passive
if is_passive is not None
else goods.is_passive,
"icon": icon or goods.icon,
},
)
if not query:
return False
await query.update(
goods_price=goods_price or query.goods_price,
goods_description=goods_description or query.goods_description,
goods_discount=goods_discount or query.goods_discount,
goods_limit_time=goods_limit_time if goods_limit_time is not None else query.goods_limit_time,
daily_limit=daily_limit if daily_limit is not None else query.daily_limit,
is_passive=is_passive if is_passive is not None else query.is_passive,
icon=icon or query.icon
).apply()
return True
except Exception as e:
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}{e}")
return False
@classmethod
async def get_goods_info(cls, goods_name: str) -> "GoodsInfo":
"""
说明:
获取商品对象
参数:
:param goods_name: 商品名称
"""
return await cls.query.where(cls.goods_name == goods_name).gino.first()
@classmethod
async def get_all_goods(cls) -> List["GoodsInfo"]:
@ -144,7 +134,7 @@ class GoodsInfo(db.Model):
说明:
获得全部有序商品对象
"""
query = await cls.query.gino.all()
query = await cls.all()
id_lst = [x.id for x in query]
goods_lst = []
for _ in range(len(query)):
@ -155,7 +145,7 @@ class GoodsInfo(db.Model):
@classmethod
async def add_user_daily_purchase(
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
cls, goods: "GoodsInfo", user_id_: int, group_id_: int, num: int = 1
):
"""
说明:
@ -166,19 +156,19 @@ class GoodsInfo(db.Model):
:param group_id: 群号
:param num: 数量
"""
user_id = str(user_id)
group_id = str(group_id)
user_id = str(user_id_)
group_id = str(group_id_)
if goods and goods.daily_limit and goods.daily_limit > 0:
if not goods.daily_purchase_limit.get(group_id):
goods.daily_purchase_limit[group_id] = {}
if not goods.daily_purchase_limit[group_id].get(user_id):
goods.daily_purchase_limit[group_id][user_id] = 0
goods.daily_purchase_limit[group_id][user_id] += num
await goods.update(daily_purchase_limit=goods.daily_purchase_limit).apply()
await goods.save(update_fields=["daily_purchase_limit"])
@classmethod
async def check_user_daily_purchase(
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
cls, goods: "GoodsInfo", user_id_: int, group_id_: int, num: int = 1
) -> Tuple[bool, int]:
"""
说明:
@ -189,8 +179,8 @@ class GoodsInfo(db.Model):
:param group_id: 群号
:param num: 数量
"""
user_id = str(user_id)
group_id = str(group_id)
user_id = str(user_id_)
group_id = str(group_id_)
if goods and goods.daily_limit > 0:
if (
not goods.daily_limit
@ -204,10 +194,3 @@ class GoodsInfo(db.Model):
goods.daily_limit - goods.daily_purchase_limit[group_id][user_id],
)
return False, 0
@classmethod
async def reset_daily_purchase(cls):
"""
重置每次次数限制
"""
await cls.update.values(daily_purchase_limit={}).gino.status()

View File

@ -1,111 +1,24 @@
from services.db_context import db
from services.log import logger
from typing import List, Optional
from tortoise import fields
class GroupInfo(db.Model):
__tablename__ = "group_info"
from services.db_context import Model
from services.log import logger
group_id = db.Column(db.BigInteger(), nullable=False, primary_key=True)
group_name = db.Column(db.Unicode(), nullable=False, default="")
max_member_count = db.Column(db.Integer(), nullable=False, default=0)
member_count = db.Column(db.Integer(), nullable=False, default=0)
group_flag = db.Column(db.Integer(), nullable=False, default=0)
_idx1 = db.Index("group_info_idx1", "group_id", unique=True)
class GroupInfo(Model):
@classmethod
async def get_group_info(cls, group_id: int) -> "GroupInfo":
"""
说明:
获取群信息
参数:
:param group_id: 群号
"""
query = cls.query.where(cls.group_id == group_id)
return await query.gino.first()
group_id = fields.BigIntField(pk=True)
"""群聊id"""
group_name = fields.TextField(default="")
"""群聊名称"""
max_member_count = fields.IntField(default=0)
"""最大人数"""
member_count = fields.IntField(default=0)
"""当前人数"""
group_flag: int = fields.IntField(default=0)
"""群认证标记"""
@classmethod
async def add_group_info(
cls,
group_id: int,
group_name: str,
max_member_count: int,
member_count: int,
group_flag: Optional[int] = None,
) -> bool:
"""
说明:
添加群信息
参数:
:param group_id: 群号
:param group_name: 群名称
:param max_member_count: 群员最大数量
:param member_count: 群员数量
:param group_flag: 群认证0为未认证1为认证
"""
try:
group = (
await cls.query.where(cls.group_id == group_id)
.with_for_update()
.gino.first()
)
if group:
await group.update(
group_name=group_name,
max_member_count=max_member_count,
member_count=member_count,
).apply()
if group_flag is not None:
await group.update(group_flag=group_flag).apply()
else:
await cls.create(
group_id=group_id,
group_name=group_name,
max_member_count=max_member_count,
member_count=member_count,
group_flag=group_flag,
)
return True
except Exception as e:
logger.info(f"GroupInfo 调用 add_group_info 发生错误 {type(e)}{e}")
return False
@classmethod
async def delete_group_info(cls, group_id: int):
"""
说明:
删除群信息
参数:
:param group_id: 群号
"""
await cls.delete.where(cls.group_id == group_id).gino.status()
@classmethod
async def get_all_group(cls) -> List["GroupInfo"]:
"""
说明:
获取所有群对象
"""
query = await cls.query.gino.all()
return query
@classmethod
async def set_group_flag(cls, group_id: int, group_flag: int) -> bool:
"""
设置群认证
:param group_id: 群号
:param group_flag: 群认证0为未认证1为认证
"""
group = (
await cls.query.where(cls.group_id == group_id)
.with_for_update()
.gino.first()
)
if group:
if group.group_flag != group_flag:
await group.update(
group_flag=group_flag,
).apply()
return True
return False
class Meta:
table = "group_info"
table_description = "群聊信息表"

View File

@ -1,116 +1,48 @@
from datetime import datetime
from typing import List, Optional, Set
from tortoise import fields
from configs.config import Config
from services.db_context import db
from typing import List, Optional
from services.db_context import Model
class GroupInfoUser(db.Model):
__tablename__ = "group_info_users"
class GroupInfoUser(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
user_name = db.Column(db.Unicode(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
user_join_time = db.Column(db.DateTime(), nullable=False)
nickname = db.Column(db.Unicode())
uid = db.Column(db.BigInteger())
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
user_name = fields.CharField(255, default="")
"""用户昵称"""
group_id = fields.BigIntField()
"""群聊id"""
user_join_time = fields.DatetimeField(null=True)
"""用户入群时间"""
nickname = fields.CharField(255, null=True)
"""群聊昵称"""
uid = fields.BigIntField(null=True)
"""用户uid"""
_idx1 = db.Index("info_group_users_idx1", "user_qq", "group_id", unique=True)
class Meta:
table = "group_info_users"
table_description = "群员信息数据表"
unique_together = ("user_qq", "group_id")
@classmethod
async def add_member_info(
cls,
user_qq: int,
group_id: int,
user_name: str,
user_join_time: datetime,
uid: Optional[int] = None,
) -> bool:
"""
说明:
添加群内用户信息
参数:
:param user_qq: qq号
:param group_id: 群号
:param user_name: 用户名称
:param user_join_time: 入群时间
:param uid: 用户唯一 id自动生成
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
try:
if not await query.gino.first():
await cls.create(
user_qq=user_qq,
user_name=user_name,
group_id=group_id,
user_join_time=user_join_time,
uid=uid
)
return True
except Exception:
return False
@classmethod
async def get_member_info(
cls, user_qq: int, group_id: int
) -> "GroupInfoUser":
"""
说明:
查询群员信息
参数:
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
return await query.gino.first()
@classmethod
async def delete_member_info(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
删除群员信息
参数:
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
query = query.with_for_update()
user = await query.gino.first()
try:
if user is None:
return True
else:
await cls.delete.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
).gino.status()
return True
except Exception:
return False
@classmethod
async def get_group_member_id_list(cls, group_id: int) -> List[int]:
async def get_group_member_id_list(cls, group_id: int) -> Set[int]:
"""
说明:
获取该群所有用户qq
参数:
:param group_id: 群号
"""
member_list = []
query = cls.query.where((cls.group_id == group_id))
for user in await query.gino.all():
member_list.append(user.user_qq)
return member_list
return set(
await cls.filter(group_id=group_id).values_list("user_qq", flat=True)
)
@classmethod
async def set_group_member_nickname(
cls, user_qq: int, group_id: int, nickname: str
) -> bool:
async def set_user_nickname(cls, user_qq: int, group_id: int, nickname: str):
"""
说明:
设置群员在该群内的昵称
@ -119,14 +51,11 @@ class GroupInfoUser(db.Model):
:param group_id: 群号
:param nickname: 昵称
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
await cls.update_or_create(
user_qq=user_qq,
group_id=group_id,
defaults={"nickname": nickname},
)
user = await query.with_for_update().gino.first()
if user:
await user.update(nickname=nickname).apply()
return True
return False
@classmethod
async def get_user_all_group(cls, user_qq: int) -> List[int]:
@ -136,13 +65,12 @@ class GroupInfoUser(db.Model):
参数:
:param user_qq: 用户qq
"""
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
if query:
query = [x.group_id for x in query]
return query
return list(
await cls.filter(user_qq=user_qq).values_list("group_id", flat=True)
)
@classmethod
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
async def get_user_nickname(cls, user_qq: int, group_id: int) -> str:
"""
说明:
获取用户在该群的昵称
@ -150,46 +78,34 @@ class GroupInfoUser(db.Model):
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
user = await query.gino.first()
if user:
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
if user.nickname:
_tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
if black_word:
nickname = ""
if black_word := Config.get_config("nickname", "BLACK_WORD"):
for x in user.nickname:
_tmp += "*" if x in black_word else x
return _tmp
nickname += "*" if x in black_word else x
return nickname
return user.nickname
return ""
@classmethod
async def get_group_member_uid(cls, user_qq: int, group_id: int) -> Optional[str]:
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
user = await query.gino.first()
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.group_id == 114514)).with_for_update()
_max_uid_user = await _max_uid.gino.first()
async def get_group_member_uid(cls, user_qq: int, group_id: int) -> Optional[int]:
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
_max_uid_user, _ = await cls.get_or_create(user_qq=114514, group_id=114514)
_max_uid = _max_uid_user.uid
if not user or not user.uid:
all_user = await cls.query.where(cls.user_qq == user_qq).gino.all()
if not user.uid:
all_user = await cls.filter(user_qq=user_qq).all()
for x in all_user:
if x.uid:
return x.uid
else:
if not user:
await GroupInfoUser.add_member_info(user_qq, group_id, '', datetime.min)
user = await cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
).gino.first()
await user.update(
uid=_max_uid + 1,
).apply()
await _max_uid_user.update(
uid=_max_uid + 1,
).apply()
return user.uid if user and user.uid else None
user.uid = _max_uid + 1
_max_uid_user.uid = _max_uid + 1
await cls.bulk_update([user, _max_uid_user], ["uid"])
return user.uid
@classmethod
async def _run_script(cls):
await cls.raw(
"alter table group_info_users alter user_join_time drop not null;"
)
"""允许 user_join_time 为空"""

View File

@ -1,18 +1,25 @@
from asyncpg import UniqueViolationError
from tortoise import fields
from services.db_context import db
from services.db_context import Model
class LevelUser(db.Model):
__tablename__ = "level_users"
class LevelUser(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
user_level = db.Column(db.BigInteger(), nullable=False)
group_flag = db.Column(db.Integer(), nullable=False, default=0)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
user_level = fields.BigIntField()
"""用户权限等级"""
group_flag = fields.IntField(default=0)
"""特殊标记,是否随群管理员变更而设置权限"""
_idx1 = db.Index("level_group_users_idx1", "user_qq", "group_id", unique=True)
class Meta:
table = "level_users"
table_description = "用户权限数据库"
unique_together = ("user_qq", "group_id")
@classmethod
async def get_user_level(cls, user_qq: int, group_id: int) -> int:
@ -23,17 +30,14 @@ class LevelUser(db.Model):
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first()
if user:
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
return user.user_level
else:
return -1
return -1
@classmethod
async def set_level(
cls, user_qq: int, group_id: int, level: int, group_flag: int = 0
) -> bool:
):
"""
说明:
设置用户在群内的权限
@ -43,23 +47,11 @@ class LevelUser(db.Model):
:param level: 权限等级
:param group_flag: 是否被自动更新刷新权限 01
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
try:
if not user:
await cls.create(
user_qq=user_qq,
group_id=group_id,
user_level=level,
group_flag=group_flag,
)
return True
else:
await user.update(user_level=level, group_flag=group_flag).apply()
return False
except UniqueViolationError:
return False
await cls.update_or_create(
user_qq=user_qq,
group_id=group_id,
defaults={"user_level": level, "group_flag": group_flag},
)
@classmethod
async def delete_level(cls, user_qq: int, group_id: int) -> bool:
@ -70,14 +62,10 @@ class LevelUser(db.Model):
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
if user is None:
return False
else:
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
await user.delete()
return True
return False
@classmethod
async def check_level(cls, user_qq: int, group_id: int, level: int) -> bool:
@ -89,25 +77,14 @@ class LevelUser(db.Model):
:param group_id: 群号
:param level: 权限等级
"""
if group_id != 0:
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
user = await query.gino.first()
if user is None:
return False
user_level = user.user_level
if group_id:
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
return user.user_level > level
else:
query = cls.query.where(cls.user_qq == user_qq)
highest_level = 0
for user in await query.gino.all():
if user.user_level > highest_level:
highest_level = user.user_level
user_level = highest_level
if user_level >= level:
return True
else:
return False
user_list = await cls.filter(user_qq=user_qq).all()
user = max(user_list, key=lambda x: x.user_level)
return user.user_level > level
return False
@classmethod
async def is_group_flag(cls, user_qq: int, group_id: int) -> bool:
@ -118,12 +95,6 @@ class LevelUser(db.Model):
:param user_qq: qq号
:param group_id: 群号
"""
user = await cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
).gino.first()
if not user:
return False
if user.group_flag == 1:
return True
else:
return False
if user := await cls.get_or_none(user_qq=user_qq, group_id=group_id):
return user.group_flag == 1
return False

View File

@ -1,99 +1,78 @@
from datetime import datetime
from typing import List
from services.db_context import db
from typing import Dict, List, Literal, Optional, Tuple, Union
from tortoise import fields
from services.db_context import Model
class SignGroupUser(db.Model):
__tablename__ = "sign_group_users"
class SignGroupUser(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
checkin_count = db.Column(db.Integer(), nullable=False)
checkin_time_last = db.Column(db.DateTime(timezone=True), nullable=False)
impression = db.Column(db.Numeric(scale=3, asdecimal=False), nullable=False)
add_probability = db.Column(
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
)
specify_probability = db.Column(
db.Numeric(scale=3, asdecimal=False), nullable=False, default=0
)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
checkin_count = fields.IntField(default=0)
"""签到次数"""
checkin_time_last = fields.DatetimeField(auto_now=True)
"""最后签到时间"""
impression = fields.DecimalField(10, 3, default=0)
"""好感度"""
add_probability = fields.DecimalField(10, 3, default=0)
"""双倍签到增加概率"""
specify_probability = fields.DecimalField(10, 3, default=0)
"""使用指定双倍概率"""
# specify_probability = fields.DecimalField(10, 3, default=0)
_idx1 = db.Index("sign_group_users_idx1", "user_qq", "group_id", unique=True)
class Meta:
table = "sign_group_users"
table_description = "群员签到数据表"
unique_together = ("user_qq", "group_id")
@classmethod
async def ensure(
cls, user_qq: int, group_id: int, for_update: bool = False
) -> "SignGroupUser":
"""
说明:
获取签到用户
参数:
:param user_qq: 用户qq
:param group_id: 所在群聊
:param for_update: 是否存在修改数据
"""
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
if for_update:
query = query.with_for_update()
user = await query.gino.first()
return user or await cls.create(
user_qq=user_qq,
group_id=group_id,
checkin_count=0,
checkin_time_last=datetime.min, # 从未签到过
impression=0,
)
@classmethod
async def get_user_all_data(cls, user_qq: int) -> List["SignGroupUser"]:
"""
说明:
获取某用户所有数据
参数:
:param user_qq: 用户qq
"""
query = cls.query.where(cls.user_qq == user_qq)
query = query.with_for_update()
return await query.gino.all()
@classmethod
async def sign(cls, user: "SignGroupUser", impression: float, checkin_time_last: datetime):
async def sign(cls, user: "SignGroupUser", impression: float):
"""
说明:
签到
说明:
:param user: 用户
:param impression: 增加的好感度
:param checkin_time_last: 签到时间
"""
await user.update(
checkin_count=user.checkin_count + 1,
checkin_time_last=checkin_time_last,
impression=user.impression + impression,
add_probability=0,
specify_probability=0,
).apply()
user.checkin_count = user.checkin_count + 1
user.add_probability = 0
user.specify_probability = 0
user.impression = float(user.impression) + impression
await user.save(
update_fields=[
"checkin_count",
"add_probability",
"specify_probability",
"impression",
]
)
@classmethod
async def get_all_impression(cls, group_id: int) -> "list, list, list":
async def get_all_impression(
cls, group_id: Optional[int]
) -> Tuple[List[int], List[int], List[float]]:
"""
说明:
获取该群所有用户 id 及对应 好感度
参数:
:param group_id: 群号
"""
impression_list = []
user_qq_list = []
user_group = []
if group_id:
query = cls.query.where(cls.group_id == group_id)
query = cls.filter(group_id=group_id)
else:
query = cls.query
for user in await query.gino.all():
impression_list.append(user.impression)
user_qq_list.append(user.user_qq)
user_group.append(user.group_id)
return user_qq_list, impression_list, user_group
query = cls
value_list = await query.all().values_list("user_qq", "group_id", "impression") # type: ignore
qq_list = []
group_list = []
impression_list = []
for value in value_list:
qq_list.append(value[0])
group_list.append(value[1])
impression_list.append(float(value[2]))
return qq_list, impression_list, group_list

View File

@ -1,59 +1,29 @@
from datetime import datetime
from services.db_context import db
from tortoise import fields
from services.db_context import Model
class UserShopGoldLog(db.Model):
__tablename__ = "user_shop_gold_log"
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
type = db.Column(db.Integer(), nullable=False) # 0: 购买1: 使用2: 插件
name = db.Column(db.String())
spend_gold = db.Column(db.Integer(), nullable=False)
num = db.Column(db.Integer(), nullable=False)
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
class UserShopGoldLog(Model):
@classmethod
async def add_shop_log(
cls,
user_qq: int,
group_id: int,
type_: int,
name: str,
num: int,
spend_gold: int = 0,
):
"""
说明:
添加商店购买或使用日志
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param type_: 类型
:param name: 商品名称
:param num: 数量
:param spend_gold: 花费金币
"""
await cls.create(
user_qq=user_qq,
group_id=group_id,
type=type_,
name=name,
num=num,
spend_gold=spend_gold,
create_time=datetime.now(),
)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
type = fields.IntField()
"""金币使用类型 0: 购买, 1: 使用, 2: 插件"""
name = fields.CharField(255)
"""商品/插件 名称"""
spend_gold = fields.IntField(default=0)
"""花费金币"""
num = fields.IntField()
"""数量"""
create_time = fields.DatetimeField(auto_now_add=True)
"""创建时间"""
@classmethod
async def get_user_log(cls, user_qq: int, group_id: int) -> "UserShopGoldLog":
"""
说明:
获取用户日志
参数:
:param user_qq: qq号
:param group_id: 所在群号
"""
return await cls.query.where(
(cls.user_qq == user_qq) & (cls.group_qq == group_id)
).first()
class Meta:
table = "user_shop_gold_log"
table_description = "金币使用日志表"

View File

@ -1,20 +1,20 @@
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from nonebot import on_command
from nonebot.rule import to_me
import os
import random
from nonebot import on_command, on_keyword
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.utils import FreqLimiter
from configs.config import NICKNAME
import random
from nonebot import on_keyword
import os
from nonebot.rule import to_me
from configs.config import NICKNAME
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from utils.utils import FreqLimiter
__zx_plugin_name__ = "基本设置 [Hidden]"
__plugin_usage__ = "用法: 无"
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_author__ = "HibiKier"
_flmt = FreqLimiter(300)
@ -29,7 +29,7 @@ async def _(event: GroupMessageEvent):
return
_flmt.start_cd(event.group_id)
await config_play_game.finish(
image(random.choice(os.listdir(IMAGE_PATH / "dayouxi")), "dayouxi")
image(IMAGE_PATH / random.choice(os.listdir(IMAGE_PATH / "dayouxi")))
)
@ -40,14 +40,14 @@ self_introduction = on_command(
@self_introduction.handle()
async def _():
if NICKNAME.find('真寻') != -1:
if NICKNAME.find("真寻") != -1:
result = (
"我叫绪山真寻\n"
"你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n"
"年龄的话我还是个**岁初中生(至少现在是)\n"
"身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n"
"我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n"
"最好的朋友是椛!\n" + image("zhenxun")
"最好的朋友是椛!\n" + image("zhenxun.jpg")
)
await self_introduction.finish(result)
@ -57,5 +57,4 @@ my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True)
@my_wife.handle()
async def _():
await my_wife.finish(image("laopo.jpg", "other"))
await my_wife.finish(image(IMAGE_PATH / "other" / "laopo.jpg"))

View File

@ -1,18 +1,14 @@
from nonebot import on_message
from nonebot.adapters.onebot.v11 import (
Bot,
GroupMessageEvent,
Message,
MessageEvent,
)
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.rule import to_me
from configs.config import NICKNAME, Config
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.utils import get_message_img, get_message_text
from .data_source import get_chat_result, hello, no_result
from configs.config import NICKNAME, Config
__zx_plugin_name__ = "AI"
__plugin_usage__ = f"""
@ -61,11 +57,9 @@ async def _(bot: Bot, event: MessageEvent):
await ai.finish(hello())
img = img[0] if img else ""
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
nickname = await GroupInfoUser.get_user_nickname(event.user_id, event.group_id)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
nickname = await FriendUser.get_user_nickname(event.user_id)
if not nickname:
if isinstance(event, GroupMessageEvent):
nickname = event.sender.card or event.sender.nickname

View File

@ -1,11 +1,13 @@
import os
import random
import re
from utils.http_utils import AsyncHttpx
from configs.path_config import IMAGE_PATH, DATA_PATH
from configs.config import NICKNAME, Config
from configs.path_config import DATA_PATH, IMAGE_PATH
from services.log import logger
from utils.message_builder import image, face
from configs.config import Config, NICKNAME
from utils.http_utils import AsyncHttpx
from utils.message_builder import face, image
from .utils import ai_message_manager
try:
@ -124,7 +126,9 @@ async def xie_ai(text: str) -> str:
:param text: 问题
:return: 青云可回复
"""
res = await AsyncHttpx.get(f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}")
res = await AsyncHttpx.get(
f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}"
)
content = ""
try:
data = json.loads(res.text)
@ -176,9 +180,9 @@ def hello() -> str:
)
img = random.choice(os.listdir(IMAGE_PATH / "zai"))
if img[-4:] == ".gif":
result += image(img, "zai")
result += image(IMAGE_PATH / "zai" / img)
else:
result += image(img, "zai")
result += image(IMAGE_PATH / "zai" / img)
return result
@ -187,17 +191,16 @@ def no_result() -> str:
"""
没有回答时的回复
"""
return (
random.choice(
[
"你在说啥子?",
f"纯洁的{NICKNAME}没听懂",
"下次再告诉你(下次一定)",
"你觉得我听懂了吗?嗯?",
"我!不!知!道!",
]
)
+ image(random.choice(os.listdir(IMAGE_PATH / "noresult")), "noresult")
return random.choice(
[
"你在说啥子?",
f"纯洁的{NICKNAME}没听懂",
"下次再告诉你(下次一定)",
"你觉得我听懂了吗?嗯?",
"我!不!知!道!",
]
) + image(
IMAGE_PATH / "noresult" / random.choice(os.listdir(IMAGE_PATH / "noresult"))
)

View File

@ -1,28 +1,29 @@
from nonebot import on_command, on_regex
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from typing import Any, Optional, Tuple
import nonebot
from nonebot import Driver, on_command, on_regex
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import ArgStr, CommandArg, RegexGroup
from nonebot.typing import T_State
from configs.config import Config
from models.level_user import LevelUser
from services.log import logger
from utils.image_utils import text2image
from utils.manager import group_manager
from utils.message_builder import image
from utils.utils import get_bot, is_number, scheduler
from .data_source import (
BilibiliSub,
SubManager,
add_live_sub,
delete_sub,
add_up_sub,
add_season_sub,
add_up_sub,
delete_sub,
get_media_id,
get_sub_status,
SubManager,
BilibiliSub,
)
from models.level_user import LevelUser
from utils.manager import group_manager
from configs.config import Config
from utils.utils import is_number, scheduler, get_bot
from typing import Optional, Tuple, Any
from services.log import logger
from nonebot import Driver
from nonebot.params import CommandArg, ArgStr, RegexGroup
import nonebot
__zx_plugin_name__ = "B站订阅"
__plugin_usage__ = """
@ -168,20 +169,20 @@ async def _(
sub_user: str = ArgStr("sub_user"),
):
if sub_type in ["主播", "直播"]:
result = await BilibiliSub.delete_bilibili_sub(int(id_),sub_user,"live")
result = await BilibiliSub.delete_bilibili_sub(int(id_), sub_user, "live")
elif sub_type.lower() in ["up", "用户"]:
result = await BilibiliSub.delete_bilibili_sub(int(id_),sub_user,"up")
else: result = await BilibiliSub.delete_bilibili_sub(int(id_),sub_user)
result = await BilibiliSub.delete_bilibili_sub(int(id_), sub_user, "up")
else:
result = await BilibiliSub.delete_bilibili_sub(int(id_), sub_user)
if result:
await del_sub.send(f"删除订阅id{id_} 成功...")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除订阅 {id_}"
)
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除订阅 {id_}"
)
else:
await del_sub.send(f"删除订阅id{id_} 失败...")
@show_sub_info.handle()
@ -190,7 +191,7 @@ async def _(event: MessageEvent):
id_ = f"{event.group_id}"
else:
id_ = f"{event.user_id}"
data = await BilibiliSub.get_sub_data(id_)
data = await BilibiliSub.filter(sub_users__contains=id_).all()
live_rst = ""
up_rst = ""
season_rst = ""
@ -217,11 +218,9 @@ async def _(event: MessageEvent):
)
await show_sub_info.send(
image(
b64=(
await text2image(
live_rst + up_rst + season_rst, padding=10, color="#f9f6f2"
)
).pic2bs4()
await text2image(
live_rst + up_rst + season_rst, padding=10, color="#f9f6f2"
)
)
)
@ -277,7 +276,9 @@ async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
):
rst = "[CQ:at,qq=all]\n" + rst
if group_manager.get_plugin_status("bilibili_sub", group_id):
await bot.send_group_msg(group_id=group_id, message=Message(rst))
await bot.send_group_msg(
group_id=group_id, message=Message(rst)
)
else:
await bot.send_private_msg(user_id=int(x), message=Message(rst))
except Exception as e:

View File

@ -1,34 +1,33 @@
from bilireq.exceptions import ResponseCodeError
from nonebot.adapters.onebot.v11 import MessageSegment
from utils.manager import resources_manager
import random
from asyncio.exceptions import TimeoutError
from datetime import datetime
from typing import Optional, Tuple
from utils.utils import get_bot
from .model import BilibiliSub
from bilireq.live import get_room_info_by_id
from .utils import get_meta, get_user_card
from utils.message_builder import image
from bilireq.user import get_videos
# from .utils import get_videos
from bilireq import dynamic
from typing import Optional, Tuple
from configs.path_config import IMAGE_PATH
from datetime import datetime
from utils.browser import get_browser
from services.db_context import db
from bilireq.exceptions import ResponseCodeError
from bilireq.live import get_room_info_by_id
from bilireq.user import get_videos
from nonebot.adapters.onebot.v11 import MessageSegment
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
import random
from utils.browser import get_browser
from utils.http_utils import AsyncHttpx, AsyncPlaywright
from utils.manager import resources_manager
from utils.message_builder import image
from utils.utils import get_bot
from .model import BilibiliSub
from .utils import get_meta, get_user_card
SEARCH_URL = "https://api.bilibili.com/x/web-interface/search/all/v2"
DYNAMIC_PATH = IMAGE_PATH / "bilibili_sub" / "dynamic"
DYNAMIC_PATH.mkdir(exist_ok=True, parents=True)
bilibili_search_url = "https://api.bilibili.com/x/web-interface/search/all/v2"
dynamic_path = IMAGE_PATH / "bilibili_sub" / "dynamic"
dynamic_path.mkdir(exist_ok=True, parents=True)
resources_manager.add_temp_dir(dynamic_path)
resources_manager.add_temp_dir(DYNAMIC_PATH)
async def add_live_sub(live_id: int, sub_user: str) -> str:
@ -49,7 +48,7 @@ async def add_live_sub(live_id: int, sub_user: str) -> str:
short_id = live_info["short_id"]
title = live_info["title"]
live_status = live_info["live_status"]
if await BilibiliSub.add_bilibili_sub(
if await BilibiliSub.sub_handle(
room_id,
"live",
sub_user,
@ -58,14 +57,14 @@ async def add_live_sub(live_id: int, sub_user: str) -> str:
live_status=live_status,
):
await _get_up_status(room_id)
uname = (await BilibiliSub.get_sub(room_id)).uname
uname = (await BilibiliSub.get_or_none(sub_id=room_id)).uname
return (
"已成功订阅主播:\n"
f"\ttitle{title}\n"
f"\tname {uname}\n"
f"\tlive_id{room_id}\n"
f"\tuid{uid}"
)
)
else:
return "添加订阅失败..."
except Exception as e:
@ -80,35 +79,34 @@ async def add_up_sub(uid: int, sub_user: str) -> str:
:param sub_user: 订阅用户
"""
try:
async with db.transaction():
try:
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await get_user_card(uid)
except ResponseCodeError:
return f"未找到UpId{uid} 的信息请检查Id是否正确"
uname = user_info["name"]
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
dynamic_upload_time = 0
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(uid)
latest_video_created = 0
if video_info["list"].get("vlist"):
latest_video_created = video_info["list"]["vlist"][0]["created"]
if await BilibiliSub.add_bilibili_sub(
uid,
"up",
sub_user,
uid=uid,
uname=uname,
dynamic_upload_time=dynamic_upload_time,
latest_video_created=latest_video_created,
):
return "已成功订阅UP\n" f"\tname: {uname}\n" f"\tuid{uid}"
else:
return "添加订阅失败..."
try:
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await get_user_card(uid)
except ResponseCodeError:
return f"未找到UpId{uid} 的信息请检查Id是否正确"
uname = user_info["name"]
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
dynamic_upload_time = 0
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(uid)
latest_video_created = 0
if video_info["list"].get("vlist"):
latest_video_created = video_info["list"]["vlist"][0]["created"]
if await BilibiliSub.sub_handle(
uid,
"up",
sub_user,
uid=uid,
uname=uname,
dynamic_upload_time=dynamic_upload_time,
latest_video_created=latest_video_created,
):
return "已成功订阅UP\n" f"\tname: {uname}\n" f"\tuid{uid}"
else:
return "添加订阅失败..."
except Exception as e:
logger.error(f"订阅Up uid{uid} 发生了错误 {type(e)}{e}")
return "添加订阅失败..."
@ -121,30 +119,29 @@ async def add_season_sub(media_id: int, sub_user: str) -> str:
:param sub_user: 订阅用户
"""
try:
async with db.transaction():
try:
"""bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
season_info = await get_meta(media_id)
except ResponseCodeError:
return f"未找到media_id{media_id} 的信息请检查Id是否正确"
season_id = season_info["media"]["season_id"]
season_current_episode = season_info["media"]["new_ep"]["index"]
season_name = season_info["media"]["title"]
if await BilibiliSub.add_bilibili_sub(
media_id,
"season",
sub_user,
season_name=season_name,
season_id=season_id,
season_current_episode=season_current_episode,
):
return (
"已成功订阅番剧:\n"
f"\ttitle: {season_name}\n"
f"\tcurrent_episode: {season_current_episode}"
)
else:
return "添加订阅失败..."
try:
"""bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
season_info = await get_meta(media_id)
except ResponseCodeError:
return f"未找到media_id{media_id} 的信息请检查Id是否正确"
season_id = season_info["media"]["season_id"]
season_current_episode = season_info["media"]["new_ep"]["index"]
season_name = season_info["media"]["title"]
if await BilibiliSub.sub_handle(
media_id,
"season",
sub_user,
season_name=season_name,
season_id=season_id,
season_current_episode=season_current_episode,
):
return (
"已成功订阅番剧:\n"
f"\ttitle: {season_name}\n"
f"\tcurrent_episode: {season_current_episode}"
)
else:
return "添加订阅失败..."
except Exception as e:
logger.error(f"订阅番剧 media_id{media_id} 发生了错误 {type(e)}{e}")
return "添加订阅失败..."
@ -171,9 +168,7 @@ async def get_media_id(keyword: str) -> dict:
for _ in range(3):
try:
_season_data = {}
response = await AsyncHttpx.get(
bilibili_search_url, params=params, timeout=5
)
response = await AsyncHttpx.get(SEARCH_URL, params=params, timeout=5)
if response.status_code == 200:
data = response.json()
if data.get("data"):
@ -227,9 +222,9 @@ async def _get_live_status(id_: int) -> Optional[str]:
room_id = live_info["room_id"]
live_status = live_info["live_status"]
cover = live_info["user_cover"]
sub = await BilibiliSub.get_sub(id_)
sub = await BilibiliSub.get_or_none(sub_id=id_)
if sub.live_status != live_status:
await BilibiliSub.update_sub_info(id_, live_status=live_status)
await BilibiliSub.sub_handle(id_, live_status=live_status)
if sub.live_status in [0, 2] and live_status == 1:
return (
f""
@ -247,7 +242,7 @@ async def _get_up_status(id_: int) -> Optional[str]:
:param id_: 订阅 id
:return:
"""
_user = await BilibiliSub.get_sub(id_)
_user = await BilibiliSub.get_or_none(sub_id=id_)
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await get_user_card(_user.uid)
uname = user_info["name"]
@ -257,14 +252,14 @@ async def _get_up_status(id_: int) -> Optional[str]:
video = None
dividing_line = "\n-------------\n"
if _user.uname != uname:
await BilibiliSub.update_sub_info(id_, uname=uname)
await BilibiliSub.sub_handle(id_, uname=uname)
dynamic_img, dynamic_upload_time, link = await get_user_dynamic(_user.uid, _user)
if video_info["list"].get("vlist"):
video = video_info["list"]["vlist"][0]
latest_video_created = video["created"]
rst = ""
if dynamic_img:
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
await BilibiliSub.sub_handle(id_, dynamic_upload_time=dynamic_upload_time)
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n{link}"
if (
latest_video_created
@ -273,9 +268,7 @@ async def _get_up_status(id_: int) -> Optional[str]:
and _user.latest_video_created < latest_video_created
):
rst = rst + dividing_line if rst else rst
await BilibiliSub.update_sub_info(
id_, latest_video_created=latest_video_created
)
await BilibiliSub.sub_handle(id_, latest_video_created=latest_video_created)
rst += (
f'{image(video["pic"])}\n'
f"{uname} 投稿了新视频啦\n"
@ -295,10 +288,10 @@ async def _get_season_status(id_) -> Optional[str]:
"""bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
season_info = await get_meta(id_)
title = season_info["media"]["title"]
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode
_idx = (await BilibiliSub.get_or_none(sub_id=id_)).season_current_episode
new_ep = season_info["media"]["new_ep"]["index"]
if new_ep != _idx:
await BilibiliSub.update_sub_info(
await BilibiliSub.sub_handle(
id_, season_current_episode=new_ep, season_update_time=datetime.now()
)
return (
@ -320,55 +313,22 @@ async def get_user_dynamic(
"""
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
browser = await get_browser()
if dynamic_info.get("cards") and browser:
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
dynamic_id = dynamic_info["cards"][0]["desc"]["dynamic_id"]
if local_user.dynamic_upload_time < dynamic_upload_time:
context = await browser.new_context()
page = await context.new_page()
try:
await page.goto(
f"https://t.bilibili.com/{dynamic_id}",
wait_until="networkidle",
timeout=10000,
)
# await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s
# 删除置顶
# await page.evaluate(
# """
# xs = document.getElementsByClassName('bili-dyn-item__tag');
# for (x of xs) {
# x.parentNode.parentNode.remove();
# }
# """
# )
# async with page.expect_popup() as popup_info:
# await page.locator(".bili-rich-text__content").click()
# details_page = await popup_info.value
await page.set_viewport_size(
{"width": 2560, "height": 1080, "timeout": 10000 * 20}
)
await page.wait_for_selector(".bili-dyn-item__main")
card = page.locator(".bili-dyn-item__main")
await card.wait_for()
await card.screenshot(
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
)
except Exception as e:
logger.error(f"B站订阅获取用户动态 发送错误 {type(e)}{e}")
finally:
await context.close()
await page.close()
return (
image(
f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
"bilibili_sub/dynamic",
),
dynamic_upload_time,
f"https://t.bilibili.com/{dynamic_id}"
image = await AsyncPlaywright.screenshot(
f"https://t.bilibili.com/{dynamic_id}",
DYNAMIC_PATH / f"sub_{local_user.sub_id}.png",
".bili-dyn-item__main",
wait_until="networkidle",
)
return None, 0, ''
return (
image,
dynamic_upload_time,
f"https://t.bilibili.com/{dynamic_id}",
)
return None, 0, ""
class SubManager:

View File

@ -1,43 +1,58 @@
from services.log import logger
from services.db_context import db
from datetime import datetime
from typing import Optional, List
from typing import List, Optional, Tuple
from tortoise import fields
from services.db_context import Model
from services.log import logger
class BilibiliSub(db.Model):
__tablename__ = "bilibili_sub"
class BilibiliSub(Model):
id = db.Column(db.Integer(), primary_key=True)
sub_id = db.Column(db.Integer(), nullable=False)
sub_type = db.Column(db.String(), nullable=False)
# 订阅用户
sub_users = db.Column(db.String(), nullable=False)
# 直播
live_short_id = db.Column(db.Integer())
live_status = db.Column(db.Integer)
# 主播/UP
uid = db.Column(db.BigInteger())
uname = db.Column(db.String())
latest_video_created = db.Column(db.BigInteger()) # 视频上传时间
dynamic_upload_time = db.Column(db.BigInteger(), default=0) # 动态发布时间
# 番剧
season_name = db.Column(db.String())
season_id = db.Column(db.Integer())
season_current_episode = db.Column(db.String())
season_update_time = db.Column(db.DateTime())
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
sub_id = fields.IntField()
"""订阅id"""
sub_type = fields.CharField(255)
"""订阅类型"""
sub_users = fields.TextField()
"""订阅用户"""
live_short_id = fields.IntField(null=True)
"""直播短id"""
live_status = fields.IntField(null=True)
"""直播状态 0: 停播 1: 直播"""
uid = fields.BigIntField(null=True)
"""主播/UP UID"""
uname = fields.CharField(255, null=True)
"""主播/UP 名称"""
latest_video_created = fields.BigIntField(null=True)
"""最后视频上传时间"""
dynamic_upload_time = fields.BigIntField(null=True, default=0)
"""动态发布时间"""
season_name = fields.CharField(255, null=True)
"""番剧名称"""
season_id = fields.IntField(null=True)
"""番剧id"""
season_current_episode = fields.CharField(255, null=True)
"""番剧最新集数"""
season_update_time = fields.DateField(null=True)
"""番剧更新日期"""
_idx1 = db.Index("bilibili_sub_idx1", "sub_id", "sub_type", unique=True)
class Meta:
table = "bilibili_sub"
table_description = "B站订阅数据表"
unique_together = ("sub_id", "sub_type")
@classmethod
async def add_bilibili_sub(
async def sub_handle(
cls,
sub_id: int,
sub_type: str,
sub_user: str,
sub_type: Optional[str] = None,
sub_user: str = "",
*,
live_short_id: Optional[int] = None,
live_status: Optional[int] = None,
dynamic_upload_time: Optional[int] = None,
dynamic_upload_time: int = 0,
uid: Optional[int] = None,
uname: Optional[str] = None,
latest_video_created: Optional[int] = None,
@ -64,50 +79,60 @@ class BilibiliSub(db.Model):
:param season_current_episode: 番剧最新集数
:param season_update_time: 番剧更新时间
"""
try:
query = (
await cls.query.where( (cls.sub_id == sub_id) & (cls.sub_type == sub_type) )
.with_for_update()
.gino.first()
)
# try:
data = {
"sub_type": sub_type,
"sub_user": sub_user,
"live_short_id": live_short_id,
"live_status": live_status,
"dynamic_upload_time": dynamic_upload_time,
"uid": uid,
"uname": uname,
"latest_video_created": latest_video_created,
"season_name": season_name,
"season_id": season_id,
"season_current_episode": season_current_episode,
"season_update_time": season_update_time,
}
if sub_user:
sub_user = sub_user if sub_user[-1] == "," else f"{sub_user},"
if query:
if sub_user not in query.sub_users:
sub_users = query.sub_users + sub_user
await query.update(sub_users=sub_users).apply()
else:
sub = await cls.create(
sub_id=sub_id, sub_type=sub_type, sub_users=sub_user
)
await sub.update(
live_short_id=live_short_id
if live_short_id
else sub.live_short_id,
live_status=live_status if live_status else sub.live_status,
dynamic_upload_time=dynamic_upload_time
if dynamic_upload_time
else sub.dynamic_upload_time,
uid=uid if uid else sub.uid,
uname=uname if uname else sub.uname,
latest_video_created=latest_video_created
if latest_video_created
else sub.latest_video_created,
season_update_time=season_update_time
if season_update_time
else sub.season_update_time,
season_current_episode=season_current_episode
if season_current_episode
else sub.season_current_episode,
season_id=season_id if season_id else sub.season_id,
season_name=season_name if season_name else sub.season_name,
).apply()
return True
except Exception as e:
logger.info(f"bilibili_sub 添加订阅错误 {type(e)}: {e}")
return False
sub = None
if sub_type:
sub = await cls.get_or_none(sub_id=sub_id, sub_type=sub_type)
else:
sub = await cls.get_or_none(sub_id=sub_id)
if sub:
sub_users = sub.sub_users + sub_user
data["sub_type"] = sub_type or sub.sub_type
data["sub_user"] = sub_users
data["live_short_id"] = live_short_id or sub.live_short_id
data["live_status"] = (
live_status if live_status is not None else sub.live_status
)
data["dynamic_upload_time"] = dynamic_upload_time or sub.dynamic_upload_time
data["uid"] = uid or sub.uid
data["uname"] = uname or sub.uname
data["latest_video_created"] = (
latest_video_created or sub.latest_video_created
)
data["season_name"] = season_name or sub.season_name
data["season_id"] = season_id or sub.season_id
data["season_current_episode"] = (
season_current_episode or sub.season_current_episode
)
data["season_update_time"] = season_update_time or sub.season_update_time
else:
await cls.create(sub_id=sub_id, sub_type=sub_type, sub_users=sub_user)
await cls.update_or_create(sub_id=sub_id, defaults=data)
return True
# except Exception as e:
# logger.info(f"bilibili_sub 添加订阅错误 {type(e)}: {e}")
# return False
@classmethod
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str,sub_type: Optional[str] = None) -> bool:
async def delete_bilibili_sub(
cls, sub_id: int, sub_user: str, sub_type: Optional[str] = None
) -> bool:
"""
说明:
删除订阅
@ -116,129 +141,30 @@ class BilibiliSub(db.Model):
:param sub_user: 删除此条目的用户
"""
try:
async with db.transaction():
if sub_type:
query = (
await cls.query.where(
(cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user) & (cls.sub_type == sub_type))
)
.with_for_update()
.gino.first()
)
else:
query = (
await cls.query.where(
(cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user))
)
.with_for_update()
.gino.first()
)
if not query:
return False
await query.update(
sub_users=query.sub_users.replace(f"{sub_user},", "")
).apply()
if not query.sub_users.strip():
await query.delete()
return True
if sub_type:
sub = await cls.filter(
sub_id=sub_id, sub_type=sub_type, sub_users__contains=sub_user
).first()
else:
sub = await cls.filter(
sub_id=sub_id, sub_users__contains=sub_user
).first()
if not sub:
return False
sub.sub_users = sub.sub_users.replace(f"{sub_user},", "")
if sub.sub_users.strip():
await sub.save(update_fields=["sub_users"])
else:
await sub.delete()
return True
except Exception as e:
logger.info(f"bilibili_sub 删除订阅错误 {type(e)}: {e}")
return False
@classmethod
async def get_sub(cls, sub_id: int) -> Optional["BilibiliSub"]:
"""
说明:
获取订阅对象
参数:
:param sub_id: 订阅 id
"""
return await cls.query.where(cls.sub_id == sub_id).gino.first()
@classmethod
async def get_sub_data(cls, id_: str) -> List["BilibiliSub"]:
"""
获取 id_ 订阅的所有内容
:param id_: id
"""
query = cls.query.where(cls.sub_users.contains(id_))
return await query.gino.all()
@classmethod
async def update_sub_info(
cls,
sub_id: int,
*,
live_short_id: Optional[int] = None,
live_status: Optional[int] = None,
dynamic_upload_time: Optional[int] = None,
uid: Optional[int] = None,
uname: Optional[str] = None,
latest_video_created: Optional[int] = None,
season_name: Optional[str] = None,
season_id: Optional[int] = None,
season_current_episode: Optional[str] = None,
season_update_time: Optional[datetime] = None,
) -> bool:
"""
说明:
更新订阅信息
参数:
:param sub_id: 订阅名称房间号番剧号等
:param live_short_id: 直接短 id
:param live_status: 主播开播状态
:param dynamic_upload_time: 主播/UP最新动态时间
:param uid: 主播/UP uid
:param uname: 用户名称
:param latest_video_created: 最新视频上传时间
:param season_name: 番剧名称
:param season_id: 番剧 season_id
:param season_current_episode: 番剧最新集数
:param season_update_time: 番剧更新时间
"""
try:
async with db.transaction():
sub = (
await cls.query.where(cls.sub_id == sub_id)
.with_for_update()
.gino.first()
)
if sub:
await sub.update(
live_short_id=live_short_id
if live_short_id is not None
else sub.live_short_id,
live_status=live_status
if live_status is not None
else sub.live_status,
dynamic_upload_time=dynamic_upload_time
if dynamic_upload_time is not None
else sub.dynamic_upload_time,
uid=uid if uid is not None else sub.uid,
uname=uname if uname is not None else sub.uname,
latest_video_created=latest_video_created
if latest_video_created is not None
else sub.latest_video_created,
season_update_time=season_update_time
if season_update_time is not None
else sub.season_update_time,
season_current_episode=season_current_episode
if season_current_episode is not None
else sub.season_current_episode,
season_id=season_id if season_id is not None else sub.season_id,
season_name=season_name
if season_name is not None
else sub.season_name,
).apply()
return True
except Exception as e:
logger.info(f"bilibili_sub 更新订阅错误 {type(e)}: {e}")
return False
@classmethod
async def get_all_sub_data(
cls,
) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]":
) -> Tuple[List["BilibiliSub"], List["BilibiliSub"], List["BilibiliSub"]]:
"""
说明:
分类获取所有数据
@ -246,7 +172,7 @@ class BilibiliSub(db.Model):
live_data = []
up_data = []
season_data = []
query = await cls.query.gino.all()
query = await cls.all()
for x in query:
if x.sub_type == "live":
live_data.append(x)

View File

@ -1,28 +1,30 @@
from datetime import datetime
from typing import Any, Tuple
from nonebot import on_command, on_message, on_regex
from nonebot.adapters.onebot.v11 import (
Bot,
Event,
MessageEvent,
GroupMessageEvent,
Message,
Bot,
MessageEvent,
)
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor
from nonebot.params import CommandArg, RegexGroup
from nonebot.permission import SUPERUSER
from configs.config import NICKNAME, Config
from models.ban_user import BanUser
from services.log import logger
from utils.image_utils import BuildImage
from utils.manager import group_manager
from utils.utils import get_message_text, is_number
from nonebot.params import RegexGroup, CommandArg
from .utils import black_word_manager
from nonebot import on_command, on_message, on_regex
from configs.config import Config, NICKNAME
from nonebot.permission import SUPERUSER
from .data_source import show_black_text_image, set_user_punish
from services.log import logger
from models.ban_user import BanUser
from datetime import datetime
from utils.message_builder import image
from .model import BlackWord
from typing import Tuple, Any
from utils.utils import get_message_text, is_number
from .data_source import set_user_punish, show_black_text_image
from .model import BlackWord
from .utils import black_word_manager
__zx_plugin_name__ = "敏感词检测"
__plugin_usage__ = """
@ -38,7 +40,7 @@ usage
设置惩罚id需要通过 '记录名单u:xxxxxxxx' 获取
指令
记录名单
设置惩罚 [user_id] [id] [punish_level]
设置惩罚 [user_id] [下标] [惩罚等级]
示例记录名单
示例记录名单u:12345678
示例设置惩罚 12345678 1 4
@ -150,24 +152,32 @@ async def _(
matcher: Matcher,
event: Event,
):
msg = get_message_text(event.json())
if (
isinstance(event, MessageEvent)
and event.is_tome()
and matcher.plugin_name == "black_word"
and not await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
and not get_message_text(event.json()).startswith("原神绑定")
and not msg.startswith("原神绑定")
):
# 屏蔽群权限-1的群
if isinstance(event, GroupMessageEvent) and group_manager.get_group_level(event.group_id) < 0:
return
user_id = event.user_id
group_id = event.group_id if isinstance(event, GroupMessageEvent) else None
msg = get_message_text(event.json())
if await black_word_manager.check(user_id, group_id, msg) and Config.get_config(
"black_word", "CONTAIN_BLACK_STOP_PROPAGATION"
# if str(event.user_id) not in bot.config.superusers:
# return logger.debug(f"超级用户跳过黑名单词汇检查 Message: {msg}", target=event.user_id)
if (
event.is_tome()
and matcher.plugin_name == "black_word"
and not await BanUser.is_ban(event.user_id)
):
matcher.stop_propagation()
# 屏蔽群权限-1的群
if (
isinstance(event, GroupMessageEvent)
and group_manager.get_group_level(event.group_id) < 0
):
return
user_id = event.user_id
group_id = event.group_id if isinstance(event, GroupMessageEvent) else None
msg = get_message_text(event.json())
if await black_word_manager.check(
user_id, group_id, msg
) and Config.get_config("black_word", "CONTAIN_BLACK_STOP_PROPAGATION"):
matcher.stop_propagation()
@show_black.handle()

View File

@ -1,47 +1,34 @@
from services.db_context import db
from typing import Optional, List
from datetime import datetime, timedelta
from typing import List, Optional
from tortoise import fields
from services.db_context import Model
class BlackWord(db.Model):
__tablename__ = "black_word"
class BlackWord(Model):
# __tablename__ = "black_word"
id = db.Column(db.Integer(), primary_key=True, autoincrement=True)
user_qq = db.Column(db.BigInteger(), nullable=False, primary_key=True)
group_id = db.Column(db.BigInteger())
plant_text = db.Column(db.String())
black_word = db.Column(db.String())
punish = db.Column(db.String(), default="")
punish_level = db.Column(db.Integer())
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField(null=True)
"""群聊id"""
plant_text = fields.TextField()
"""检测文本"""
black_word = fields.TextField()
"""黑名单词语"""
punish = fields.TextField(default="")
"""惩罚内容"""
punish_level = fields.IntField()
"""惩罚等级"""
create_time = fields.DatetimeField(auto_now_add=True)
"""创建时间"""
@classmethod
async def add_user_black_word(
cls,
user_qq: int,
group_id: Optional[int],
black_word: str,
plant_text: str,
punish_level: int,
):
"""
说明:
添加用户发送的敏感词
参数:
:param user_qq: 用户id
:param group_id: 群号
:param black_word: 黑名单词汇
:param plant_text: 消息文本
:param punish_level: 惩罚等级
"""
await cls.create(
user_qq=user_qq,
group_id=group_id,
plant_text=plant_text,
black_word=black_word,
punish_level=punish_level,
create_time=datetime.now(),
)
class Meta:
table = "black_word"
table_description = "惩罚机制数据表"
@classmethod
async def set_user_punish(
@ -63,17 +50,21 @@ class BlackWord(db.Model):
user = None
if (not black_word and not id_) or not punish:
return False
query = cls.query.where(cls.user_qq == user_qq).with_for_update()
if black_word:
user = await query.where(cls.black_word == black_word).order_by(cls.id.desc()).gino.first()
user = (
await cls.filter(user_qq=user_qq, black_word=black_word)
.order_by("id")
.first()
)
elif id_:
user_list = await query.gino.all()
user_list = await cls.filter(user_qq=user_qq).order_by("id").all()
if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)):
return False
user = user_list[id_]
if not user:
return False
await user.update(punish=cls.punish + punish + " ").apply()
user.punish = f"{user.punish}{punish} "
await user.save(update_fields=["punish"])
return True
@classmethod
@ -88,15 +79,14 @@ class BlackWord(db.Model):
:param days: 周期天数
:param punish_level: 惩罚等级
"""
setattr(BlackWord, "count", db.func.count(cls.id).label("count"))
query = cls.select("count").where(
(cls.user_qq == user_qq)
& (cls.punish_level != -1)
& (cls.create_time > datetime.now() - timedelta(days=days))
query = cls.filter(
user_qq=user_qq,
create_time__gte=datetime.now() - timedelta(days=days),
punish_level__not_in=[-1],
)
if punish_level is not None:
query = query.where(cls.punish_level == punish_level)
return (await query.gino.first())[0]
query = query.filter(punish_level=punish_level)
return await query.count()
@classmethod
async def get_user_punish_level(cls, user_qq: int, days: int = 7) -> Optional[int]:
@ -108,12 +98,14 @@ class BlackWord(db.Model):
:param days: 周期天数
"""
if (
query := await cls.query.where(cls.user_qq == user_qq)
.where(cls.create_time > datetime.now() - timedelta(days=days))
.order_by(cls.id.desc())
.gino.first()
user := await cls.filter(
user_qq=user_qq,
create_time__gte=datetime.now() - timedelta(days=days),
)
.order_by("id")
.first()
):
return query.punish_level
return user.punish_level
return None
@classmethod
@ -133,16 +125,18 @@ class BlackWord(db.Model):
:param date: 日期
:param date_type: 日期查询类型
"""
query = cls.query
query = cls
if user_qq:
query = query.where(cls.user_qq == user_qq)
query = query.filter(user_qq=user_qq)
if group_id:
query = query.where(cls.group_id == group_id)
query = query.filter(group_id=group_id)
if date:
if date_type == "=":
query = query.where(cls.create_time == date)
query = query.filter(
create_time__range=[date, date + timedelta(days=1)]
)
elif date_type == ">":
query = query.where(cls.create_time > date)
query = query.filter(create_time__gte=date)
elif date_type == "<":
query = query.where(cls.create_time < date)
return await query.gino.all()
query = query.filter(create_time__lte=date)
return await query.order_by("id").all()

View File

@ -1,15 +1,18 @@
from utils.utils import cn2py, get_bot
from configs.path_config import DATA_PATH
from typing import Optional, Union, Tuple
from .model import BlackWord
from configs.config import Config
from pathlib import Path
from services.log import logger
from models.ban_user import BanUser
from nonebot.adapters.onebot.v11 import ActionFailed
from models.group_member_info import GroupInfoUser
from utils.http_utils import AsyncHttpx
import random
from pathlib import Path
from typing import Optional, Tuple, Union
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import Config
from configs.path_config import DATA_PATH
from models.ban_user import BanUser
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.utils import cn2py, get_bot
from .model import BlackWord
try:
import ujson as json
@ -49,7 +52,7 @@ class BlackWordManager:
"hanbi",
"hanpi",
"laji",
"fw"
"fw",
],
"5": [],
}
@ -94,9 +97,9 @@ class BlackWordManager:
user_id, group_id, data[0], message, int(data[1])
)
return True
if Config.get_config(
"black_word", "ALAPI_CHECK_FLAG"
) and not await check_text(message):
if Config.get_config("black_word", "ALAPI_CHECK_FLAG") and not await check_text(
message
):
await send_msg(
0, None, f"USER {user_id} GROUP {group_id} ALAPI 疑似检测:{message}"
)
@ -146,8 +149,12 @@ async def _add_user_black_word(
"black_word", "AUTO_ADD_PUNISH_LEVEL"
) and user_count > Config.get_config("black_word", "ADD_PUNISH_LEVEL_TO_COUNT"):
punish_level -= 1
await BlackWord.add_user_black_word(
user_id, group_id, black_word, message, punish_level
await BlackWord.create(
user_qq=user_id,
group_id=group_id,
plant_text=message,
black_word=black_word,
punish_level=punish_level,
)
logger.info(
f"已将 USER {user_id} GROUP {group_id} 添加至黑名单词汇记录 Black_word{black_word} Plant_text{message}"
@ -172,7 +179,9 @@ async def _punish_handle(
# 用户周期内触发punish_level级惩罚的次数
user_count = await BlackWord.get_user_count(user_id, cycle_days, punish_level)
# 获取最近一次的惩罚等级,将在此基础上增加
punish_level = await BlackWord.get_user_punish_level(user_id, cycle_days) or punish_level
punish_level = (
await BlackWord.get_user_punish_level(user_id, cycle_days) or punish_level
)
# 容忍次数List[int]
tolerate_count = Config.get_config("black_word", "TOLERATE_COUNT")
if not tolerate_count or len(tolerate_count) < 5:
@ -226,15 +235,17 @@ async def _get_punish(
ban_4_duration = Config.get_config("black_word", "BAN_4_DURATION")
# 口头警告内容
warning_result = Config.get_config("black_word", "WARNING_RESULT")
try:
uname = (await GroupInfoUser.get_member_info(user_id, group_id)).user_name
except AttributeError:
if user := await GroupInfoUser.get_or_none(user_qq=user_id, group_id=group_id):
uname = user.user_name
else:
uname = user_id
# 永久ban
if id_ == 1:
if str(user_id) not in bot.config.superusers:
await BanUser.ban(user_id, 10, 99999999)
await send_msg(user_id, group_id, f"BlackWordChecker 永久ban USER {uname}({user_id})")
await send_msg(
user_id, group_id, f"BlackWordChecker 永久ban USER {uname}({user_id})"
)
logger.info(f"BlackWord 永久封禁 USER {user_id}...")
# 删除好友(有的话
elif id_ == 2:
@ -319,4 +330,7 @@ async def check_text(text: str) -> bool:
return True
black_word_manager = BlackWordManager(DATA_PATH / "black_word" / "black_word.json", DATA_PATH / "black_word" / "black_py.json")
black_word_manager = BlackWordManager(
DATA_PATH / "black_word" / "black_word.json",
DATA_PATH / "black_word" / "black_py.json",
)

View File

@ -1,13 +1,7 @@
from utils.http_utils import AsyncHttpx
from configs.config import Config
from bs4 import BeautifulSoup
import platform
# if platform.system() == "Windows":
# import asyncio
#
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
from configs.config import Config
from utils.http_utils import AsyncHttpx
url = "http://www.eclzz.love"
@ -28,10 +22,7 @@ async def get_bt_info(keyword: str, page: int):
for item in item_lst[:bt_max_num]:
divs = item.find_all("div")
title = (
str(divs[0].find("a").text)
.replace("<em>", "")
.replace("</em>", "")
.strip()
str(divs[0].find("a").text).replace("<em>", "").replace("</em>", "").strip()
)
spans = divs[2].find_all("span")
type_ = spans[0].text

View File

@ -65,4 +65,4 @@ async def _():
mes = "[[_task|genshin_alc]]" + alc_img
for gid in gl:
if group_manager.check_group_task_status(gid, "genshin_alc"):
await bot.send_group_msg(group_id=int(gid), message="" + mes)
await bot.send_group_msg(group_id=int(gid), message=mes)

View File

@ -1,18 +1,19 @@
from nonebot import on_command, Driver
from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent
from utils.message_builder import image
from utils.image_utils import BuildImage
from utils.browser import get_browser
from configs.path_config import IMAGE_PATH
import nonebot
from services.log import logger
from nonebot.permission import SUPERUSER
from typing import List
from datetime import datetime, timedelta
import os
import asyncio
import os
import time
from datetime import datetime, timedelta
from typing import List
import nonebot
from nonebot import Driver, on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageEvent
from nonebot.permission import SUPERUSER
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.browser import get_browser
from utils.image_utils import BuildImage
from utils.message_builder import image
__zx_plugin_name__ = "今日素材"
__plugin_usage__ = """
@ -114,5 +115,3 @@ def get_background_height(weapons_img: List[str]) -> int:
last_weapon.save(weapons_img[-1])
return height

View File

@ -1,219 +1,49 @@
from services.db_context import db
from typing import Optional, Union, List
from datetime import datetime, timedelta
import random
from datetime import datetime, timedelta
from typing import Optional
import pytz
from tortoise import fields
from tortoise.contrib.postgres.functions import Random
from services.db_context import Model
class Genshin(db.Model):
__tablename__ = "genshin"
class Genshin(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
uid = db.Column(db.BigInteger())
mys_id = db.Column(db.BigInteger())
cookie = db.Column(db.String(), default="")
today_query_uid = db.Column(db.String(), default="") # 该cookie今日查询的uid
auto_sign = db.Column(db.Boolean(), default=False)
auto_sign_time = db.Column(db.DateTime(timezone=True))
resin_remind = db.Column(db.Boolean(), default=False) # 树脂提醒
resin_recovery_time = db.Column(db.DateTime(timezone=True)) # 满树脂提醒日期
bind_group = db.Column(db.BigInteger())
login_ticket = db.Column(db.String(), default="")
stuid = db.Column(db.String(), default="")
stoken = db.Column(db.String(), default="")
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
uid = fields.BigIntField()
"""uid"""
mys_id: int = fields.BigIntField(null=True)
"""米游社id"""
cookie: str = fields.TextField(default="")
"""米游社cookie"""
auto_sign = fields.BooleanField(default=False)
"""是否自动签到"""
today_query_uid = fields.TextField(default="")
"""cookie今日查询uid"""
auto_sign_time = fields.DatetimeField(null=True)
"""签到日期时间"""
resin_remind = fields.BooleanField(default=False)
"""树脂提醒"""
resin_recovery_time = fields.DatetimeField(null=True)
"""满树脂提醒日期"""
bind_group: int = fields.BigIntField(null=True)
"""发送提示 绑定群聊"""
login_ticket = fields.TextField(default="")
"""login_ticket"""
stuid: str = fields.TextField(default="")
"""stuid"""
stoken: str = fields.TextField(default="")
"""stoken"""
_idx1 = db.Index("genshin_uid_idx1", "user_qq", "uid", unique=True)
@classmethod
async def add_uid(cls, user_qq: int, uid: int):
"""
说明:
添加一个uid
参数:
:param user_qq 用户qq
:param uid: 原神uid
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.uid == uid))
user = await query.gino.first()
if not user:
await cls.create(
user_qq=user_qq,
uid=uid,
)
return True
return False
@classmethod
async def set_mys_id(cls, uid: int, mys_id: int) -> bool:
"""
说明:
设置米游社id
参数:
:param uid: 原神uid
:param mys_id: 米游社id
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(mys_id=mys_id).apply()
return True
return False
@classmethod
async def set_bind_group(cls, uid: int, bind_group) -> bool:
"""
说明:
绑定group_id除私聊外的提醒将在此群发送
参数:
:param uid: uid
:param bind_group: 群号
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(bind_group=bind_group).apply()
return True
return False
@classmethod
async def get_bind_group(cls, uid: int) -> Optional[int]:
"""
说明:
获取用户绑定的群聊
参数:
:param uid: uid
"""
user = await cls.query.where(cls.uid == uid).gino.first()
if user:
return user.bind_group
return None
@classmethod
async def set_cookie(cls, uid: int, cookie: str) -> bool:
"""
说明:
设置cookie
参数:
:param uid: 原神uid
:param cookie: 米游社id
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(cookie=cookie).apply()
return True
return False
@classmethod
async def set_resin_remind(cls, uid: int, flag: bool) -> bool:
"""
说明:
设置体力提醒
参数:
:param uid: 原神uid
:param flag: 开关状态
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(resin_remind=flag).apply()
return True
return False
@classmethod
async def set_user_resin_recovery_time(cls, uid: int, date: datetime):
"""
说明:
设置体力完成时间
参数:
:param uid: uid
:param date: 提醒日期
"""
u = await cls.query.where(cls.uid == uid).gino.first()
if u:
await u.update(resin_recovery_time=date).apply()
@classmethod
async def get_user_resin_recovery_time(cls, uid: int) -> Optional[datetime]:
"""
说明:
获取体力完成时间
参数:
:param uid: uid
"""
u = await cls.query.where(cls.uid == uid).gino.first()
if u:
return u.resin_recovery_time.astimezone(pytz.timezone("Asia/Shanghai"))
return None
@classmethod
async def get_all_resin_remind_user(cls) -> List["Genshin"]:
"""
说明:
获取所有开启体力提醒的用户
"""
return await cls.query.where(cls.resin_remind == True).gino.all()
@classmethod
async def clear_resin_remind_time(cls, uid: int) -> bool:
"""
说明:
清空提醒日期
参数:
:param uid: uid
"""
user = await cls.query.where(cls.uid == uid).gino.first()
if user:
await user.update(resin_recovery_time=None).apply()
return True
return False
@classmethod
async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
"""
说明:
设置米游社/原神自动签到
参数:
:param uid: 原神uid
:param flag: 开关状态
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(auto_sign=flag).apply()
return True
return False
@classmethod
async def get_all_auto_sign_user(cls) -> List["Genshin"]:
"""
说明:
获取所有开启自动签到的用户
"""
return await cls.query.where(cls.auto_sign == True).gino.all()
@classmethod
async def get_all_sign_user(cls) -> List["Genshin"]:
"""
说明:
获取 原神 所有今日签到用户
"""
return await cls.query.where(cls.auto_sign_time != None).gino.all()
@classmethod
async def clear_sign_time(cls, uid: int) -> bool:
"""
说明:
清空签到日期
参数:
:param uid: uid
"""
user = await cls.query.where(cls.uid == uid).gino.first()
if user:
await user.update(auto_sign_time=None).apply()
return True
return False
class Meta:
table = "genshin"
table_description = "原神数据表"
unique_together = ("user_qq", "uid")
@classmethod
async def random_sign_time(cls, uid: int) -> Optional[datetime]:
@ -223,262 +53,43 @@ class Genshin(db.Model):
说明:
:param uid: uid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
user = await cls.get_or_none(uid=uid)
if user and user.cookie:
if user.auto_sign_time and user.auto_sign_time.astimezone(
pytz.timezone("Asia/Shanghai")
pytz.timezone("Asia/Shanghai")
) - timedelta(seconds=2) >= datetime.now(pytz.timezone("Asia/Shanghai")):
return user.auto_sign_time.astimezone(pytz.timezone("Asia/Shanghai"))
hours = int(str(datetime.now()).split()[1].split(":")[0])
minutes = int(str(datetime.now()).split()[1].split(":")[1])
date = (
datetime.now()
+ timedelta(days=1)
- timedelta(hours=hours)
- timedelta(minutes=minutes - 1)
datetime.now()
+ timedelta(days=1)
- timedelta(hours=hours)
- timedelta(minutes=minutes - 1)
)
random_hours = random.randint(0, 22)
random_minutes = random.randint(1, 59)
date += timedelta(hours=random_hours) + timedelta(minutes=random_minutes)
await user.update(auto_sign_time=date).apply()
user.auto_sign_time = date
await user.save(update_fields=["auto_sign_time"])
return date
return None
@classmethod
async def get_query_cookie(cls, uid: int) -> Optional[str]:
async def random_cookie(cls, uid: int) -> Optional[str]:
"""
说明:
获取查询角色信息cookie
随机获取查询角色信息cookie
参数:
:param uid: 原神uid
"""
# 查找用户今日是否已经查找过,防止重复
query = cls.query.where(cls.today_query_uid.contains(str(uid)))
x = await query.gino.first()
if x:
await cls._add_query_uid(uid, uid)
return x.cookie
for u in await cls.query.where(cls.cookie != "").order_by(db.func.random()).gino.all():
if not u.today_query_uid or len(u.today_query_uid[:-1].split()) < 30:
await cls._add_query_uid(uid, u.uid)
return u.cookie
return None
@classmethod
async def get_user_cookie(cls, uid: int, flag: bool = False) -> Optional[str]:
"""
说明:
获取用户cookie
参数:
:param uid原神uid
:param flag必须使用自己的cookie
"""
cookie = await cls._get_user_data(None, uid, "cookie")
if not cookie and not flag:
cookie = await cls.get_query_cookie(uid)
return cookie
@classmethod
async def get_user_by_qq(cls, user_qq: int) -> Optional["Genshin"]:
"""
说明:
通过qq获取用户对象
参数:
:param user_qq: qq
"""
return await cls.query.where(cls.user_qq == user_qq).gino.first()
@classmethod
async def get_user_by_uid(cls, uid: int) -> Optional["Genshin"]:
"""
说明:
通过uid获取用户对象
参数:
:param uid: qq
"""
return await cls.query.where(cls.uid == uid).gino.first()
@classmethod
async def get_user_uid(cls, user_qq: int) -> Optional[int]:
"""
说明:
获取用户uid
参数:
:param user_qq用户qq
"""
return await cls._get_user_data(user_qq, None, "uid")
@classmethod
async def get_user_mys_id(cls, uid: int) -> Optional[int]:
"""
说嘛
获取用户米游社id
参数:
:param uid原神id
"""
return await cls._get_user_data(None, uid, "mys_id")
@classmethod
async def delete_user_cookie(cls, uid: int):
"""
说明:
删除用户cookie
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
user = await cls.get_or_none(today_query_uid__contains=str(uid))
if user:
await user.update(cookie="").apply()
@classmethod
async def delete_user(cls, user_qq: int):
"""
说明:
删除用户数据
参数:
:param user_qq 用户qq
"""
query = cls.query.where(cls.user_qq == user_qq).with_for_update()
user = await query.gino.first()
if not user:
return False
await user.delete()
return True
@classmethod
async def _add_query_uid(cls, uid: int, cookie_uid: int):
"""
说明:
添加每日查询重复uid的cookie
参数:
:param uid: 原神uid
:param cookie_uid: cookie的uid
"""
query = cls.query.where(cls.uid == cookie_uid).with_for_update()
user = await query.gino.first()
await user.update(today_query_uid=user.today_query_uid + f"{uid} ").apply()
@classmethod
async def _get_user_data(
cls, user_qq: Optional[int], uid: Optional[int], type_: str
) -> Optional[Union[int, str]]:
"""
说明:
获取用户数据
参数:
:param user_qq 用户qq
:param uid: uid
:param type_: 数据类型
"""
if type_ == "uid":
user = await cls.query.where(cls.user_qq == user_qq).gino.first()
return user.uid if user else None
user = await cls.query.where(cls.uid == uid).gino.first()
if not user:
return None
if type_ == "mys_id":
return user.mys_id
elif type_ == "cookie":
return user.cookie
return None
@classmethod
async def reset_today_query_uid(cls):
for u in await cls.query.with_for_update().gino.all():
if u.today_query_uid:
await u.update(today_query_uid="").apply()
@classmethod
async def set_stuid(cls, uid: int, stuid: str) -> bool:
"""
说明:
设置stuid
参数:
:param uid: 原神uid
:param stuid: stuid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(stuid=stuid).apply()
return True
return False
@classmethod
async def set_stoken(cls, uid: int, stoken: str) -> bool:
"""
说明:
设置stoken
参数:
:param uid: 原神uid
:param stoken: stoken
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(stoken=stoken).apply()
return True
return False
@classmethod
async def set_login_ticket(cls, uid: int, login_ticket: str) -> bool:
"""
说明:
设置login_ticket
参数:
:param uid: 原神uid
:param login_ticket: login_ticket
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(login_ticket=login_ticket).apply()
return True
return False
# 获取login_ticket
@classmethod
async def get_login_ticket(cls, uid: int) -> Optional[str]:
"""
说明:
获取login_ticket
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid)
user = await query.gino.first()
if user:
return user.login_ticket
return None
# 获取stuid
@classmethod
async def get_stuid(cls, uid: int) -> Optional[str]:
"""
说明:
获取stuid
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid)
user = await query.gino.first()
if user:
return user.stuid
return None
# 获取stoken
@classmethod
async def get_stoken(cls, uid: int) -> Optional[str]:
"""
说明:
获取stoken
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid)
user = await query.gino.first()
if user:
return user.stoken
for user in await cls.filter(cookie__not="").annotate(rand=Random()).all():
if not user.today_query_uid or len(user.today_query_uid[:-1].split()) < 30:
user.today_query_uid = user.today_query_uid + f"{uid} "
await user.save(update_fields=["today_query_uid"])
return user.cookie
return None

View File

@ -1,9 +1,10 @@
from configs.config import Config
import json
import time
import random
import hashlib
import json
import random
import string
import time
from configs.config import Config
def _md5(text):
@ -15,7 +16,7 @@ def _md5(text):
def get_old_ds() -> str:
n = Config.get_config("genshin", "n")
i = str(int(time.time()))
r = ''.join(random.sample(string.ascii_lowercase + string.digits, 6))
r = "".join(random.sample(string.ascii_lowercase + string.digits, 6))
c = _md5("salt=" + n + "&t=" + i + "&r=" + r)
return i + "," + r + "," + c
@ -33,7 +34,7 @@ def get_ds(q: str = "", b: dict = None) -> str:
def random_hex(length: int) -> str:
result = hex(random.randint(0, 16 ** length)).replace("0x", "").upper()
result = hex(random.randint(0, 16**length)).replace("0x", "").upper()
if len(result) < length:
result = "0" * (length - len(result)) + result
return result

View File

@ -1,13 +1,16 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
from utils.utils import is_number
from .._models import Genshin
from services.log import logger
from nonebot.params import CommandArg, Command
from typing import Tuple
from utils.http_utils import AsyncHttpx
import json
from typing import Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageEvent
from nonebot.params import Command, CommandArg
from services.log import logger
from utils.depends import OneCommand
from utils.http_utils import AsyncHttpx
from utils.utils import is_number
from .._models import Genshin
__zx_plugin_name__ = "原神绑定"
__plugin_usage__ = """
@ -43,82 +46,94 @@ unbind = on_command("原神解绑", priority=5, block=True)
web_Api = "https://api-takumi.mihoyo.com"
bbs_Cookie_url = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}"
bbs_Cookie_url2 = web_Api + "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}"
bbs_Cookie_url2 = (
web_Api
+ "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}"
)
@bind.handle()
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(event: MessageEvent, cmd: str = OneCommand(), arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
user = await Genshin.get_or_none(user_qq=event.user_id)
if cmd in ["原神绑定uid", "原神绑定米游社id"]:
if not is_number(msg):
await bind.finish("uid/id必须为纯数字", at_senders=True)
msg = int(msg)
if cmd == "原神绑定uid":
uid = await Genshin.get_user_uid(event.user_id)
if uid:
await bind.finish(f"您已绑定过uid{uid}如果希望更换uid请先发送原神解绑")
flag = await Genshin.add_uid(event.user_id, msg)
if not flag:
if user:
await bind.finish(f"您已绑定过uid{user.uid}如果希望更换uid请先发送原神解绑")
if await Genshin.get_or_none(user_qq=event.user_id, uid=msg):
await bind.finish("添加失败该uid可能已存在...")
user = await Genshin.create(user_qq=event.user_id, uid=msg)
_x = f"已成功添加原神uid{msg}"
elif cmd == "原神绑定米游社id":
uid = await Genshin.get_user_uid(event.user_id)
if not uid:
if not user:
await bind.finish("请先绑定原神uid..")
await Genshin.set_mys_id(uid, msg)
_x = f"已成功为uid{uid} 设置米游社id{msg}"
user.mys_id = int(msg)
_x = f"已成功为uid{user.uid} 设置米游社id{msg}"
else:
if not msg:
await bind.finish("""私聊发送!!
await bind.finish(
"""私聊发送!!
1.以无痕模式打开浏览器Edge请新建InPrivate窗口
2.打开http://bbs.mihoyo.com/ys/并登陆
2.打开http://bbs.mihoyo.com/ys/ 并登陆
3.登陆后打开http://user.mihoyo.com/进行登陆
4.按下F12打开控制台输入以下命令
var cookie=document.cookie;var ask=confirm('Cookie:'+cookie+'\\n\\nDo you want to copy the cookie to the clipboard?');if(ask==true){copy(cookie);msg=cookie}else{msg='Cancel'}
5.私聊发送原神绑定cookie 刚刚复制的cookie""")
5.私聊发送原神绑定cookie 刚刚复制的cookie"""
)
if isinstance(event, GroupMessageEvent):
await bind.finish("请立即撤回你的消息并私聊发送!")
uid = await Genshin.get_user_uid(event.user_id)
if not uid:
if not user:
await bind.finish("请先绑定原神uid..")
if msg.startswith('"') or msg.startswith("'"):
msg = msg[1:]
if msg.endswith('"') or msg.endswith("'"):
msg = msg[:-1]
await Genshin.set_cookie(uid, msg)
cookie = msg
# 用: 代替=, ,代替;
cookie = '{"' + cookie.replace('=', '": "').replace("; ", '","') + '"}'
print(cookie)
cookie = '{"' + cookie.replace("=", '": "').replace("; ", '","') + '"}'
# print(cookie)
cookie_json = json.loads(cookie)
print(cookie_json)
if 'login_ticket' not in cookie_json:
# print(cookie_json)
if "login_ticket" not in cookie_json:
await bind.finish("请发送正确完整的cookie")
login_ticket = cookie_json['login_ticket']
user.cookie = str(msg)
login_ticket = cookie_json["login_ticket"]
# try:
res = await AsyncHttpx.get(url=bbs_Cookie_url.format(login_ticket))
res.encoding = "utf-8"
data = json.loads(res.text)
print(data)
# print(data)
if "成功" in data["data"]["msg"]:
stuid = str(data["data"]["cookie_info"]["account_id"])
res = await AsyncHttpx.get(url=bbs_Cookie_url2.format(
login_ticket, stuid))
res = await AsyncHttpx.get(url=bbs_Cookie_url2.format(login_ticket, stuid))
res.encoding = "utf-8"
data = json.loads(res.text)
stoken = data["data"]["list"][0]["token"]
# await Genshin.set_cookie(uid, cookie)
await Genshin.set_stoken(uid, stoken)
await Genshin.set_stuid(uid, stuid)
await Genshin.set_login_ticket(uid, login_ticket)
user.stoken = stoken
user.stuid = stuid
user.login_ticket = login_ticket
# except Exception as e:
# await bind.finish("获取登陆信息失败请检查cookie是否正确或更新cookie")
elif data["data"]["msg"] == "登录信息已失效,请重新登录":
await bind.finish("登录信息失效请重新获取最新cookie进行绑定")
_x = f"已成功为uid{uid} 设置cookie"
_x = f"已成功为uid{user.uid} 设置cookie"
if isinstance(event, GroupMessageEvent):
await Genshin.set_bind_group(uid, event.group_id)
user.bind_group = event.group_id
if user:
await user.save(
update_fields=[
"mys_id",
"cookie",
"stoken",
"stuid",
"login_ticket",
"bind_group",
]
)
await bind.send(_x)
logger.info(
f"(USER {event.user_id}, "
@ -129,12 +144,10 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message
@unbind.handle()
async def _(event: MessageEvent):
if await Genshin.delete_user(event.user_id):
await unbind.send("用户数据删除成功...")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f"原神解绑"
)
else:
await unbind.send("该用户数据不存在..")
await Genshin.filter(user_qq=event.user_id).delete()
await unbind.send("用户数据删除成功...")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f"原神解绑"
)

View File

@ -1,14 +1,17 @@
from .data_source import get_sign_reward_list, genshin_sign
from ..mihoyobbs_sign import mihoyobbs_sign
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from nonebot import on_command
from services.log import logger
from .init_task import add_job, scheduler, _sign
from apscheduler.jobstores.base import JobLookupError
from .._models import Genshin
from nonebot.params import Command
from typing import Tuple
from apscheduler.jobstores.base import JobLookupError
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from nonebot.params import Command
from services.log import logger
from utils.depends import OneCommand
from .._models import Genshin
from ..mihoyobbs_sign import mihoyobbs_sign
from .data_source import genshin_sign, get_sign_reward_list
from .init_task import _sign, add_job, scheduler
__zx_plugin_name__ = "原神自动签到"
__plugin_usage__ = """
@ -39,45 +42,46 @@ genshin_matcher = on_command(
@genshin_matcher.handle()
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
cmd = cmd[0]
uid = await Genshin.get_user_uid(event.user_id)
async def _(event: MessageEvent, cmd: str = OneCommand()):
user = await Genshin.get_or_none(user_qq=event.user_id)
if not user:
await genshin_matcher.finish("请先绑定user.uid...")
if cmd == "查看我的cookie":
my_cookie = await Genshin.get_user_cookie(uid, True)
if isinstance(event, GroupMessageEvent):
await genshin_matcher.finish("请私聊查看您的cookie")
await genshin_matcher.finish("您的cookie为" + my_cookie)
if not uid or not await Genshin.get_user_cookie(uid, True):
await genshin_matcher.finish("请先绑定uid和cookie")
# if "account_id" not in await Genshin.get_user_cookie(uid, True):
await genshin_matcher.finish("您的cookie为" + user.cookie)
if not user.uid or not user.cookie:
await genshin_matcher.finish("请先绑定user.uid和cookie")
# if "account_id" not in await Genshin.get_user_cookie(user.uid, True):
# await genshin_matcher.finish("请更新cookie")
if cmd == "原神我硬签":
try:
await genshin_matcher.send("正在进行签到...", at_sender=True)
msg = await genshin_sign(uid)
msg = await genshin_sign(user.uid)
return_data = await mihoyobbs_sign(event.user_id)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID{uid} 原神签到"
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID{user.uid} 原神签到"
)
logger.info(msg)
# 硬签,移除定时任务
try:
for i in range(3):
scheduler.remove_job(f"genshin_auto_sign_{uid}_{event.user_id}_{i}",)
scheduler.remove_job(
f"genshin_auto_sign_{user.uid}_{event.user_id}_{i}",
)
except JobLookupError:
pass
u = await Genshin.get_user_by_uid(uid)
if u and u.auto_sign:
await u.clear_sign_time(uid)
next_date = await Genshin.random_sign_time(uid)
add_job(event.user_id, uid, next_date)
if user.auto_sign:
user.auto_sign_time = None
next_date = await Genshin.random_sign_time(user.uid)
add_job(event.user_id, user.uid, next_date)
msg += f"\n{return_data}\n因开启自动签到\n下一次签到时间为:{next_date.replace(microsecond=0)}"
except Exception as e:
msg = "原神签到失败..请尝试检查cookie或报告至管理员"
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID{uid} 原神签到发生错误 "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID{user.uid} 原神签到发生错误 "
f"{type(e)}{e}"
)
msg = msg or "请检查cookie是否更新"
@ -85,13 +89,16 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
else:
for i in range(3):
try:
scheduler.remove_job(f"genshin_auto_sign_{uid}_{event.user_id}_{i}")
scheduler.remove_job(
f"genshin_auto_sign_{user.uid}_{event.user_id}_{i}"
)
except JobLookupError:
pass
if cmd[0] == "":
await Genshin.set_auto_sign(uid, True)
next_date = await Genshin.random_sign_time(uid)
add_job(event.user_id, uid, next_date)
next_date = await Genshin.random_sign_time(user.uid)
user.auto_sign = True
user.auto_sign_time = next_date
add_job(event.user_id, user.uid, next_date)
await genshin_matcher.send(
f"已开启原神自动签到!\n下一次签到时间为:{next_date.replace(microsecond=0)}",
at_sender=True,
@ -102,11 +109,13 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
f" 开启原神自动签到"
)
else:
await Genshin.set_auto_sign(uid, False)
await Genshin.clear_sign_time(uid)
user.auto_sign = False
user.auto_sign_time = None
await genshin_matcher.send(f"已关闭原神自动签到!", at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 关闭原神自动签到"
)
if user:
await user.save(update_fields=["auto_sign_time", "auto_sign"])

View File

@ -1,14 +1,16 @@
from utils.http_utils import AsyncHttpx
from configs.config import Config
from services.log import logger
from ..mihoyobbs_sign.setting import *
from .._models import Genshin
from typing import Optional, Dict
import hashlib
import random
import string
import uuid
import time
import uuid
from typing import Dict, Optional
from configs.config import Config
from services.log import logger
from utils.http_utils import AsyncHttpx
from .._models import Genshin
from ..mihoyobbs_sign.setting import *
async def genshin_sign(uid: int) -> Optional[str]:
@ -28,10 +30,10 @@ async def genshin_sign(uid: int) -> Optional[str]:
sign_list = await get_sign_reward_list()
get_reward = sign_list["data"]["awards"][
int(sign_info["total_sign_day"]) - 1
]["name"]
]["name"]
reward_num = sign_list["data"]["awards"][
int(sign_info["total_sign_day"]) - 1
]["cnt"]
]["cnt"]
get_im = f"本次签到获得:{get_reward}x{reward_num}"
logger.info("get_im:" + get_im + "\nsign_info:" + str(sign_info))
if status == "OK" and sign_info["is_sign"]:
@ -64,7 +66,7 @@ def timestamp() -> int:
def random_text(num: int) -> str:
return ''.join(random.sample(string.ascii_lowercase + string.digits, num))
return "".join(random.sample(string.ascii_lowercase + string.digits, num))
def md5(text: str) -> str:
@ -75,8 +77,7 @@ def md5(text: str) -> str:
# 生成一个device id
def get_device_id(cookie) -> str:
return str(uuid.uuid3(uuid.NAMESPACE_URL, cookie)).replace(
'-', '').upper()
return str(uuid.uuid3(uuid.NAMESPACE_URL, cookie)).replace("-", "").upper()
async def _sign(uid: int, server_id: str = "cn_gf01") -> Optional[Dict[str, str]]:
@ -88,18 +89,20 @@ async def _sign(uid: int, server_id: str = "cn_gf01") -> Optional[Dict[str, str]
if str(uid)[0] == "5":
server_id = "cn_qd01"
try:
cookie = await Genshin.get_user_cookie(uid, True)
headers['DS'] = get_ds(web=True)
headers['Referer'] = 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true' \
f'&act_id={genshin_Act_id}&utm_source=bbs&utm_medium=mys&utm_campaign=icon'
headers['Cookie'] = cookie
headers['x-rpc-device_id'] = get_device_id(cookie)
req = await AsyncHttpx.post(
url=genshin_Signurl,
headers=headers,
json={"act_id": genshin_Act_id, "uid": uid, "region": server_id},
)
return req.json()
if user := await Genshin.get_or_none(uid=uid):
headers["DS"] = get_ds(web=True)
headers["Referer"] = (
"https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true"
f"&act_id={genshin_Act_id}&utm_source=bbs&utm_medium=mys&utm_campaign=icon"
)
headers["Cookie"] = user.cookie
headers["x-rpc-device_id"] = get_device_id(user.cookie)
req = await AsyncHttpx.post(
url=genshin_Signurl,
headers=headers,
json={"act_id": genshin_Act_id, "uid": uid, "region": server_id},
)
return req.json()
except Exception as e:
logger.error(f"米游社签到发生错误 UID{uid} {type(e)}{e}")
return None
@ -129,17 +132,22 @@ async def _get_sign_info(uid: int, server_id: str = "cn_gf01"):
if str(uid)[0] == "5":
server_id = "cn_qd01"
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi.mihoyo.com/event/bbs_sign_reward/info?act_id=e202009291139501&region={server_id}&uid={uid}",
headers={
"x-rpc-app_version": str(Config.get_config("genshin", "mhyVersion")),
"Cookie": await Genshin.get_user_cookie(int(uid), True),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": str(Config.get_config("genshin", "client_type")),
"Referer": "https://webstatic.mihoyo.com/",
},
)
return req.json()
if user := await Genshin.get_or_none(uid=uid):
req = await AsyncHttpx.get(
url=f"https://api-takumi.mihoyo.com/event/bbs_sign_reward/info?act_id=e202009291139501&region={server_id}&uid={uid}",
headers={
"x-rpc-app_version": str(
Config.get_config("genshin", "mhyVersion")
),
"Cookie": user.cookie,
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": str(
Config.get_config("genshin", "client_type")
),
"Referer": "https://webstatic.mihoyo.com/",
},
)
return req.json()
except Exception as e:
logger.error(f"获取签到信息发生错误 UID{uid} {type(e)}{e}")
return None

View File

@ -1,17 +1,19 @@
from .data_source import genshin_sign
from ..mihoyobbs_sign import mihoyobbs_sign
from models.group_member_info import GroupInfoUser
from utils.message_builder import at
from services.log import logger
from utils.utils import scheduler, get_bot
from apscheduler.jobstores.base import ConflictingIdError
from .._models import Genshin
from datetime import datetime, timedelta
from nonebot import Driver
import nonebot
import random
import pytz
from datetime import datetime, timedelta
import nonebot
import pytz
from apscheduler.jobstores.base import ConflictingIdError
from nonebot import Driver
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.message_builder import at
from utils.utils import get_bot, scheduler
from .._models import Genshin
from ..mihoyobbs_sign import mihoyobbs_sign
from .data_source import genshin_sign
driver: Driver = nonebot.get_driver()
@ -21,7 +23,7 @@ async def _():
"""
启动时分配定时任务
"""
g_list = await Genshin.get_all_auto_sign_user()
g_list = await Genshin.filter(auto_sign=True).all()
for u in g_list:
if u.auto_sign_time:
if date := await Genshin.random_sign_time(u.uid):
@ -33,7 +35,8 @@ async def _():
args=[u.user_qq, u.uid, 0],
)
logger.info(
f"genshin_sign add_jobUSER{u.user_qq} UID{u.uid} " f"{date} 原神自动签到"
f"genshin_sign add_jobUSER{u.user_qq} UID{u.uid} "
f"{date} 原神自动签到"
)
@ -110,10 +113,12 @@ async def _sign(user_id: int, uid: int, count: int):
await bot.send_private_msg(user_id=user_id, message=return_data)
await bot.send_private_msg(user_id=user_id, message=msg)
else:
if not (group_id := await Genshin.get_bind_group(uid)):
group_list = await GroupInfoUser.get_user_all_group(user_id)
if group_list:
group_id = group_list[0]
await bot.send_group_msg(
group_id=group_id, message=at(user_id) + msg
)
if user := await Genshin.get_or_none(uid=uid):
group_id = user.bind_group
if not group_id:
if group_list := await GroupInfoUser.get_user_all_group(user_id):
group_id = group_list[0]
if group_id:
await bot.send_group_msg(
group_id=group_id, message=at(user_id) + msg
)

View File

@ -1,14 +1,16 @@
from nonebot.adapters.onebot.v11 import MessageEvent
from typing import Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot.params import Command
from services.log import logger
# from .init_task import add_job, scheduler, _sign
# from apscheduler.jobstores.base import JobLookupError
from .._models import Genshin
from nonebot.params import Command
from typing import Tuple
from .mihoyobbs import *
__zx_plugin_name__ = "米游社自动签到"
__plugin_usage__ = """
usage
@ -28,12 +30,10 @@ __plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["原神签到"],
"cmd": ["米游社签到"],
}
mihoyobbs_matcher = on_command(
"米游社签到", aliases={"米游社我硬签"}, priority=5, block=True
)
mihoyobbs_matcher = on_command("米游社签到", aliases={"米游社我硬签"}, priority=5, block=True)
@mihoyobbs_matcher.handle()
@ -47,24 +47,29 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
async def mihoyobbs_sign(user_id):
uid = await Genshin.get_user_uid(user_id)
if not uid or not await Genshin.get_user_cookie(uid, True):
user = await Genshin.get_or_none(user_qq=user_id)
if not user or not user.uid or not user.cookie:
await mihoyobbs_matcher.finish("请先绑定uid和cookie", at_sender=True)
stuid = await Genshin.get_stuid(uid)
stoken = await Genshin.get_stoken(uid)
cookie = await Genshin.get_user_cookie(uid)
bbs = mihoyobbs.Mihoyobbs(stuid=stuid, stoken=stoken, cookie=cookie)
bbs = mihoyobbs.Mihoyobbs(stuid=user.stuid, stoken=user.stoken, cookie=user.cookie)
await bbs.init()
return_data = ""
if bbs.Task_do["bbs_Sign"] and bbs.Task_do["bbs_Read_posts"] and bbs.Task_do["bbs_Like_posts"] and \
bbs.Task_do["bbs_Share"]:
return_data += f"今天的米游社签到任务已经全部完成了!\n" \
f"一共获得{mihoyobbs.today_have_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
logger.info(f"今天已经全部完成了!一共获得{mihoyobbs.today_have_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币")
if (
bbs.Task_do["bbs_Sign"]
and bbs.Task_do["bbs_Read_posts"]
and bbs.Task_do["bbs_Like_posts"]
and bbs.Task_do["bbs_Share"]
):
return_data += (
f"今天的米游社签到任务已经全部完成了!\n"
f"一共获得{mihoyobbs.today_have_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
)
logger.info(
f"今天已经全部完成了!一共获得{mihoyobbs.today_have_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币"
)
else:
i = 0
print("开始签到")
print(mihoyobbs.today_have_get_coins)
# print("开始签到")
# print(mihoyobbs.today_have_get_coins)
while mihoyobbs.today_get_coins != 0 and i < 3:
# if i > 0:
await bbs.refresh_list()
@ -74,8 +79,12 @@ async def mihoyobbs_sign(user_id):
await bbs.share_post()
await bbs.get_tasks_list()
i += 1
return_data += "\n" + f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币\n" \
f"还能获得{mihoyobbs.today_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
logger.info(f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币,"
f"还能获得{mihoyobbs.today_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币")
return_data += (
"\n" + f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币\n"
f"还能获得{mihoyobbs.today_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
)
logger.info(
f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币,"
f"还能获得{mihoyobbs.today_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币"
)
return return_data

View File

@ -1,9 +1,10 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from services.log import logger
from .data_source import get_user_memo, get_memo
from .._models import Genshin
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from services.log import logger
from .._models import Genshin
from .data_source import get_memo, get_user_memo
__zx_plugin_name__ = "原神便笺查询"
__plugin_usage__ = """
@ -27,30 +28,27 @@ __plugin_settings__ = {
__plugin_block_limit__ = {}
query_memo_matcher = on_command("原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True)
query_memo_matcher = on_command(
"原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True
)
@query_memo_matcher.handle()
async def _(event: MessageEvent):
uid = await Genshin.get_user_uid(event.user_id)
if not uid or not await Genshin.get_user_cookie(uid, True):
user = await Genshin.get_or_none(user_qq=event.user_id)
if not user or not user.uid or not user.cookie:
await query_memo_matcher.finish("请先绑定uid和cookie")
if isinstance(event, GroupMessageEvent):
uname = event.sender.card or event.sender.nickname
else:
uname = event.sender.nickname
data = await get_user_memo(event.user_id, uid, uname)
data = await get_user_memo(event.user_id, user.uid, uname)
if data:
await query_memo_matcher.send(data)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
f"使用原神便笺查询 uid{uid}"
f"使用原神便笺查询 uid{user.uid}"
)
else:
await query_memo_matcher.send("未查询到数据...")

View File

@ -1,20 +1,22 @@
from typing import Optional, Union
from nonebot.adapters.onebot.v11 import MessageSegment
from configs.config import Config
from asyncio.exceptions import TimeoutError
from services.log import logger
from configs.path_config import IMAGE_PATH
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
from utils.utils import get_user_avatar
from utils.message_builder import image
from .._utils import get_ds
from .._models import Genshin
from io import BytesIO
from nonebot import Driver
import asyncio
import nonebot
from asyncio.exceptions import TimeoutError
from io import BytesIO
from typing import Optional, Tuple, Union
import nonebot
from nonebot import Driver
from nonebot.adapters.onebot.v11 import MessageSegment
from configs.config import Config
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage
from utils.message_builder import image
from utils.utils import get_user_avatar
from .._models import Genshin
from .._utils import get_ds
driver: Driver = nonebot.get_driver()
@ -26,10 +28,7 @@ memo_path.mkdir(exist_ok=True, parents=True)
@driver.on_startup
async def _():
for name, url in zip(
[
"resin.png", "task.png", "resin_discount.png", "chengehu.png",
"zhibian.png"
],
["resin.png", "task.png", "resin_discount.png", "chengehu.png", "zhibian.png"],
[
"https://upload-bbs.mihoyo.com/upload/2021/09/29/8819732/54266243c7d15ba31690c8f5d63cc3c6_71491376413333325"
"20.png?x-oss-process=image//resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,png",
@ -45,8 +44,9 @@ async def _():
logger.info(f"已下载原神便签资源 -> {file}...")
async def get_user_memo(user_id: int, uid: int,
uname: str) -> Optional[Union[str, MessageSegment]]:
async def get_user_memo(
user_id: int, uid: int, uname: str
) -> Optional[Union[str, MessageSegment]]:
uid = str(uid)
if uid[0] in ["1", "2"]:
server_id = "cn_gf01"
@ -57,21 +57,17 @@ async def get_user_memo(user_id: int, uid: int,
return await parse_data_and_draw(user_id, uid, server_id, uname)
async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
async def get_memo(uid: str, server_id: str) -> Tuple[Union[str, dict], int]:
try:
req = await AsyncHttpx.get(
url=
f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
headers={
"DS": get_ds(f"role_id={uid}&server={server_id}"),
"x-rpc-app_version": Config.get_config("genshin",
"mhyVersion"),
"User-Agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": Config.get_config("genshin",
"client_type"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
"Referer": "https://webstatic.mihoyo.com/",
"Cookie": await Genshin.get_user_cookie(int(uid))
"Cookie": await Genshin.random_cookie(uid),
},
)
data = req.json()
@ -85,18 +81,13 @@ async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
return "发生了一些错误,请稍后再试", 998
def create_border(image_name: str, content: str, notice_text: str,
value: str) -> BuildImage:
border = BuildImage(500,
75,
color="#E0D9D1",
font="HYWenHei-85W.ttf",
font_size=20)
text_bk = BuildImage(350,
75,
color="#F5F1EB",
font_size=23,
font="HYWenHei-85W.ttf")
def create_border(
image_name: str, content: str, notice_text: str, value: str
) -> BuildImage:
border = BuildImage(500, 75, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20)
text_bk = BuildImage(
350, 75, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf"
)
_x = 70 if image_name == "resin.png" else 50
_px = 10 if image_name == "resin.png" else 20
text_bk.paste(
@ -119,15 +110,14 @@ def create_border(image_name: str, content: str, notice_text: str,
True,
)
font_width, _ = border.getsize(value)
border.text((350 + 76 - int(font_width / 2), 0),
value,
center_type="by_height")
border.text((350 + 76 - int(font_width / 2), 0), value, center_type="by_height")
border.paste(text_bk, (2, 0), center_type="by_height")
return border
async def parse_data_and_draw(user_id: int, uid: str, server_id: str,
uname: str) -> Union[str, MessageSegment]:
async def parse_data_and_draw(
user_id: int, uid: str, server_id: str, uname: str
) -> Union[str, MessageSegment]:
data, code = await get_memo(uid, server_id)
if code != 200:
return data
@ -138,11 +128,13 @@ async def parse_data_and_draw(user_id: int, uid: str, server_id: str,
if not role_avatar.exists():
await AsyncHttpx.download_file(x["avatar_side_icon"], role_avatar)
return await asyncio.get_event_loop().run_in_executor(
None, _parse_data_and_draw, data, user_avatar, uid, uname)
None, _parse_data_and_draw, data, user_avatar, uid, uname
)
def _parse_data_and_draw(data: dict, user_avatar: BytesIO, uid: int,
uname: str) -> Union[str, MessageSegment]:
def _parse_data_and_draw(
data: dict, user_avatar: BytesIO, uid: int, uname: str
) -> Union[str, MessageSegment]:
current_resin = data["current_resin"] # 当前树脂
max_resin = data["max_resin"] # 最大树脂
resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间
@ -157,33 +149,24 @@ def _parse_data_and_draw(data: dict, user_avatar: BytesIO, uid: int,
max_coin = data["max_home_coin"] # 最大宝钱
coin_recovery_time = data["home_coin_recovery_time"] # 宝钱全部回复时间
transformer_available = data["transformer"]["obtained"] # 参量质变仪可获取
transformer_state = data["transformer"]["recovery_time"][
"reached"] # 参量质变仪状态
transformer_recovery_time = data["transformer"]["recovery_time"][
"Day"] # 参量质变仪回复时间
transformer_state = data["transformer"]["recovery_time"]["reached"] # 参量质变仪状态
transformer_recovery_time = data["transformer"]["recovery_time"]["Day"] # 参量质变仪回复时间
transformer_recovery_hour = data["transformer"]["recovery_time"][
"Hour"] # 参量质变仪回复时间
"Hour"
] # 参量质变仪回复时间
coin_minute, coin_second = divmod(int(coin_recovery_time), 60)
coin_hour, coin_minute = divmod(coin_minute, 60)
#print(data)
# print(data)
minute, second = divmod(int(resin_recovery_time), 60)
hour, minute = divmod(minute, 60)
A = BuildImage(1030,
570,
color="#f1e9e1",
font_size=15,
font="HYWenHei-85W.ttf")
A = BuildImage(1030, 570, color="#f1e9e1", font_size=15, font="HYWenHei-85W.ttf")
A.text((10, 15), "原神便笺 | Create By ZhenXun", (198, 186, 177))
ava = BuildImage(100, 100, background=user_avatar)
ava.circle()
A.paste(ava, (40, 40), True)
A.paste(
BuildImage(0,
0,
plain_text=uname,
font_size=20,
font="HYWenHei-85W.ttf"),
BuildImage(0, 0, plain_text=uname, font_size=20, font="HYWenHei-85W.ttf"),
(160, 62),
True,
)
@ -225,40 +208,39 @@ def _parse_data_and_draw(data: dict, user_avatar: BytesIO, uid: int,
"chengehu.png",
"洞天财翁-洞天宝钱",
"洞天财翁已达到存储上限"
if current_coin == max_coin else f"{coin_hour}小时{coin_minute}分钟后存满",
if current_coin == max_coin
else f"{coin_hour}小时{coin_minute}分钟后存满",
f"{current_coin}/{max_coin}",
)
A.paste(border, (10, 395))
border = create_border(
"zhibian.png",
"参量质变仪",
"不存在" if not transformer_available else
"已准备完成 " if transformer_state else f"{transformer_recovery_hour}小时后可使用" if not transformer_recovery_time else f"{transformer_recovery_time}天后可使用",
"不存在" if not transformer_available else
"可使用" if transformer_state else "冷却中",
"不存在"
if not transformer_available
else "已准备完成 "
if transformer_state
else f"{transformer_recovery_hour}小时后可使用"
if not transformer_recovery_time
else f"{transformer_recovery_time}天后可使用",
"不存在" if not transformer_available else "可使用" if transformer_state else "冷却中",
)
A.paste(border, (10, 475))
expeditions_border = BuildImage(470,
510,
color="#E0D9D1",
font="HYWenHei-85W.ttf",
font_size=20)
expeditions_text = BuildImage(466,
506,
color="#F5F1EB",
font_size=23,
font="HYWenHei-85W.ttf")
expeditions_border = BuildImage(
470, 510, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20
)
expeditions_text = BuildImage(
466, 506, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf"
)
expeditions_text.text(
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}",
(100, 100, 98))
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}", (100, 100, 98)
)
h = 45
for x in expeditions:
_bk = BuildImage(400,
82,
color="#ECE3D8",
font="HYWenHei-85W.ttf",
font_size=21)
_bk = BuildImage(
400, 82, color="#ECE3D8", font="HYWenHei-85W.ttf", font_size=21
)
file_name = x["avatar_side_icon"].split("_")[-1]
role_avatar = memo_path / "role_avatar" / file_name
_ava_img = BuildImage(75, 75, background=role_avatar)

View File

@ -1,11 +1,13 @@
from httpx import ConnectError
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
from services.log import logger
from .data_source import query_role_data
from .._models import Genshin
from utils.utils import is_number
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageEvent
from nonebot.params import CommandArg
from services.log import logger
from utils.utils import is_number
from .._models import Genshin
from .data_source import query_role_data
__zx_plugin_name__ = "原神玩家查询"
__plugin_usage__ = """
@ -29,7 +31,9 @@ __plugin_settings__ = {
__plugin_block_limit__ = {}
query_role_info_matcher = on_command("原神玩家查询", aliases={"原神玩家查找", "ys"}, priority=5, block=True)
query_role_info_matcher = on_command(
"原神玩家查询", aliases={"原神玩家查找", "ys"}, priority=5, block=True
)
@query_role_info_matcher.handle()
@ -39,24 +43,25 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
if not is_number(msg):
await query_role_info_matcher.finish("查询uid必须为数字")
msg = int(msg)
if not msg:
uid = await Genshin.get_user_uid(event.user_id)
uid = None
user = await Genshin.get_or_none(user_qq=event.user_id)
if not msg and user:
uid = user.uid
else:
uid = msg
if not uid: # or not await Genshin.get_user_cookie(uid):
await query_role_info_matcher.finish("请先绑定uid和cookie")
nickname = event.sender.card or event.sender.nickname
mys_id = await Genshin.get_user_mys_id(uid)
data = await query_role_data(event.user_id, uid, mys_id, nickname)
if data:
await query_role_info_matcher.send(data)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神玩家查询 uid{uid}"
)
else:
await query_role_info_matcher.send("查询失败..")
mys_id = user.mys_id if user else None
try:
data = await query_role_data(event.user_id, uid, mys_id, nickname)
if data:
await query_role_info_matcher.send(data)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神玩家查询 uid{uid}"
)
else:
await query_role_info_matcher.send("查询失败..")
except ConnectError:
await query_role_info_matcher.send("网络出小差啦~")

View File

@ -1,11 +1,14 @@
from typing import Optional, List, Dict, Union
from .draw_image import init_image, get_genshin_image
from typing import Dict, List, Optional, Tuple, Union
from nonebot.adapters.onebot.v11 import MessageSegment
from .._utils import get_ds, element_mastery
from configs.config import Config
from services.log import logger
from utils.http_utils import AsyncHttpx
from configs.config import Config
from .._models import Genshin
from .._utils import element_mastery, get_ds
from .draw_image import get_genshin_image, init_image
try:
import ujson as json
@ -96,66 +99,66 @@ b=body q=query
"""
async def get_info(uid_: str, server_id: str) -> "Optional[Union[dict, str]], int":
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index?server={server_id}&role_id={uid_}",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(f"role_id={uid_}&server={server_id}"),
"Origin": "https://webstatic.mihoyo.com",
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 miHoYoBBS/2.2.0",
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
"Referer": "https://webstatic.mihoyo.com/app/community-game-records/index.html?v=6",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
"Cookie": await Genshin.get_user_cookie(int(uid_))
},
)
data = req.json()
if data["message"] == "OK":
return data["data"], 200
return data["message"], 999
except Exception as e:
logger.error(f"访问失败,请重试! {type(e)}: {e}")
async def get_info(uid_: str, server_id: str) -> Tuple[Optional[Union[dict, str]], int]:
# try:
req = await AsyncHttpx.get(
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index?server={server_id}&role_id={uid_}",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(f"role_id={uid_}&server={server_id}"),
"Origin": "https://webstatic.mihoyo.com",
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 miHoYoBBS/2.2.0",
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
"Referer": "https://webstatic.mihoyo.com/app/community-game-records/index.html?v=6",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
"Cookie": await Genshin.random_cookie(uid_),
},
)
data = req.json()
if data["message"] == "OK":
return data["data"], 200
return data["message"], 999
# except Exception as e:
# logger.error(f"访问失败,请重试! {type(e)}: {e}")
return None, -1
async def get_character(
uid: str, character_ids: List[str], server_id="cn_gf01"
) -> Optional[dict]:
try:
req = await AsyncHttpx.post(
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(
"",
{
"character_ids": character_ids,
"role_id": uid,
"server": server_id,
},
),
"Origin": "https://webstatic.mihoyo.com",
"Cookie": await Genshin.get_user_cookie(int(uid)),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
},
json={"character_ids": character_ids, "role_id": uid, "server": server_id},
)
data = req.json()
if data["message"] == "OK":
return data["data"]
except Exception as e:
logger.error(f"访问失败,请重试! {type(e)}: {e}")
# try:
req = await AsyncHttpx.post(
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(
"",
{
"character_ids": character_ids,
"role_id": uid,
"server": server_id,
},
),
"Origin": "https://webstatic.mihoyo.com",
"Cookie": await Genshin.random_cookie(uid),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
},
json={"character_ids": character_ids, "role_id": uid, "server": server_id},
)
data = req.json()
if data["message"] == "OK":
return data["data"]
# except Exception as e:
# logger.error(f"访问失败,请重试! {type(e)}: {e}")
return None
@ -205,7 +208,7 @@ def parsed_data(
"image": world["icon"],
"name": world["name"],
"offerings": world["offerings"],
"icon": world["icon"]
"icon": world["icon"],
}
world_data_dict[world["name"]] = _x
home_data_list = []
@ -231,21 +234,21 @@ async def get_mys_data(uid: str, mys_id: Optional[str]) -> Optional[List[Dict]]:
:param mys_id: 米游社id
"""
if mys_id:
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
headers={
"DS": get_ds(f"uid={mys_id}"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Cookie": await Genshin.get_user_cookie(int(uid))
},
)
data = req.json()
if data["message"] == "OK":
return data["data"]["list"]
except Exception as e:
logger.error(f"访问失败,请重试! {type(e)}: {e}")
# try:
req = await AsyncHttpx.get(
url=f"https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
headers={
"DS": get_ds(f"uid={mys_id}"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Cookie": await Genshin.random_cookie(uid),
},
)
data = req.json()
if data["message"] == "OK":
return data["data"]["list"]
# except Exception as e:
# logger.error(f"访问失败,请重试! {type(e)}: {e}")
return None

View File

@ -1,6 +1,7 @@
from utils.utils import scheduler
from .._models import Genshin
from services.log import logger
from utils.utils import scheduler
from .._models import Genshin
@scheduler.scheduled_job(
@ -10,7 +11,7 @@ from services.log import logger
)
async def _():
try:
await Genshin.reset_today_query_uid()
await Genshin.all().update(today_query_uid="")
logger.warning(f"重置原神查询记录成功..")
except Exception as e:
logger.error(f"重置原神查询记录失败. {type(e)}:{e}")

View File

@ -1,12 +1,15 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from apscheduler.jobstores.base import JobLookupError
from services.log import logger
from .init_task import scheduler, add_job
from .._models import Genshin
from nonebot.params import Command
from typing import Tuple
from apscheduler.jobstores.base import JobLookupError
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from nonebot.params import Command
from services.log import logger
from utils.depends import OneCommand
from .._models import Genshin
from .init_task import add_job, scheduler
__zx_plugin_name__ = "原神树脂提醒"
__plugin_usage__ = """
@ -33,31 +36,32 @@ __plugin_configs__ = {
"AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND": {
"value": True,
"help": "当请求连续三次失败时,关闭用户的树脂提醒",
"default_value": True
"default_value": True,
},
"CUSTOM_RESIN_OVERFLOW_REMIND": {
"value": 20,
"help": "自定义树脂溢出指定数量时的提醒,空值是为关闭",
"default_value": None
}
"default_value": None,
},
}
resin_remind = on_command("开原神树脂提醒", aliases={"关原神树脂提醒"}, priority=5, block=True)
@resin_remind.handle()
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
cmd = cmd[0]
uid = await Genshin.get_user_uid(event.user_id)
if not uid or not await Genshin.get_user_cookie(uid, True):
async def _(event: MessageEvent, cmd: str = OneCommand()):
user = await Genshin.get_or_none(user_qq=event.user_id)
if not user or not user.uid or not user.cookie:
await resin_remind.finish("请先绑定uid和cookie")
try:
scheduler.remove_job(f"genshin_resin_remind_{uid}_{event.user_id}")
scheduler.remove_job(f"genshin_resin_remind_{user.uid}_{event.user_id}")
except JobLookupError:
pass
if cmd[0] == "":
await Genshin.set_resin_remind(uid, True)
add_job(event.user_id, uid)
if user.resin_remind:
await resin_remind.finish("原神树脂提醒已经是开启状态,请勿重复开启!", at_sender=True)
user.resin_remind = True
add_job(event.user_id, user.uid)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
@ -65,12 +69,15 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
)
await resin_remind.send("开启原神树脂提醒成功!", at_sender=True)
else:
await Genshin.set_resin_remind(uid, False)
await Genshin.clear_resin_remind_time(uid)
if not user.resin_remind:
await resin_remind.finish("原神树脂提醒已经是开启状态,请勿重复开启!", at_sender=True)
user.resin_remind = False
user.resin_recovery_time = None
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 关闭原神体力提醒"
)
await resin_remind.send("已关闭原神树脂提醒..", at_sender=True)
if user:
await user.save(update_fields=["resin_remind", "resin_recovery_time"])

View File

@ -1,20 +1,20 @@
from nonebot.adapters.onebot.v11 import ActionFailed
from utils.utils import get_bot, scheduler
from utils.message_builder import at
from models.group_member_info import GroupInfoUser
from apscheduler.jobstores.base import ConflictingIdError
from nonebot import Driver
from .._models import Genshin
from datetime import datetime, timedelta
from apscheduler.jobstores.base import JobLookupError
from services.log import logger
from nonebot.plugin import require
from configs.config import Config
import random
from datetime import datetime, timedelta
import nonebot
import pytz
from apscheduler.jobstores.base import ConflictingIdError, JobLookupError
from nonebot import Driver
from nonebot.adapters.onebot.v11 import ActionFailed
from nonebot.plugin import require
from configs.config import Config
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.message_builder import at
from utils.utils import get_bot, scheduler
from .._models import Genshin
driver: Driver = nonebot.get_driver()
@ -23,7 +23,6 @@ require("query_memo")
from ..query_memo import get_memo
global_map = {}
@ -80,12 +79,13 @@ async def _():
"""
启动时分配定时任务
"""
g_list = await Genshin.get_all_resin_remind_user()
g_list = await Genshin.filter(resin_remind=True).all()
update_list = []
date = datetime.now(pytz.timezone("Asia/Shanghai")) + timedelta(seconds=30)
for u in g_list:
if u.resin_remind:
if u.resin_recovery_time:
if await Genshin.get_user_resin_recovery_time(u.uid) > datetime.now(
if u.resin_recovery_time and u.resin_recovery_time > datetime.now(
pytz.timezone("Asia/Shanghai")
):
# date = await Genshin.get_user_resin_recovery_time(u.uid) # 不能要,因为可能在这期间用户使用了树脂
@ -101,7 +101,8 @@ async def _():
f"genshin_resin_remind add_jobUSER{u.user_qq} UID{u.uid}启动原神树脂提醒 "
)
else:
await Genshin.clear_resin_remind_time(u.uid)
u.resin_recovery_time = None
update_list.append(u)
add_job(u.user_qq, u.uid)
logger.info(
f"genshin_resin_remind add_job CHECKUSER{u.user_qq} UID{u.uid}启动原神树脂提醒 "
@ -111,6 +112,8 @@ async def _():
logger.info(
f"genshin_resin_remind add_job CHECKUSER{u.user_qq} UID{u.uid}启动原神树脂提醒 "
)
if update_list:
await Genshin.bulk_update(update_list, ["resin_recovery_time"])
def add_job(user_id: int, uid: int):
@ -133,6 +136,7 @@ def add_job(user_id: int, uid: int):
async def _remind(user_id: int, uid: str):
user = await Genshin.get_or_none(user_qq=user_id, uid=int(uid))
uid = str(uid)
if uid[0] in ["1", "2"]:
server_id = "cn_gf01"
@ -158,7 +162,9 @@ async def _remind(user_id: int, uid: str):
elif max_resin - 20 <= current_resin < max_resin:
next_time = now + timedelta(minutes=(max_resin - current_resin) * 8)
elif current_resin == max_resin:
custom_overflow_resin = Config.get_config("resin_remind", "CUSTOM_RESIN_OVERFLOW_REMIND")
custom_overflow_resin = Config.get_config(
"resin_remind", "CUSTOM_RESIN_OVERFLOW_REMIND"
)
if user_manager.is_overflow(uid) and custom_overflow_resin:
next_time = now + timedelta(minutes=custom_overflow_resin * 8)
user_manager.add_overflow(uid)
@ -178,28 +184,35 @@ async def _remind(user_id: int, uid: str):
message=msg,
)
else:
group_id = await Genshin.get_bind_group(int(uid))
if not group_id:
group_list = await GroupInfoUser.get_user_all_group(user_id)
if group_list:
group_id = group_list[0]
try:
await bot.send_group_msg(
group_id=group_id,
message=at(user_id) + msg
)
except ActionFailed as e:
logger.error(f"树脂提醒推送发生错误 {type(e)}{e}")
if user:
group_id = user.bind_group
if not group_id:
if group_list := await GroupInfoUser.get_user_all_group(
user_id
):
group_id = group_list[0]
try:
await bot.send_group_msg(
group_id=group_id, message=at(user_id) + msg
)
except ActionFailed as e:
logger.error(f"树脂提醒推送发生错误 {type(e)}{e}")
if not next_time:
if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"):
await Genshin.set_resin_remind(int(uid), False)
await Genshin.clear_resin_remind_time(int(uid))
if user_manager.check(uid) and Config.get_config(
"resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"
):
if user:
user.resin_remind = False
user.resin_recovery_time = None
await user.save(update_fields=["resin_recovery_time", "resin_remind"])
next_time = now + timedelta(minutes=(20 + random.randint(5, 20)) * 8)
user_manager.add_error_count(uid)
else:
user_manager.remove_error_count(uid)
await Genshin.set_user_resin_recovery_time(int(uid), next_time)
if user:
user.resin_recovery_time = next_time
await user.save(update_fields=["resin_recovery_time", "resin_remind"])
scheduler.add_job(
_remind,
"date",
@ -208,6 +221,5 @@ async def _remind(user_id: int, uid: str):
args=[user_id, uid],
)
logger.info(
f"genshin_resin_remind add_jobUSER{user_id} UID{uid} "
f"{next_time} 原神树脂提醒"
)
f"genshin_resin_remind add_jobUSER{user_id} UID{uid} " f"{next_time} 原神树脂提醒"
)

View File

@ -29,7 +29,6 @@ from nonebot.params import CommandArg
import random
import time
__zx_plugin_name__ = "金币红包"
__plugin_usage__ = """
usage
@ -64,11 +63,16 @@ __plugin_settings__ = {
}
__plugin_resources__ = {"prts": IMAGE_PATH}
async def rule(event: GroupMessageEvent) -> bool:
return check_on_gold_red(event)
gold_redbag = on_command(
"塞红包", aliases={"金币红包"}, priority=5, block=True, permission=GROUP
)
open_ = on_command("", aliases={""}, priority=5, block=True, permission=GROUP)
open_ = on_command("", aliases={""}, priority=5, block=True, permission=GROUP, rule=rule)
poke_ = on_notice(priority=6, block=False)
@ -85,27 +89,11 @@ festive_redbag_data = {}
# 阻断其他poke
@run_preprocessor
async def _(matcher: Matcher, event: PokeNotifyEvent):
async def _(matcher: Matcher, event: PokeNotifyEvent, ):
try:
if matcher.type == "notice" and event.self_id == event.target_id:
flag1 = True
flag2 = True
try:
if festive_redbag_data[event.group_id]["user_id"]:
if (
event.user_id
in festive_redbag_data[event.group_id]["open_user"]
):
flag1 = False
except KeyError:
flag1 = False
try:
if redbag_data[event.group_id]["user_id"]:
if event.user_id in redbag_data[event.group_id]["open_user"]:
flag2 = False
except KeyError:
flag2 = False
if flag1 or flag2:
flag = check_on_gold_red(event)
if flag:
if matcher.plugin_name == "poke":
raise IgnoredException("目前正在抢红包...")
else:
@ -121,8 +109,8 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
try:
if time.time() - redbag_data[event.group_id]["time"] > 60:
amount = (
redbag_data[event.group_id]["amount"]
- redbag_data[event.group_id]["open_amount"]
redbag_data[event.group_id]["amount"]
- redbag_data[event.group_id]["open_amount"]
)
await return_gold(redbag_data[event.group_id]["user_id"], event.group_id, amount)
await gold_redbag.send(
@ -185,43 +173,21 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
msg = (
msg.replace("!", "")
.replace("", "")
.replace(",", "")
.replace("", "")
.replace(".", "")
.replace("", "")
.replace("", "")
.replace(",", "")
.replace("", "")
.replace(".", "")
.replace("", "")
)
if msg:
if "红包" not in msg:
return
flag1 = True
flag2 = True
open_flag1 = True
open_flag2 = True
try:
if festive_redbag_data[event.group_id]["user_id"]:
if event.user_id in festive_redbag_data[event.group_id]["open_user"]:
open_flag1 = False
except KeyError:
open_flag1 = False
flag1 = False
try:
if redbag_data[event.group_id]["user_id"]:
if event.user_id in redbag_data[event.group_id]["open_user"]:
open_flag2 = False
except KeyError:
flag2 = False
if not flag1 and not flag2:
await open_.finish("目前没有红包可以开...", at_sender=True)
if open_flag1 or open_flag2:
try:
await open_.send(
image(b64=await get_redbag_img(event.user_id, event.group_id)),
at_sender=True,
await open_.send(
image(b64=await get_redbag_img(event.user_id, event.group_id)),
at_sender=True,
)
except KeyError:
await open_.finish("真贪心,明明已经开过这个红包了的说...", at_sender=True)
else:
except KeyError:
await open_.finish("真贪心,明明已经开过这个红包了的说...", at_sender=True)
@ -229,19 +195,8 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
async def _poke_(event: PokeNotifyEvent):
global redbag_data, festive_redbag_data
if event.self_id == event.target_id:
flag1 = True
flag2 = True
try:
if event.user_id in festive_redbag_data[event.group_id]["open_user"]:
flag1 = False
except KeyError:
flag1 = False
try:
if event.user_id in redbag_data[event.group_id]["open_user"]:
flag2 = False
except KeyError:
flag2 = False
if not flag1 and not flag2:
flag = check_on_gold_red(event)
if not flag:
return
await poke_.send(
image(b64=await get_redbag_img(event.user_id, event.group_id)),
@ -331,7 +286,7 @@ async def _(bot: Bot, arg: Message = CommandArg()):
await bot.send_group_msg(
group_id=g,
message=f"{NICKNAME}发起了金币红包\n金额:{amount}\n数量:{num}\n"
+ image(
+ image(
b64=await generate_send_redbag_pic(int(bot.self_id), greetings)
),
)
@ -342,13 +297,13 @@ async def _(bot: Bot, arg: Message = CommandArg()):
# 红包数据初始化
def init_redbag(
user_id: int,
group_id: int,
nickname: str,
amount: int,
num: int,
bot_self_id: int,
mode: int = 0,
user_id: int,
group_id: int,
nickname: str,
amount: int,
num: int,
bot_self_id: int,
mode: int = 0,
):
global redbag_data, festive_redbag_data
data = redbag_data if mode == 0 else festive_redbag_data
@ -428,3 +383,27 @@ async def end_festive_redbag(bot: Bot, group_id: int):
)
await bot.send_group_msg(group_id=group_id, message=message)
festive_redbag_data[group_id] = {}
def check_on_gold_red(event) -> bool:
flag1 = True
flag2 = True
try:
if festive_redbag_data[event.group_id]["user_id"]:
if (
event.user_id
in festive_redbag_data[event.group_id]["open_user"]
):
flag1 = False
except KeyError:
flag1 = False
try:
if redbag_data[event.group_id]["user_id"]:
if event.user_id in redbag_data[event.group_id]["open_user"]:
flag2 = False
except KeyError:
flag2 = False
if flag1 or flag2:
return True
else:
return False

View File

@ -1,73 +1,58 @@
from services.db_context import db
from typing import List
from tortoise import fields
class RedbagUser(db.Model):
__tablename__ = "redbag_users"
from services.db_context import Model
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
send_redbag_count = db.Column(db.Integer(), default=0)
get_redbag_count = db.Column(db.Integer(), default=0)
spend_gold = db.Column(db.Integer(), default=0)
get_gold = db.Column(db.Integer(), default=0)
_idx1 = db.Index("redbag_group_users_idx1", "user_qq", "group_id", unique=True)
class RedbagUser(Model):
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
send_redbag_count = fields.IntField(default=0)
"""发送红包次数"""
get_redbag_count = fields.IntField(default=0)
"""开启红包次数"""
spend_gold = fields.IntField(default=0)
"""发送红包花费金额"""
get_gold = fields.IntField(default=0)
"""开启红包获取金额"""
class Meta:
table = "redbag_users"
table_description = "红包统计数据表"
unique_together = ("user_qq", "group_id")
@classmethod
async def add_redbag_data(cls, user_qq: int, group_id: int, itype: str, money: int):
async def add_redbag_data(
cls, user_qq: int, group_id: int, i_type: str, money: int
):
"""
说明:
添加收发红包数据
参数:
:param user_qq: qq号
:param group_id: 群号
:param itype: 收或发
:param i_type: 收或发
:param money: 金钱数量
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.with_for_update().gino.first() or await cls.create(
user_qq=user_qq,
group_id=group_id,
)
if itype == "get":
await user.update(
get_redbag_count=user.get_redbag_count + 1,
get_gold=user.get_gold + money,
).apply()
else:
await user.update(
send_redbag_count=user.send_redbag_count + 1,
spend_gold=user.spend_gold + money,
).apply()
@classmethod
async def ensure(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
获取用户对象
参数:
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first() or await cls.create(
user_qq=user_qq,
group_id=group_id,
)
return user
@classmethod
async def get_user_all(cls, group_id: int = None) -> List["RedbagUser"]:
"""
说明:
获取所有用户对象
参数:
:param group_id: 群号
"""
if not group_id:
query = await cls.query.gino.all()
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
if i_type == "get":
user.get_redbag_count = user.get_redbag_count + 1
user.get_gold = user.get_gold + money
else:
query = await cls.query.where((cls.group_id == group_id)).gino.all()
return query
user.send_redbag_count = user.send_redbag_count + 1
user.spend_gold = user.spend_gold + money
await user.save(
update_fields=[
"get_redbag_count",
"get_gold",
"send_redbag_count",
"spend_gold",
]
)

View File

@ -1,15 +1,17 @@
from nonebot import on_message, on_regex
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from utils.utils import is_number, get_message_text
from services.log import logger
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from utils.utils import FreqLimiter, cn2py
from configs.config import Config
from utils.manager import withdraw_message_manager
from .rule import rule
import random
import os
import random
from nonebot import on_message, on_regex
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from configs.config import Config
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.manager import withdraw_message_manager
from utils.message_builder import image
from utils.utils import FreqLimiter, cn2py, get_message_text, is_number
from .rule import rule
try:
import ujson as json
@ -66,16 +68,14 @@ async def _(event: MessageEvent):
if len(msg) > 1:
img_id = msg[1]
path = _path / cn2py(gallery)
if gallery in Config.get_config(
"image_management", "IMAGE_DIR_LIST"
):
if gallery in Config.get_config("image_management", "IMAGE_DIR_LIST"):
if not path.exists() and (path.parent.parent / cn2py(gallery)).exists():
path = IMAGE_PATH / cn2py(gallery)
else:
path.mkdir(parents=True, exist_ok=True)
length = len(os.listdir(path))
if length == 0:
logger.warning(f'图库 {cn2py(gallery)} 为空,调用取消!')
logger.warning(f"图库 {cn2py(gallery)} 为空,调用取消!")
await send_img.finish("该图库中没有图片噢")
index = img_id if img_id else str(random.randint(0, length - 1))
if not is_number(index):
@ -87,8 +87,7 @@ async def _(event: MessageEvent):
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
f"发送{cn2py(gallery)}:"
+ result
f"发送{cn2py(gallery)}:" + result
)
msg_id = await send_img.send(
f"id{index}" + result
@ -113,4 +112,6 @@ async def _(event: MessageEvent):
async def _(event: MessageEvent):
if _flmt.check(event.user_id):
_flmt.start_cd(event.user_id)
await pa_reg.finish(image(random.choice(os.listdir(IMAGE_PATH / "pa")), "pa"))
await pa_reg.finish(
image(IMAGE_PATH / "pa" / random.choice(os.listdir(IMAGE_PATH / "pa")))
)

View File

@ -1,10 +1,11 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from models.group_member_info import GroupInfoUser
from datetime import timedelta
from models.level_user import LevelUser
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from nonebot.adapters.onebot.v11.permission import GROUP
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
__zx_plugin_name__ = "个人信息权限查看"
__plugin_usage__ = """
@ -31,13 +32,13 @@ async def _(event: GroupMessageEvent):
async def get_member_info(user_qq: int, group_id: int) -> str:
user = await GroupInfoUser.get_member_info(user_qq, group_id)
if user is None:
if user := await GroupInfoUser.get_or_none(user_qq=user_qq, group_id=group_id):
result = ""
result += "昵称:" + user.user_name + "\n"
result += "加群时间:" + str(user.user_join_time.date())
return result
else:
return "该群员不在列表中,请更新群成员信息"
result = ""
result += "昵称:" + user.user_name + "\n"
result += "加群时间:" + str(user.user_join_time.date() + timedelta(hours=8))
return result
@my_level.handle()

View File

@ -1,35 +1,23 @@
from datetime import datetime
from tortoise import fields
from services.db_context import db
from services.db_context import Model
# 1.狂牙武器箱
class BuffPrice(db.Model):
__tablename__ = 'buff_prices'
__table_args__ = {'extend_existing': True}
class BuffPrice(Model):
id = db.Column(db.Integer(), primary_key=True)
case_id = db.Column(db.Integer(), nullable=False)
skin_name = db.Column(db.Unicode(), nullable=False)
skin_price = db.Column(db.Float(), nullable=False)
update_date = db.Column(db.DateTime(), nullable=False)
_idx1 = db.Index('buff_price_idx1', 'skin_name', unique=True)
@classmethod
async def ensure(cls, skin_name: str, for_update: bool = False) -> 'BuffPrice':
query = cls.query.where(
(cls.skin_name == skin_name)
)
if for_update:
query = query.with_for_update()
user = await query.gino.first()
return user or await cls.create(
case_id=1,
skin_name=skin_name,
skin_price=0,
update_date=datetime.min,
)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
case_id = fields.IntField()
"""箱子id"""
skin_name = fields.CharField(255, unique=True)
"""皮肤名称"""
skin_price = fields.FloatField()
"""皮肤价格"""
update_date = fields.DatetimeField()
class Meta:
table = "buff_prices"
table_description = "Buff价格数据表"

View File

@ -1,60 +1,51 @@
from datetime import datetime
from tortoise import fields
from services.db_context import db
class OpenCasesUser(db.Model):
__tablename__ = 'open_cases_users'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
total_count = db.Column(db.Integer(), nullable=False, default=0)
blue_count = db.Column(db.Integer(), nullable=False, default=0)
blue_st_count = db.Column(db.Integer(), nullable=False, default=0)
purple_count = db.Column(db.Integer(), nullable=False, default=0)
purple_st_count = db.Column(db.Integer(), nullable=False, default=0)
pink_count = db.Column(db.Integer(), nullable=False, default=0)
pink_st_count = db.Column(db.Integer(), nullable=False, default=0)
red_count = db.Column(db.Integer(), nullable=False, default=0)
red_st_count = db.Column(db.Integer(), nullable=False, default=0)
knife_count = db.Column(db.Integer(), nullable=False, default=0)
knife_st_count = db.Column(db.Integer(), nullable=False, default=0)
spend_money = db.Column(db.Integer(), nullable=False, default=0)
make_money = db.Column(db.Float(), nullable=False, default=0)
today_open_total = db.Column(db.Integer(), nullable=False, default=0)
open_cases_time_last = db.Column(db.DateTime(timezone=True), nullable=False, default=datetime.now())
knifes_name = db.Column(db.Unicode(), nullable=False, default="")
_idx1 = db.Index('open_cases_group_users_idx1', 'user_qq', 'group_id', unique=True)
@classmethod
async def ensure(cls, user_qq: int, group_id: int, for_update: bool = False) -> 'OpenCasesUser':
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
if for_update:
query = query.with_for_update()
user = await query.gino.first()
return user or await cls.create(
user_qq=user_qq,
group_id=group_id,
)
@classmethod
async def get_user_all(cls, group_id: int = None) -> 'list':
user_list = []
if not group_id:
query = await cls.query.gino.all()
else:
query = await cls.query.where(
(cls.group_id == group_id)
).gino.all()
for user in query:
user_list.append(user)
return user_list
from services.db_context import Model
class OpenCasesUser(Model):
__tablename__ = "open_cases_users"
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
total_count = fields.IntField(default=0)
"""总开启次数"""
blue_count = fields.IntField(default=0)
"""蓝色"""
blue_st_count = fields.IntField(default=0)
"""蓝色暗金"""
purple_count = fields.IntField(default=0)
"""紫色"""
purple_st_count = fields.IntField(default=0)
"""紫色暗金"""
pink_count = fields.IntField(default=0)
"""粉色"""
pink_st_count = fields.IntField(default=0)
"""粉色暗金"""
red_count = fields.IntField(default=0)
"""紫色"""
red_st_count = fields.IntField(default=0)
"""紫色暗金"""
knife_count = fields.IntField(default=0)
"""金色"""
knife_st_count = fields.IntField(default=0)
"""金色暗金"""
spend_money = fields.IntField(default=0)
"""花费金币"""
make_money = fields.IntField(default=0)
"""赚取金币"""
today_open_total = fields.IntField(default=0)
"""今日开箱数量"""
open_cases_time_last = fields.DatetimeField()
"""最后开箱日期"""
knifes_name = fields.TextField(default="")
"""已获取金色"""
class Meta:
table = "open_cases_users"
table_description = "开箱统计数据表"
unique_together = ("user_qq", "group_id")

View File

@ -1,20 +1,22 @@
from datetime import datetime, timedelta
from .config import *
from services.log import logger
from services.db_context import db
from .models.open_cases_user import OpenCasesUser
from models.sign_group_user import SignGroupUser
from utils.message_builder import image
import pypinyin
import random
from .utils import get_price
from .models.buff_prices import BuffPrice
from PIL import Image
from utils.image_utils import alpha2white_pil, BuildImage
from configs.path_config import IMAGE_PATH
import asyncio
from utils.utils import cn2py
import random
from datetime import datetime, timedelta
import pypinyin
from PIL import Image
from configs.config import Config
from configs.path_config import IMAGE_PATH
from models.sign_group_user import SignGroupUser
from services.log import logger
from utils.image_utils import BuildImage, alpha2white_pil
from utils.message_builder import image
from utils.utils import cn2py
from .config import *
from .models.buff_prices import BuffPrice
from .models.open_cases_user import OpenCasesUser
from .utils import get_price
async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动") -> str:
@ -26,71 +28,76 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
case = ""
for i in pypinyin.pinyin(case_name, style=pypinyin.NORMAL):
case += "".join(i)
impression = (await SignGroupUser.ensure(user_qq, group)).impression
user, _ = await SignGroupUser.get_or_create(user_qq=user_qq, group_id=group)
impression = user.impression
rand = random.random()
async with db.transaction():
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
# 一天次数上限
if user.today_open_total >= int(
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ int(impression)
/ Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
):
return _handle_is_MAX_COUNT()
skin, mosun = get_color_quality(rand, case_name)
# 调侃
if skin[:2] == "军规":
if skin.find("StatTrak") == -1:
uplist[0] = 1
else:
uplist[1] = 1
ridicule_result = random.choice(["这样看着才舒服", "是自己人,大伙把刀收好", "非常舒适~"])
if skin[:2] == "受限":
if skin.find("StatTrak") == -1:
uplist[2] = 1
else:
uplist[3] = 1
ridicule_result = random.choice(
["还行吧,勉强接受一下下", "居然不是蓝色,太假了", "运气-1-1-1-1-1..."]
)
if skin[:2] == "保密":
if skin.find("StatTrak") == -1:
uplist[4] = 1
else:
uplist[5] = 1
ridicule_result = random.choice(
["开始不适....", "你妈妈买菜必涨价!涨三倍!", "你最近不适合出门,真的"]
)
if skin[:2] == "隐秘":
if skin.find("StatTrak") == -1:
uplist[6] = 1
else:
uplist[7] = 1
ridicule_result = random.choice(
["已经非常不适", "好兄弟你开的什么箱子啊,一般箱子不是只有蓝色的吗", "开始拿阳寿开箱子了?"]
)
if skin[:2] == "罕见":
knifes_flag = True
if skin.find("StatTrak") == -1:
uplist[8] = 1
else:
uplist[9] = 1
ridicule_result = random.choice(
["你的好运我收到了,你可以去喂鲨鱼了", "最近该吃啥就迟点啥吧,哎,好好的一个人怎么就....哎", "众所周知,欧皇寿命极短."]
)
if skin.find("") != -1:
cskin = skin.split("")
skin = cskin[0].strip() + "" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
if skin.find("无涂装") == -1:
dbprice = await BuffPrice.ensure(skin[9:])
await OpenCasesUser.get_or_none(user_qq=user_qq, group_id=group)
# user, _ = await OpenCasesUser.get_or_create(user_qq=user_qq, group_id=group)
user = await OpenCasesUser.get_or_none(user_qq=user_qq, group_id=group)
if not user:
user = await OpenCasesUser.create(
user_qq=user_qq, group_id=group, open_cases_time_last=datetime.now()
)
# 一天次数上限
if user.today_open_total >= int(
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ int(impression) / Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
):
return _handle_is_MAX_COUNT()
skin, mosun = get_color_quality(rand, case_name)
# 调侃
if skin[:2] == "军规":
if skin.find("StatTrak") == -1:
uplist[0] = 1
else:
dbprice = await BuffPrice.ensure(skin[9 : skin.rfind("(")].strip())
if dbprice.skin_price != 0:
price_result = dbprice.skin_price
logger.info("数据库查询到价格: ", dbprice.skin_price)
uplist[10] = dbprice.skin_price
uplist[1] = 1
ridicule_result = random.choice(["这样看着才舒服", "是自己人,大伙把刀收好", "非常舒适~"])
if skin[:2] == "受限":
if skin.find("StatTrak") == -1:
uplist[2] = 1
else:
uplist[3] = 1
ridicule_result = random.choice(
["还行吧,勉强接受一下下", "居然不是蓝色,太假了", "运气-1-1-1-1-1..."]
)
if skin[:2] == "保密":
if skin.find("StatTrak") == -1:
uplist[4] = 1
else:
uplist[5] = 1
ridicule_result = random.choice(["开始不适....", "你妈妈买菜必涨价!涨三倍!", "你最近不适合出门,真的"])
if skin[:2] == "隐秘":
if skin.find("StatTrak") == -1:
uplist[6] = 1
else:
uplist[7] = 1
ridicule_result = random.choice(
["已经非常不适", "好兄弟你开的什么箱子啊,一般箱子不是只有蓝色的吗", "开始拿阳寿开箱子了?"]
)
if skin[:2] == "罕见":
knifes_flag = True
if skin.find("StatTrak") == -1:
uplist[8] = 1
else:
uplist[9] = 1
ridicule_result = random.choice(
["你的好运我收到了,你可以去喂鲨鱼了", "最近该吃啥就迟点啥吧,哎,好好的一个人怎么就....哎", "众所周知,欧皇寿命极短."]
)
if skin.find("") != -1:
cskin = skin.split("")
skin = cskin[0].strip() + "" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
if skin.find("无涂装") == -1:
search_name = skin[9:]
else:
search_name = skin[9 : skin.rfind("(")].strip()
price_result = 0
if data := await BuffPrice.get_or_none(skin_name=search_name):
if data.skin_price != 0:
price_result = data.skin_price
logger.info("数据库查询到价格: ", data.skin_price)
uplist[10] = data.skin_price
else:
price = -1
price_result = "未查询到"
@ -102,55 +109,56 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
price = float(pcp[1].strip())
break
if price != -1:
logger.info("存储入数据库---->", price)
logger.info("存储入数据库---->{price}")
uplist[10] = price
price_result = str(price)
await dbprice.update(
skin_price=price,
update_date=datetime.now(),
).apply()
# sp = skin.split("|")
# cskin_word = sp[1][:sp[1].find("(") - 1].strip()
if knifes_flag:
await user.update(
knifes_name=user.knifes_name
+ f"{case}||{skin.split(':')[1].strip()} 磨损:{str(mosun)[:11]} 价格:{uplist[10]},"
).apply()
cskin_word = skin.split(":")[1].replace("|", "-").replace("StatTrak™", "")
cskin_word = cskin_word[: cskin_word.rfind("(")].strip()
skin_name = cn2py(
cskin_word.replace("|", "-").replace("StatTrak™", "").strip()
data.skin_price = price
data.update_date = datetime.now()
await data.save(update_fields=["skin_price", "update_date"])
# sp = skin.split("|")
# cskin_word = sp[1][:sp[1].find("(") - 1].strip()
if knifes_flag:
await user.update(
knifes_name=user.knifes_name
+ f"{case}||{skin.split(':')[1].strip()} 磨损:{str(mosun)[:11]} 价格:{uplist[10]},"
).apply()
cskin_word = skin.split(":")[1].replace("|", "-").replace("StatTrak™", "")
cskin_word = cskin_word[: cskin_word.rfind("(")].strip()
skin_name = cn2py(cskin_word.replace("|", "-").replace("StatTrak™", "").strip())
img = image(IMAGE_PATH / "cases" / case / f"{skin_name}.png")
# if knifes_flag:
# await user.update(
# knifes_name=user.knifes_name + f"{skin} 磨损:{mosun} 价格:{uplist[10]}"
# ).apply()
if await update_user_total(user, uplist):
logger.info(
f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun} 价格:{uplist[10]} 数据更新成功"
)
img = image(f"{skin_name}.png", "cases/" + case)
# if knifes_flag:
# await user.update(
# knifes_name=user.knifes_name + f"{skin} 磨损:{mosun} 价格:{uplist[10]}"
# ).apply()
if await update_user_total(user, uplist):
logger.info(
f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun} 价格:{uplist[10]} 数据更新成功"
)
else:
logger.warning(
f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun} 价格:{uplist[10]} 数据更新失败"
)
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
over_count = int(
else:
logger.warning(
f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun} 价格:{uplist[10]} 数据更新失败"
)
user, _ = await OpenCasesUser.get_or_create(user_qq=user_qq, group_id=group)
over_count = (
int(
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ int(impression)
/ Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
) - user.today_open_total
return (
f"开启{case_name}武器箱.\n剩余开箱次数:{over_count}.\n" + img + "\n" + f"皮肤:{skin}\n"
f"磨损:{mosun:.9f}\n"
f"价格:{price_result}\n"
f"{ridicule_result}"
)
- user.today_open_total
)
return (
f"开启{case_name}武器箱.\n剩余开箱次数:{over_count}.\n" + img + "\n" + f"皮肤:{skin}\n"
f"磨损:{mosun:.9f}\n"
f"价格:{price_result}\n"
f"{ridicule_result}"
)
async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int = 10):
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
impression = (await SignGroupUser.ensure(user_qq, group)).impression
user, _ = await OpenCasesUser.get_or_create(user_qq=user_qq, group_id=group)
sign_user, _ = await SignGroupUser.get_or_create(user_qq=user_qq, group_id=group)
impression = sign_user.impression
max_count = int(
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ int(impression) / Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
@ -162,11 +170,10 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
f"今天开箱次数不足{num}次噢,请单抽试试看(也许单抽运气更好?)"
f"\n剩余开箱次数:{max_count - user.today_open_total}"
)
await user.update(
total_count=user.total_count + num,
spend_money=user.spend_money + 17 * num,
today_open_total=user.today_open_total + num,
).apply()
user.total_count = user.total_count + num
user.spend_money = user.spend_money + 17 * num
user.today_open_total = user.today_open_total + num
await user.save(update_fields=["total_count", "spend_money", "today_open_total"])
if num < 5:
h = 270
elif num % 5 == 0:
@ -180,46 +187,46 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
uplist = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0]
img_list = []
name_list = ["", "蓝(暗金)", "", "紫(暗金)", "", "粉(暗金)", "", "红(暗金)", "", "金(暗金)"]
async with db.transaction():
for _ in range(num):
knifes_flag = False
rand = random.random()
skin, mosun = get_color_quality(rand, case_name)
if skin[:2] == "军规":
if skin.find("StatTrak") == -1:
uplist[0] += 1
else:
uplist[1] += 1
if skin[:2] == "受限":
if skin.find("StatTrak") == -1:
uplist[2] += 1
else:
uplist[3] += 1
if skin[:2] == "保密":
if skin.find("StatTrak") == -1:
uplist[4] += 1
else:
uplist[5] += 1
if skin[:2] == "隐秘":
if skin.find("StatTrak") == -1:
uplist[6] += 1
else:
uplist[7] += 1
if skin[:2] == "罕见":
knifes_flag = True
if skin.find("StatTrak") == -1:
uplist[8] += 1
else:
uplist[9] += 1
if skin.find("") != -1:
cskin = skin.split("")
skin = cskin[0].strip() + "" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
if skin.find("无涂装") == -1:
dbprice = await BuffPrice.ensure(skin[9:])
for _ in range(num):
knifes_flag = False
rand = random.random()
skin, mosun = get_color_quality(rand, case_name)
if skin[:2] == "军规":
if skin.find("StatTrak") == -1:
uplist[0] += 1
else:
dbprice = await BuffPrice.ensure(skin[9 : skin.rfind("(")].strip())
uplist[1] += 1
if skin[:2] == "受限":
if skin.find("StatTrak") == -1:
uplist[2] += 1
else:
uplist[3] += 1
if skin[:2] == "保密":
if skin.find("StatTrak") == -1:
uplist[4] += 1
else:
uplist[5] += 1
if skin[:2] == "隐秘":
if skin.find("StatTrak") == -1:
uplist[6] += 1
else:
uplist[7] += 1
if skin[:2] == "罕见":
knifes_flag = True
if skin.find("StatTrak") == -1:
uplist[8] += 1
else:
uplist[9] += 1
if skin.find("") != -1:
cskin = skin.split("")
skin = cskin[0].strip() + "" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
if skin.find("无涂装") == -1:
search_name = skin[9:]
else:
search_name = skin[9 : skin.rfind("(")].strip()
if dbprice := await BuffPrice.get_or_none(skin_name=search_name):
if dbprice.skin_price != 0:
price_result = dbprice.skin_price
uplist[10] += price_result
@ -238,7 +245,6 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
style=pypinyin.NORMAL,
):
skin_name += "".join(i)
# img = image(skin_name, "cases/" + case, "png")
wImg = BuildImage(200, 270, 200, 200)
wImg.paste(
alpha2white_pil(
@ -296,7 +302,7 @@ def _handle_is_MAX_COUNT() -> str:
async def update_user_total(user: OpenCasesUser, up_list: list, num: int = 1) -> bool:
try:
await user.update(
await user.update_or_create(
total_count=user.total_count + num,
blue_count=user.blue_count + up_list[0],
blue_st_count=user.blue_st_count + up_list[1],
@ -312,36 +318,35 @@ async def update_user_total(user: OpenCasesUser, up_list: list, num: int = 1) ->
make_money=user.make_money + up_list[10],
today_open_total=user.today_open_total + num,
open_cases_time_last=datetime.now(),
).apply()
)
return True
except:
return False
async def total_open_statistics(user_qq: int, group: int) -> str:
async with db.transaction():
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
return (
f"开箱总数:{user.total_count}\n"
f"今日开箱:{user.today_open_total}\n"
f"蓝色军规:{user.blue_count}\n"
f"蓝色暗金:{user.blue_st_count}\n"
f"紫色受限:{user.purple_count}\n"
f"紫色暗金:{user.purple_st_count}\n"
f"粉色保密:{user.pink_count}\n"
f"粉色暗金:{user.pink_st_count}\n"
f"红色隐秘:{user.red_count}\n"
f"红色暗金:{user.red_st_count}\n"
f"金色罕见:{user.knife_count}\n"
f"金色暗金:{user.knife_st_count}\n"
f"花费金额:{user.spend_money}\n"
f"获取金额:{user.make_money:.2f}\n"
f"最后开箱日期:{(user.open_cases_time_last + timedelta(hours=8)).date()}"
)
user, _ = await OpenCasesUser.get_or_create(user_qq=user_qq, group_id=group)
return (
f"开箱总数:{user.total_count}\n"
f"今日开箱:{user.today_open_total}\n"
f"蓝色军规:{user.blue_count}\n"
f"蓝色暗金:{user.blue_st_count}\n"
f"紫色受限:{user.purple_count}\n"
f"紫色暗金:{user.purple_st_count}\n"
f"粉色保密:{user.pink_count}\n"
f"粉色暗金:{user.pink_st_count}\n"
f"红色隐秘:{user.red_count}\n"
f"红色暗金:{user.red_st_count}\n"
f"金色罕见:{user.knife_count}\n"
f"金色暗金:{user.knife_st_count}\n"
f"花费金额:{user.spend_money}\n"
f"获取金额:{user.make_money:.2f}\n"
f"最后开箱日期:{user.open_cases_time_last.date()}"
)
async def group_statistics(group: int):
user_list = await OpenCasesUser.get_user_all(group)
user_list = await OpenCasesUser.filter(group_id=group).all()
# lan zi fen hong jin pricei
uplist = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0, 0, 0]
for user in user_list:
@ -377,7 +382,8 @@ async def group_statistics(group: int):
async def my_knifes_name(user_id: int, group: int):
knifes_name = (await OpenCasesUser.ensure(user_id, group)).knifes_name
user, _ = await OpenCasesUser.get_or_create(user_qq=user_id, group_id=group)
knifes_name = user.knifes_name
if knifes_name:
knifes_list = knifes_name[:-1].split(",")
length = len(knifes_list)

View File

@ -1,17 +1,19 @@
from .models.buff_prices import BuffPrice
from services.db_context import db
from datetime import datetime, timedelta
from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx
from .models.open_cases_user import OpenCasesUser
from services.log import logger
from utils.utils import get_bot, cn2py
from asyncio.exceptions import TimeoutError
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import Config
from utils.manager import group_manager
from .config import *
import os
from asyncio.exceptions import TimeoutError
from datetime import datetime, timedelta
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import Config
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.manager import group_manager
from utils.utils import cn2py, get_bot
from .config import *
from .models.buff_prices import BuffPrice
from .models.open_cases_user import OpenCasesUser
url = "https://buff.163.com/api/market/goods"
# proxies = 'http://49.75.59.242:3128'
@ -49,108 +51,102 @@ async def util_get_buff_price(case_name: str = "狂牙大行动") -> str:
"骷髅匕首 | 无涂装",
]:
skin = skin.split("|")[0].strip()
async with db.transaction():
name_list = []
price_list = []
parameter = {"game": "csgo", "page_num": "1", "search": skin}
try:
response = await AsyncHttpx.get(url, proxy=Config.get_config("open_cases", "BUFF_PROXY"),
name_list = []
price_list = []
parameter = {"game": "csgo", "page_num": "1", "search": skin}
try:
response = await AsyncHttpx.get(
url,
proxy=Config.get_config("open_cases", "BUFF_PROXY"),
params=parameter,
cookies=cookie,)
if response.status_code == 200:
data = response.json()["data"]
total_page = data["total_page"]
data = data["items"]
flag = False
if (
skin.find("|") == -1
): # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
for i in range(1, total_page + 1):
name_list = []
price_list = []
parameter = {
"game": "csgo",
"page_num": f"{i}",
"search": skin,
}
res = await AsyncHttpx.get(url, params=parameter, cookies=cookie)
data = res.json()["data"][
"items"
]
for j in range(len(data)):
if data[j]["name"] in [f"{skin}(★)"]:
name = data[j]["name"]
price = data[j][
"sell_reference_price"
]
name_list.append(
name.split("")[0].strip()
+ " | 无涂装"
)
price_list.append(price)
flag = True
break
if flag:
cookies=cookie,
)
if response.status_code == 200:
data = response.json()["data"]
total_page = data["total_page"]
data = data["items"]
flag = False
if (
skin.find("|") == -1
): # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
for i in range(1, total_page + 1):
name_list = []
price_list = []
parameter = {
"game": "csgo",
"page_num": f"{i}",
"search": skin,
}
res = await AsyncHttpx.get(
url, params=parameter, cookies=cookie
)
data = res.json()["data"]["items"]
for j in range(len(data)):
if data[j]["name"] in [f"{skin}(★)"]:
name = data[j]["name"]
price = data[j]["sell_reference_price"]
name_list.append(
name.split("")[0].strip() + " | 无涂装"
)
price_list.append(price)
flag = True
break
else:
try:
for _ in range(total_page):
for i in range(len(data)):
name = data[i]["name"]
price = data[i]["sell_reference_price"]
name_list.append(name)
price_list.append(price)
except Exception as e:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
if flag:
break
else:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
except Exception:
try:
for _ in range(total_page):
for i in range(len(data)):
name = data[i]["name"]
price = data[i]["sell_reference_price"]
name_list.append(name)
price_list.append(price)
except Exception as e:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
else:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
continue
for i in range(len(name_list)):
name = name_list[i].strip()
price = float(price_list[i])
if name.find("(★)") != -1:
name = name[: name.find("")] + name[name.find("") + 1 :]
if name.find("消音") != -1 and name.find("S") != -1:
name = name.split("")[0][:-4] + "" + name.split("")[1]
name = (
name.split("|")[0].strip()
+ " | "
+ name.split("|")[1].strip()
)
elif name.find("消音") != -1:
name = (
name.split("|")[0][:-5].strip()
+ " | "
+ name.split("|")[1].strip()
)
if name.find(" 18 ") != -1 and name.find("S") != -1:
name = name.split("")[0][:-5] + "" + name.split("")[1]
name = (
name.split("|")[0].strip()
+ " | "
+ name.split("|")[1].strip()
)
elif name.find(" 18 ") != -1:
name = (
name.split("|")[0][:-6].strip()
+ " | "
+ name.split("|")[1].strip()
)
dbskin = await BuffPrice.ensure(name, True)
if (
dbskin.update_date + timedelta(8)
).date() == datetime.now().date():
except Exception:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
continue
for i in range(len(name_list)):
name = name_list[i].strip()
price = float(price_list[i])
if name.find("(★)") != -1:
name = name[: name.find("")] + name[name.find("") + 1 :]
if name.find("消音") != -1 and name.find("S") != -1:
name = name.split("")[0][:-4] + "" + name.split("")[1]
name = (
name.split("|")[0].strip() + " | " + name.split("|")[1].strip()
)
elif name.find("消音") != -1:
name = (
name.split("|")[0][:-5].strip()
+ " | "
+ name.split("|")[1].strip()
)
if name.find(" 18 ") != -1 and name.find("S") != -1:
name = name.split("")[0][:-5] + "" + name.split("")[1]
name = (
name.split("|")[0].strip() + " | " + name.split("|")[1].strip()
)
elif name.find(" 18 ") != -1:
name = (
name.split("|")[0][:-6].strip()
+ " | "
+ name.split("|")[1].strip()
)
if dbskin := await BuffPrice.get_or_none(skin_name=name):
if dbskin.update_date.date() == datetime.now().date():
continue
await dbskin.update(
case_id=case_id,
skin_price=price,
update_date=datetime.now(),
).apply()
dbskin.case_id = case_id
dbskin.skin_price = price
dbskin.update_date = datetime.now()
await dbskin.save(
update_fields=["case_id", "skin_price", "update_date"]
)
logger.info(f"{name_list[i]}---------->成功更新")
result = None
if failed_list:
@ -186,14 +182,16 @@ async def util_get_buff_img(case_name: str = "狂牙大行动") -> str:
logger.info(f"开始更新----->{skin}")
skin_name = ""
# try:
response = await AsyncHttpx.get(url, proxy=Config.get_config("open_cases", "BUFF_PROXY"), params=parameter)
response = await AsyncHttpx.get(
url,
proxy=Config.get_config("open_cases", "BUFF_PROXY"),
params=parameter,
)
if response.status_code == 200:
data = response.json()["data"]
total_page = data["total_page"]
flag = False
if (
skin.find("|") == -1
): # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
if skin.find("|") == -1: # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
for i in range(1, total_page + 1):
res = await AsyncHttpx.get(url, params=parameter)
data = res.json()["data"]["items"]
@ -201,17 +199,21 @@ async def util_get_buff_img(case_name: str = "狂牙大行动") -> str:
if data[j]["name"] in [f"{skin}(★)"]:
img_url = data[j]["goods_info"]["icon_url"]
skin_name = cn2py(skin + "无涂装")
await AsyncHttpx.download_file(img_url, path / f"{skin_name}.png")
await AsyncHttpx.download_file(
img_url, path / f"{skin_name}.png"
)
flag = True
break
if flag:
break
else:
img_url = (await response.json())["data"]["items"][0][
"goods_info"
]["icon_url"]
img_url = (await response.json())["data"]["items"][0]["goods_info"][
"icon_url"
]
skin_name += cn2py(skin.replace("|", "-").strip())
if await AsyncHttpx.download_file(img_url, path / f"{skin_name}.png"):
if await AsyncHttpx.download_file(
img_url, path / f"{skin_name}.png"
):
logger.info(f"------->写入 {skin} 成功")
else:
logger.info(f"------->写入 {skin} 失败")
@ -255,18 +257,15 @@ async def get_price(d_name):
async def update_count_daily():
try:
users = await OpenCasesUser.get_user_all()
if users:
for user in users:
await user.update(
today_open_total=0,
).apply()
await OpenCasesUser.all().update(today_open_total=0)
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
try:
await bot.send_group_msg(group_id=g, message="[[_task|open_case_reset_remind]]今日开箱次数重置成功")
await bot.send_group_msg(
group_id=g, message="[[_task|open_case_reset_remind]]今日开箱次数重置成功"
)
except ActionFailed:
logger.warning(f"{g} 群被禁言,无法发送 开箱重置提醒")
logger.info("今日开箱次数重置成功")

View File

@ -1,22 +1,24 @@
from nonebot import on_message
from services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent, ActionFailed
from utils.manager import group_manager
from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.message_builder import image
from utils.image_utils import BuildImage
from utils.browser import get_browser
from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx
from configs.config import Config
from utils.user_agent import get_user_agent
import aiohttp
import asyncio
import time
import aiohttp
import ujson as json
from bilireq import video
from nonebot import on_message
from nonebot.adapters.onebot.v11 import ActionFailed, GroupMessageEvent
from nonebot.adapters.onebot.v11.permission import GROUP
from configs.config import Config
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from utils.browser import get_browser
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage
from utils.manager import group_manager
from utils.message_builder import image
from utils.user_agent import get_user_agent
from utils.utils import get_local_proxy, get_message_json, get_message_text, is_number
__zx_plugin_name__ = "B站转发解析"
__plugin_usage__ = """
usage
@ -39,7 +41,10 @@ Config.add_plugin_config(
async def plugin_on_checker(event: GroupMessageEvent) -> bool:
return group_manager.get_plugin_status("parse_bilibili_json", event.group_id)
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False, rule=plugin_on_checker)
parse_bilibili_json = on_message(
priority=1, permission=GROUP, block=False, rule=plugin_on_checker
)
_tmp = {}
@ -55,16 +60,14 @@ async def _(event: GroupMessageEvent):
data = None
if data:
# 转发视频
if data.get("desc") == "哔哩哔哩" or data.get('prompt').find('哔哩哔哩') != -1:
async with aiohttp.ClientSession(
headers=get_user_agent()
) as session:
if data.get("desc") == "哔哩哔哩" or "哔哩哔哩" in data.get("prompt"):
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
data["meta"]["detail_1"]["qqdocurl"],
timeout=7,
data["meta"]["detail_1"]["qqdocurl"],
timeout=7,
) as response:
url = str(response.url).split("?")[0]
if url[-1] == '/':
if url[-1] == "/":
url = url[:-1]
bvid = url.split("/")[-1]
vd_info = await video.get_video_base_info(bvid)
@ -93,10 +96,11 @@ async def _(event: GroupMessageEvent):
timeout=100000,
)
await asyncio.get_event_loop().run_in_executor(
None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
None, resize, TEMP_PATH / f"cv_{event.user_id}.png"
)
await parse_bilibili_json.send(
"[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
"[[_task|bilibili_parse]]"
+ image(TEMP_PATH / f"cv_{event.user_id}.png")
)
await page.close()
logger.info(
@ -121,15 +125,13 @@ async def _(event: GroupMessageEvent):
msg = msg[index + 2 : index + 11]
if is_number(msg):
url = f"https://www.bilibili.com/video/av{msg}"
vd_info = await video.get_video_base_info('av' + msg)
vd_info = await video.get_video_base_info("av" + msg)
elif "https://b23.tv" in msg:
url = "https://" + msg[msg.find("b23.tv"): msg.find("b23.tv") + 14]
async with aiohttp.ClientSession(
headers=get_user_agent()
) as session:
url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 14]
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
url,
timeout=7,
url,
timeout=7,
) as response:
url = (str(response.url).split("?")[0]).strip("/")
bvid = url.split("/")[-1]
@ -150,8 +152,9 @@ async def _(event: GroupMessageEvent):
date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
try:
await parse_bilibili_json.send(
"[[_task|bilibili_parse]]" +
image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
"[[_task|bilibili_parse]]"
+ image(vd_info["pic"])
+ f"\nav{aid}\n标题:{title}\n"
f"UP{author}\n"
f"上传日期:{date}\n"
f"回复:{reply},收藏:{favorite},投币:{coin}\n"

View File

@ -1,17 +1,17 @@
from asyncio.exceptions import TimeoutError
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import Arg, CommandArg
from nonebot.typing import T_State
from configs.config import Config
from utils.utils import is_number, change_pixiv_image_links
from utils.message_builder import image
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from asyncio.exceptions import TimeoutError
from configs.path_config import IMAGE_PATH
from utils.manager import withdraw_message_manager
from utils.http_utils import AsyncHttpx
from nonebot.params import CommandArg, Arg
from utils.manager import withdraw_message_manager
from utils.message_builder import image
from utils.utils import change_pixiv_image_links, is_number
__zx_plugin_name__ = "pid搜索"
__plugin_usage__ = """
@ -88,7 +88,7 @@ async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
img_url = change_pixiv_image_links(img_url)
if not await AsyncHttpx.download_file(
img_url,
IMAGE_PATH / "temp" / f"pid_search_{event.user_id}_{i}.png",
TEMP_PATH / f"pid_search_{event.user_id}_{i}.png",
headers=headers,
):
await pid_search.send("图片下载失败了....", at_sender=True)
@ -101,7 +101,7 @@ async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
f"pid{pid}\n"
f"author{author}\n"
f"author_id{author_id}\n"
f'{image(f"pid_search_{event.user_id}_{i}.png", "temp")}'
f'{image(TEMP_PATH / f"pid_search_{event.user_id}_{i}.png")}'
f"{tmp}"
)
)

View File

@ -1,7 +1,7 @@
from configs.config import Config
from utils.utils import GDict
import nonebot
from configs.config import Config
from utils.utils import GDict
Config.add_plugin_config(
"hibiapi",
@ -10,59 +10,42 @@ Config.add_plugin_config(
help_="如果没有自建或其他hibiapi请不要修改",
default_value="https://api.obfs.dev",
)
Config.add_plugin_config(
"pixiv",
"PIXIV_NGINX_URL",
"i.pximg.cf",
help_="Pixiv反向代理"
)
Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pximg.cf", help_="Pixiv反向代理")
Config.add_plugin_config(
"pix",
"PIX_IMAGE_SIZE",
"master",
name="PIX图库",
help_="PIX图库下载的画质 可能的值original原图master缩略图加快发送速度",
default_value="master"
default_value="master",
)
Config.add_plugin_config(
"pix",
"SEARCH_HIBIAPI_BOOKMARKS",
5000,
help_="最低收藏PIX使用HIBIAPI搜索图片时达到最低收藏才会添加至图库",
default_value=5000
default_value=5000,
)
Config.add_plugin_config(
"pix",
"WITHDRAW_PIX_MESSAGE",
(0, 1),
help_="自动撤回参1延迟撤回色图时间(秒)0 为关闭 | 参2监控聊天类型0(私聊) 1(群聊) 2(群聊+私聊)",
default_value=(0, 1)
default_value=(0, 1),
)
Config.add_plugin_config(
"pix",
"PIX_OMEGA_PIXIV_RATIO",
(10, 0),
help_="PIX图库 与 额外图库OmegaPixivIllusts 混合搜索的比例 参1PIX图库 参2OmegaPixivIllusts扩展图库没有此图库请设置为0",
default_value=(10, 0)
)
Config.add_plugin_config(
"pix",
"TIMEOUT",
10,
help_="下载图片超时限制(秒)",
default_value=10
default_value=(10, 0),
)
Config.add_plugin_config("pix", "TIMEOUT", 10, help_="下载图片超时限制(秒)", default_value=10)
Config.add_plugin_config(
"pix",
"SHOW_INFO",
True,
help_="是否显示图片的基本信息如PID等",
default_value=True
"pix", "SHOW_INFO", True, help_="是否显示图片的基本信息如PID等", default_value=True
)
GDict['run_sql'].append("ALTER TABLE omega_pixiv_illusts ADD classified Integer;")
GDict["run_sql"].append("ALTER TABLE omega_pixiv_illusts ADD classified Integer;")
nonebot.load_plugins("plugins/pix_gallery")

View File

@ -1,19 +1,23 @@
from asyncpg.exceptions import UniqueViolationError
from ._model.omega_pixiv_illusts import OmegaPixivIllusts
from asyncio.locks import Semaphore
from asyncio.exceptions import TimeoutError
from ._model.pixiv import Pixiv
from typing import List, Optional
from utils.utils import change_pixiv_image_links, change_img_md5
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
from services.log import logger
from configs.config import Config
from configs.path_config import TEMP_PATH
import aiofiles
import platform
import asyncio
import math
import platform
from asyncio.exceptions import TimeoutError
from asyncio.locks import Semaphore
from copy import deepcopy
from typing import List, Optional, Tuple
import aiofiles
from asyncpg.exceptions import UniqueViolationError
from configs.config import Config
from configs.path_config import TEMP_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage
from utils.utils import change_img_md5, change_pixiv_image_links
from ._model.omega_pixiv_illusts import OmegaPixivIllusts
from ._model.pixiv import Pixiv
try:
import ujson as json
@ -65,9 +69,7 @@ async def start_update_image_url(
params = {"word": keyword, "page": page}
tasks.append(
asyncio.ensure_future(
search_image(
url, keyword, params, semaphore, page, black_pid
)
search_image(url, keyword, params, semaphore, page, black_pid)
)
)
if keyword.startswith("pid:"):
@ -101,96 +103,91 @@ async def search_image(
pic_count = 0
pid_count = 0
async with semaphore:
try:
data = (await AsyncHttpx.get(url, params=params)).json()
if (
not data
or data.get("error")
or (not data.get("illusts") and not data.get("illust"))
):
return 0, 0
if url != f"{HIBIAPI}/api/pixiv/illust":
logger.info(f'{keyword}: 获取数据成功...数据总量:{len(data["illusts"])}')
data = data["illusts"]
# try:
data = (await AsyncHttpx.get(url, params=params)).json()
if (
not data
or data.get("error")
or (not data.get("illusts") and not data.get("illust"))
):
return 0, 0
if url != f"{HIBIAPI}/api/pixiv/illust":
logger.info(f'{keyword}: 获取数据成功...数据总量:{len(data["illusts"])}')
data = data["illusts"]
else:
logger.info(f'获取数据成功...PID{params.get("id")}')
data = [data["illust"]]
img_data = {}
for x in data:
pid = x["id"]
title = x["title"]
width = x["width"]
height = x["height"]
view = x["total_view"]
bookmarks = x["total_bookmarks"]
uid = x["user"]["id"]
author = x["user"]["name"]
tags = []
for tag in x["tags"]:
for i in tag:
if tag[i]:
tags.append(tag[i])
img_urls = []
if x["page_count"] == 1:
img_urls.append(x["meta_single_page"]["original_image_url"])
else:
logger.info(f'获取数据成功...PID{params.get("id")}')
data = [data["illust"]]
img_data = {}
for x in data:
pid = x["id"]
title = x["title"]
width = x["width"]
height = x["height"]
view = x["total_view"]
bookmarks = x["total_bookmarks"]
uid = x["user"]["id"]
author = x["user"]["name"]
tags = []
for tag in x["tags"]:
for i in tag:
if tag[i]:
tags.append(tag[i])
img_urls = []
if x["page_count"] == 1:
img_urls.append(x["meta_single_page"]["original_image_url"])
else:
for urls in x["meta_pages"]:
img_urls.append(urls["image_urls"]["original"])
if (
(
bookmarks
>= Config.get_config("pix", "SEARCH_HIBIAPI_BOOKMARKS")
or (
url == f"{HIBIAPI}/api/pixiv/member_illust"
and bookmarks >= 1500
)
or (url == f"{HIBIAPI}/api/pixiv/illust")
for urls in x["meta_pages"]:
img_urls.append(urls["image_urls"]["original"])
if (
(
bookmarks >= Config.get_config("pix", "SEARCH_HIBIAPI_BOOKMARKS")
or (
url == f"{HIBIAPI}/api/pixiv/member_illust"
and bookmarks >= 1500
)
and len(img_urls) < 10
and _check_black(img_urls, black)
or (url == f"{HIBIAPI}/api/pixiv/illust")
)
and len(img_urls) < 10
and _check_black(img_urls, black)
):
img_data[pid] = {
"pid": pid,
"title": title,
"width": width,
"height": height,
"view": view,
"bookmarks": bookmarks,
"img_urls": img_urls,
"uid": uid,
"author": author,
"tags": tags,
}
else:
continue
for x in img_data.keys():
data = img_data[x]
data_copy = deepcopy(data)
del data_copy["img_urls"]
for img_url in data["img_urls"]:
img_p = img_url[img_url.rfind("_") + 1 : img_url.rfind(".")]
data_copy["img_url"] = img_url
data_copy["img_p"] = img_p
data_copy["is_r18"] = "R-18" in data["tags"]
if not await Pixiv.exists(
pid=data["pid"], img_url=img_url, img_p=img_p
):
img_data[pid] = {
"pid": pid,
"title": title,
"width": width,
"height": height,
"view": view,
"bookmarks": bookmarks,
"img_urls": img_urls,
"uid": uid,
"author": author,
"tags": tags,
}
data_copy["img_url"] = img_url
await Pixiv.create(**data_copy)
if data["pid"] not in tmp_pid:
pid_count += 1
tmp_pid.append(data["pid"])
pic_count += 1
logger.info(f'存储图片PID{data["pid"]} IMG_P{img_p}')
else:
continue
for x in img_data.keys():
data = img_data[x]
for img_url in data["img_urls"]:
img_p = img_url[img_url.rfind("_") + 1 : img_url.rfind(".")]
try:
if await Pixiv.add_image_data(
data["pid"],
data["title"],
data["width"],
data["height"],
data["view"],
data["bookmarks"],
img_url,
img_p,
data["uid"],
data["author"],
",".join(data["tags"]),
):
if data["pid"] not in tmp_pid:
pid_count += 1
tmp_pid.append(data["pid"])
pic_count += 1
logger.info(f'存储图片PID{data["pid"]} IMG_P{img_p}')
except UniqueViolationError:
logger.warning(f'{data["pid"]} | {img_url} 已存在...')
except Exception as e:
logger.warning(f"PIX在线搜索图片错误已再次调用 {type(e)}{e}")
await search_image(url, keyword, params, semaphore, page, black)
logger.warning(f'{data["pid"]} | {img_url} 已存在...')
# except Exception as e:
# logger.warning(f"PIX在线搜索图片错误已再次调用 {type(e)}{e}")
# await search_image(url, keyword, params, semaphore, page, black)
return pid_count, pic_count
@ -206,7 +203,9 @@ async def get_image(img_url: str, user_id: int) -> Optional[str]:
params = {"id": pid}
for _ in range(3):
try:
response = await AsyncHttpx.get(f"{HIBIAPI}/api/pixiv/illust", params=params)
response = await AsyncHttpx.get(
f"{HIBIAPI}/api/pixiv/illust", params=params
)
if response.status_code == 200:
data = response.json()
if data.get("illust"):
@ -215,22 +214,28 @@ async def get_image(img_url: str, user_id: int) -> Optional[str]:
"original_image_url"
]
else:
img_url = data["illust"]["meta_pages"][0][
"image_urls"
]["original"]
img_url = data["illust"]["meta_pages"][0]["image_urls"][
"original"
]
break
except TimeoutError:
pass
old_img_url = img_url
img_url = change_pixiv_image_links(
img_url, Config.get_config("pix", "PIX_IMAGE_SIZE"), Config.get_config("pixiv", "PIXIV_NGINX_URL")
img_url,
Config.get_config("pix", "PIX_IMAGE_SIZE"),
Config.get_config("pixiv", "PIXIV_NGINX_URL"),
)
old_img_url = change_pixiv_image_links(
old_img_url, None, Config.get_config("pixiv", "PIXIV_NGINX_URL")
)
for _ in range(3):
try:
response = await AsyncHttpx.get(img_url, headers=headers, timeout=Config.get_config("pix", "TIMEOUT"),)
response = await AsyncHttpx.get(
img_url,
headers=headers,
timeout=Config.get_config("pix", "TIMEOUT"),
)
if response.status_code == 404:
img_url = old_img_url
continue
@ -238,7 +243,9 @@ async def get_image(img_url: str, user_id: int) -> Optional[str]:
TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg", "wb"
) as f:
await f.write(response.content)
change_img_md5(TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg")
change_img_md5(
TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg"
)
return TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg"
except TimeoutError:
logger.warning(f"PIX{img_url} 图片下载超时...")
@ -264,7 +271,7 @@ async def uid_pid_exists(id_: str) -> bool:
return True
async def get_keyword_num(keyword: str) -> "int, int, int, int, int":
async def get_keyword_num(keyword: str) -> Tuple[int, int, int, int, int]:
"""
查看图片相关 tag 数量
:param keyword: 关键词tag
@ -276,7 +283,7 @@ async def get_keyword_num(keyword: str) -> "int, int, int, int, int":
return count, r18_count, count_, setu_count, r18_count_
async def remove_image(pid: int, img_p: str) -> bool:
async def remove_image(pid: int, img_p: Optional[str]):
"""
删除置顶图片
:param pid: pid
@ -285,7 +292,10 @@ async def remove_image(pid: int, img_p: str) -> bool:
if img_p:
if "p" not in img_p:
img_p = f"p{img_p}"
return await Pixiv.remove_image_data(pid, img_p)
if img_p:
await Pixiv.filter(pid=pid, img_p=img_p).delete()
else:
await Pixiv.filter(pid=pid).delete()
def gen_keyword_pic(
@ -392,6 +402,3 @@ def _check_black(img_urls: List[str], black: List[str]) -> bool:
if b in img_url:
return False
return True

View File

@ -1,79 +1,50 @@
from typing import Optional, List, Tuple
from services.db_context import db
from typing import List, Optional, Tuple
from tortoise import fields
from tortoise.contrib.postgres.functions import Random
from services.db_context import Model
class OmegaPixivIllusts(db.Model):
__tablename__ = "omega_pixiv_illusts"
__table_args__ = {'extend_existing': True}
class OmegaPixivIllusts(Model):
id = db.Column(db.Integer(), primary_key=True)
pid = db.Column(db.BigInteger(), nullable=False)
uid = db.Column(db.BigInteger(), nullable=False)
title = db.Column(db.String(), nullable=False)
uname = db.Column(db.String(), nullable=False)
classified = db.Column(db.Integer(), nullable=False)
nsfw_tag = db.Column(db.Integer(), nullable=False)
width = db.Column(db.Integer(), nullable=False)
height = db.Column(db.Integer(), nullable=False)
tags = db.Column(db.String(), nullable=False)
url = db.Column(db.String(), nullable=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
pid = fields.BigIntField()
"""pid"""
uid = fields.BigIntField()
"""uid"""
title = fields.CharField(255)
"""标题"""
uname = fields.CharField(255)
"""画师名称"""
classified = fields.IntField()
"""标记标签, 0=未标记, 1=已人工标记或从可信已标记来源获取"""
nsfw_tag = fields.IntField()
"""nsfw标签,-1=未标记, 0=safe, 1=setu. 2=r18"""
width = fields.IntField()
"""宽度"""
height = fields.IntField()
"""高度"""
tags = fields.TextField()
"""tags"""
url = fields.CharField(255)
"""pixiv url链接"""
_idx1 = db.Index("omega_pixiv_illusts_idx1", "pid", "url", unique=True)
@classmethod
async def add_image_data(
cls,
pid: int,
title: str,
width: int,
height: int,
url: str,
uid: int,
uname: str,
classified: int,
nsfw_tag: int,
tags: str,
):
"""
说明:
添加图片信息
参数:
:param pid: pid
:param title: 标题
:param width: 宽度
:param height: 长度
:param url: url链接
:param uid: 作者uid
:param uname: 作者名称
:param classified: 标记标签, 0=未标记, 1=已人工标记或从可信已标记来源获取
:param nsfw_tag: nsfw标签,-1=未标记, 0=safe, 1=setu. 2=r18
:param tags: 相关tag
"""
if not await cls.check_exists(pid):
await cls.create(
pid=pid,
title=title,
width=width,
height=height,
url=url,
uid=uid,
uname=uname,
classified=classified,
nsfw_tag=nsfw_tag,
tags=tags,
)
return True
return False
class Meta:
table = "omega_pixiv_illusts"
table_description = "omega图库数据表"
unique_together = ("pid", "url")
@classmethod
async def query_images(
cls,
keywords: Optional[List[str]] = None,
uid: Optional[int] = None,
pid: Optional[int] = None,
nsfw_tag: Optional[int] = 0,
num: int = 100
) -> List[Optional["OmegaPixivIllusts"]]:
cls,
keywords: Optional[List[str]] = None,
uid: Optional[int] = None,
pid: Optional[int] = None,
nsfw_tag: Optional[int] = 0,
num: int = 100,
) -> List["OmegaPixivIllusts"]:
"""
说明:
查找符合条件的图片
@ -84,66 +55,38 @@ class OmegaPixivIllusts(db.Model):
:param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18
:param num: 获取图片数量
"""
if not num:
return []
query = cls
if nsfw_tag is not None:
query = cls.query.where(cls.nsfw_tag == nsfw_tag)
else:
query = cls.query
query = cls.filter(nsfw_tag=nsfw_tag)
if keywords:
for keyword in keywords:
query = query.where(cls.tags.contains(keyword))
query = query.filter(tags__contains=keyword)
elif uid:
query = query.where(cls.uid == uid)
query = query.filter(uid=uid)
elif pid:
query = query.where(cls.uid == pid)
query = query.order_by(db.func.random()).limit(num)
return await query.gino.all()
query = query.filter(pid=pid)
query = query.annotate(rand=Random()).limit(num)
return await query.all() # type: ignore
@classmethod
async def check_exists(cls, pid: int) -> bool:
"""
说明:
检测pid是否已存在
参数:
:param pid: 图片PID
"""
query = await cls.query.where(cls.pid == pid).gino.all()
return bool(query)
@classmethod
async def get_keyword_num(cls, tags: List[str] = None) -> Tuple[int, int, int]:
async def get_keyword_num(
cls, tags: Optional[List[str]] = None
) -> Tuple[int, int, int]:
"""
说明:
获取相关关键词(keyword, tag)在图库中的数量
参数:
:param tags: 关键词/Tag
"""
setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count'))
query = cls.select('count')
query = cls
if tags:
for tag in tags:
query = query.where(cls.tags.contains(tag))
count = await query.where(cls.nsfw_tag == 0).gino.first()
setu_count = await query.where(cls.nsfw_tag == 1).gino.first()
r18_count = await query.where(cls.nsfw_tag == 2).gino.first()
return count[0], setu_count[0], r18_count[0]
@classmethod
async def get_all_pid(cls) -> List[int]:
"""
说明:
获取所有图片PID
"""
data = await cls.select('pid').gino.all()
return [x[0] for x in data]
# async def test(cls, nsfw_tag: int = 1):
# if nsfw_tag is not None:
# query = cls.query.where(cls.nsfw_tag == nsfw_tag)
# else:
# query = cls.query
# query = query.where((cls.width - cls.height) < 50)
# for x in await query.gino.all():
# print(x.pid)
query = query.filter(tags__contains=tag)
else:
query = query.all()
count = await query.filter(nsfw_tag=0).count()
setu_count = await query.filter(nsfw_tag=1).count()
r18_count = await query.filter(nsfw_tag=2).count()
return count, setu_count, r18_count

View File

@ -1,105 +1,43 @@
from typing import Optional, List
from services.db_context import db
from typing import List, Optional, Tuple
from tortoise import fields
from tortoise.contrib.postgres.functions import Random
from services.db_context import Model
class Pixiv(db.Model):
__tablename__ = "pixiv"
__table_args__ = {'extend_existing': True}
class Pixiv(Model):
id = db.Column(db.Integer(), primary_key=True)
pid = db.Column(db.BigInteger(), nullable=False)
title = db.Column(db.String(), nullable=False)
width = db.Column(db.Integer(), nullable=False)
height = db.Column(db.Integer(), nullable=False)
view = db.Column(db.Integer(), nullable=False)
bookmarks = db.Column(db.Integer(), nullable=False)
img_url = db.Column(db.String(), nullable=False)
img_p = db.Column(db.String(), nullable=False)
uid = db.Column(db.BigInteger(), nullable=False)
author = db.Column(db.String(), nullable=False)
is_r18 = db.Column(db.Boolean(), nullable=False)
tags = db.Column(db.String(), nullable=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
pid = fields.BigIntField()
"""pid"""
uid = fields.BigIntField()
"""uid"""
author = fields.CharField(255)
"""作者"""
title = fields.CharField(255)
"""标题"""
width = fields.IntField()
"""宽度"""
height = fields.IntField()
"""高度"""
view = fields.IntField()
"""pixiv查看数"""
bookmarks = fields.IntField()
"""收藏数"""
tags = fields.TextField()
"""tags"""
img_url = fields.CharField(255)
"""pixiv url链接"""
img_p = fields.CharField(255)
"""图片pN"""
is_r18 = fields.BooleanField()
_idx1 = db.Index("pixiv_idx1", "pid", "img_url", unique=True)
@classmethod
async def add_image_data(
cls,
pid: int,
title: str,
width: int,
height: int,
view: int,
bookmarks: int,
img_url: str,
img_p: str,
uid: int,
author: str,
tags: str,
):
"""
说明:
添加图片信息
参数:
:param pid: pid
:param title: 标题
:param width: 宽度
:param height: 长度
:param view: 被查看次数
:param bookmarks: 收藏数
:param img_url: url链接
:param img_p: 张数
:param uid: 作者uid
:param author: 作者名称
:param tags: 相关tag
"""
if not await cls.check_exists(pid, img_p):
await cls.create(
pid=pid,
title=title,
width=width,
height=height,
view=view,
bookmarks=bookmarks,
img_url=img_url,
img_p=img_p,
uid=uid,
author=author,
is_r18=True if "R-18" in tags else False,
tags=tags,
)
return True
return False
@classmethod
async def remove_image_data(cls, pid: int, img_p: str) -> bool:
"""
说明:
删除图片数据
参数:
:param pid: 图片pid
:param img_p: 图片pid的张数p0p1
"""
try:
if img_p:
await cls.delete.where(
(cls.pid == pid) & (cls.img_p == img_p)
).gino.status()
else:
await cls.delete.where(cls.pid == pid).gino.status()
return True
except Exception:
return False
@classmethod
async def get_all_pid(cls) -> List[int]:
"""
说明:
获取所有PID
"""
query = await cls.query.select("pid").gino.first()
pid = [x[0] for x in query]
return list(set(pid))
class Meta:
table = "pixiv"
table_description = "pix图库数据表"
unique_together = ("pid", "img_url", "img_p")
# 0非r18 1r18 2混合
@classmethod
@ -109,7 +47,7 @@ class Pixiv(db.Model):
uid: Optional[int] = None,
pid: Optional[int] = None,
r18: Optional[int] = 0,
num: int = 100
num: int = 100,
) -> List[Optional["Pixiv"]]:
"""
说明:
@ -121,50 +59,37 @@ class Pixiv(db.Model):
:param r18: 是否r180非r18 1r18 2混合
:param num: 查找图片的数量
"""
if not num:
return []
query = cls
if r18 == 0:
query = cls.query.where(cls.is_r18 == False)
query = query.filter(is_r18=False)
elif r18 == 1:
query = cls.query.where(cls.is_r18 == True)
else:
query = cls.query
query = query.filter(is_r18=True)
if keywords:
for keyword in keywords:
query = query.where(cls.tags.contains(keyword))
query = query.filter(tags__contains=keyword)
elif uid:
query = query.where(cls.uid == uid)
query = query.filter(uid=uid)
elif pid:
query = query.where(cls.pid == pid)
query = query.order_by(db.func.random()).limit(num)
return await query.gino.all()
query = query.filter(pid=pid)
query = query.annotate(rand=Random()).limit(num)
return await query.all() # type: ignore
@classmethod
async def check_exists(cls, pid: int, img_p: str) -> bool:
"""
说明:
检测pid是否已存在
参数:
:param pid: 图片PID
:param img_p: 张数
"""
query = await cls.query.where(
(cls.pid == pid) & (cls.img_p == img_p)
).gino.all()
return bool(query)
@classmethod
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int":
async def get_keyword_num(cls, tags: Optional[List[str]] = None) -> Tuple[int, int]:
"""
说明:
获取相关关键词(keyword, tag)在图库中的数量
参数:
:param tags: 关键词/Tag
"""
setattr(Pixiv, 'count', db.func.count(cls.pid).label('count'))
query = cls.select('count')
query = cls
if tags:
for tag in tags:
query = query.where(cls.tags.contains(tag))
count = await query.where(cls.is_r18 == False).gino.first()
r18_count = await query.where(cls.is_r18 == True).gino.first()
return count[0], r18_count[0]
query = query.filter(tags__contains=tag)
else:
query = query.all()
count = await query.filter(is_r18=False).count()
r18_count = await query.filter(is_r18=True).count()
return count, r18_count

View File

@ -1,101 +1,42 @@
from services.db_context import db
from typing import Set, List
from typing import List, Set, Tuple
from tortoise import fields
from services.db_context import Model
class PixivKeywordUser(db.Model):
class PixivKeywordUser(Model):
__tablename__ = "pixiv_keyword_users"
__table_args__ = {'extend_existing': True}
__table_args__ = {"extend_existing": True}
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
keyword = db.Column(db.String(), nullable=False)
is_pass = db.Column(db.Boolean(), default=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
keyword = fields.CharField(255, unique=True)
"""关键词"""
is_pass = fields.BooleanField()
"""是否通过"""
_idx1 = db.Index("pixiv_keyword_users_idx1", "keyword", unique=True)
class Meta:
table = "pixiv_keyword_users"
table_description = "pixiv关键词数据表"
@classmethod
async def add_keyword(
cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str]
) -> bool:
"""
说明:
添加搜图的关键词
参数:
:param user_qq: qq号
:param group_id: 群号
:param keyword: 关键词
:param superusers: 是否为超级用户
"""
is_pass = True if str(user_qq) in superusers else False
if not await cls._check_keyword_exists(keyword):
await cls.create(
user_qq=user_qq, group_id=group_id, keyword=keyword, is_pass=is_pass
)
return True
return False
@classmethod
async def delete_keyword(cls, keyword: str) -> bool:
"""
说明:
删除关键词
参数:
:param keyword: 关键词
"""
if await cls._check_keyword_exists(keyword):
query = cls.query.where(cls.keyword == keyword).with_for_update()
query = await query.gino.first()
await query.delete()
return True
return False
@classmethod
async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int":
"""
说明:
通过或禁用关键词
参数:
:param keyword: 关键词
:param is_pass: 通过状态
"""
if await cls._check_keyword_exists(keyword):
query = cls.query.where(cls.keyword == keyword).with_for_update()
query = await query.gino.first()
await query.update(
is_pass=is_pass,
).apply()
return query.user_qq, query.group_id
return 0, 0
@classmethod
async def get_all_user_dict(cls) -> dict:
"""
说明:
获取关键词数据库各个用户贡献的关键词字典
"""
tmp = {}
query = await cls.query.gino.all()
for user in query:
if not tmp.get(user.user_qq):
tmp[user.user_qq] = {"keyword": []}
tmp[user.user_qq]["keyword"].append(user.keyword)
return tmp
@classmethod
async def get_current_keyword(cls) -> "List[str], List[str]":
async def get_current_keyword(cls) -> Tuple[List[str], List[str]]:
"""
说明:
获取当前通过与未通过的关键词
"""
pass_keyword = []
not_pass_keyword = []
query = await cls.query.gino.all()
for user in query:
if user.is_pass:
pass_keyword.append(user.keyword)
for data in await cls.all().values_list("keyword", "is_pass"):
if data[1]:
pass_keyword.append(data[0])
else:
not_pass_keyword.append(user.keyword)
not_pass_keyword.append(data[0])
return pass_keyword, not_pass_keyword
@classmethod
@ -105,23 +46,9 @@ class PixivKeywordUser(db.Model):
获取黑名单PID
"""
black_pid = []
query = await cls.query.where(cls.user_qq == 114514).gino.all()
for image in query:
black_pid.append(image.keyword[6:])
keyword_list = await cls.filter(user_qq=114514).values_list(
"keyword", flat=True
)
for image in keyword_list:
black_pid.append(image[6:])
return black_pid
@classmethod
async def _check_keyword_exists(cls, keyword: str) -> bool:
"""
说明:
检测关键词是否已存在
参数:
:param keyword: 关键词
"""
current_keyword = []
query = await cls.query.gino.all()
for user in query:
current_keyword.append(user.keyword)
if keyword in current_keyword:
return True
return False

View File

@ -1,14 +1,17 @@
from nonebot import on_command
from utils.utils import is_number
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from nonebot.params import CommandArg, Command
from typing import Tuple
from ._data_source import uid_pid_exists
from ._model.pixiv_keyword_user import PixivKeywordUser
from ._model.pixiv import Pixiv
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from services.log import logger
from utils.utils import is_number
from ._data_source import uid_pid_exists
from ._model.pixiv import Pixiv
from ._model.pixiv_keyword_user import PixivKeywordUser
__zx_plugin_name__ = "PIX关键词/UID/PID添加管理 [Superuser]"
__plugin_usage__ = """
usage
@ -46,9 +49,16 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
if msg:
if await PixivKeywordUser.add_keyword(
event.user_id, group_id, msg, bot.config.superusers
):
# if await PixivKeywordUser.add_keyword(
# event.user_id, group_id, msg, bot.config.superusers
# ):
if not await PixivKeywordUser.exists(keyword=msg):
await PixivKeywordUser.create(
user_qq=event.user_id,
group_id=group_id,
keyword=msg,
is_pass=str(event.user_id) in bot.config.superusers,
)
await add_keyword.send(
f"已成功添加pixiv搜图关键词{msg},请等待管理员通过该关键词!", at_sender=True
)
@ -63,7 +73,12 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
@add_uid_pid.handle()
async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
async def _(
bot: Bot,
event: MessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
):
msg = arg.extract_plain_text().strip()
exists_flag = True
if msg.find("-f") != -1 and str(event.user_id) in bot.config.superusers:
@ -77,16 +92,23 @@ async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg
msg = f"uid:{msg}"
else:
msg = f"pid:{msg}"
if await Pixiv.check_exists(int(msg[4:]), "p0"):
if await Pixiv.get_or_none(pid=int(msg[4:]), img_p="p0"):
await add_uid_pid.finish(f"该PID{msg[4:]}已存在...", at_sender=True)
if not await uid_pid_exists(msg) and exists_flag:
await add_uid_pid.finish("画师或作品不存在或搜索正在CD请稍等...", at_sender=True)
group_id = -1
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
if await PixivKeywordUser.add_keyword(
event.user_id, group_id, msg, bot.config.superusers
):
# if await PixivKeywordUser.add_keyword(
# event.user_id, group_id, msg, bot.config.superusers
# ):
if not await PixivKeywordUser.exists(keyword=msg):
await PixivKeywordUser.create(
user_qq=event.user_id,
group_id=group_id,
keyword=msg,
is_pass=str(event.user_id) in bot.config.superusers,
)
await add_uid_pid.send(
f"已成功添加pixiv搜图UID/PID{msg[4:]},请等待管理员通过!", at_sender=True
)
@ -106,12 +128,21 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
pid = pid[: pid.find("p")]
if not is_number(pid):
await add_black_pid.finish("PID必须全部是数字", at_sender=True)
if await PixivKeywordUser.add_keyword(
114514,
114514,
f"black:{pid}{f'_p{img_p}' if img_p else ''}",
bot.config.superusers,
# if await PixivKeywordUser.add_keyword(
# 114514,
# 114514,
# f"black:{pid}{f'_p{img_p}' if img_p else ''}",
# bot.config.superusers,
# ):
if not await PixivKeywordUser.exists(
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}"
):
await PixivKeywordUser.create(
user_qq=114514,
group_id=114514,
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}",
is_pass=str(event.user_id) in bot.config.superusers,
)
await add_black_pid.send(f"已添加PID{pid} 至黑名单中...")
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"

View File

@ -1,15 +1,17 @@
from nonebot import on_command
from utils.utils import is_number
from utils.message_builder import at
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from nonebot.params import CommandArg, Command
from nonebot.permission import SUPERUSER
from ._data_source import remove_image
from ._model.pixiv_keyword_user import PixivKeywordUser
from ._model.pixiv import Pixiv
from typing import Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from services.log import logger
from utils.message_builder import at
from utils.utils import is_number
from ._data_source import remove_image
from ._model.pixiv import Pixiv
from ._model.pixiv_keyword_user import PixivKeywordUser
__zx_plugin_name__ = "PIX关键词/UID/PID删除管理 [Superuser]"
__plugin_usage__ = """
@ -60,7 +62,8 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = f"uid:{msg}"
if msg.lower().startswith("pid"):
msg = "pid:" + msg.replace("pid", "").replace(":", "")
if await PixivKeywordUser.delete_keyword(msg):
if data := await PixivKeywordUser.get_or_none(keyword=msg):
await data.delete()
await del_keyword.send(f"删除搜图关键词/UID{msg} 成功...")
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
@ -97,22 +100,31 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
if await remove_image(int(pid), img_p):
msg += f'{pid}{f"_p{img_p}" if img_p else ""}'
if flag:
if await PixivKeywordUser.add_keyword(
114514,
114514,
f"black:{pid}{f'_p{img_p}' if img_p else ''}",
bot.config.superusers,
# if await PixivKeywordUser.add_keyword(
# 114514,
# 114514,
# f"black:{pid}{f'_p{img_p}' if img_p else ''}",
# bot.config.superusers,
# ):
if await PixivKeywordUser.exists(
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}"
):
await PixivKeywordUser.create(
user_qq=114514,
group_id=114514,
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}",
is_pass=False,
)
black_pid += f'{pid}{f"_p{img_p}" if img_p else ""}'
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除了PIX图片 PID:{pid}{f'_p{img_p}' if img_p else ''}"
)
else:
await del_pic.send(
f"PIX:删除pid{pid}{f'_p{img_p}' if img_p else ''} 失败.."
)
# else:
# await del_pic.send(
# f"PIX:删除pid{pid}{f'_p{img_p}' if img_p else ''} 失败.."
# )
else:
await del_pic.send(
f"PIX:图片pix{pid}{f'_p{img_p}' if img_p else ''} 不存在...无法删除.."
@ -127,7 +139,12 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
@pass_keyword.handle()
async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
async def _(
bot: Bot,
event: MessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
):
tmp = {"group": {}, "private": {}}
msg = arg.extract_plain_text().strip()
if not msg:
@ -145,7 +162,13 @@ async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg
if not is_number(x[4:]):
await pass_keyword.send(f"UID/PID{x} 非全数字,跳过该关键词...")
continue
user_id, group_id = await PixivKeywordUser.set_keyword_pass(x, flag)
data = await PixivKeywordUser.get_or_none(keyword=x)
user_id = 0
group_id = 0
if data:
data.is_pass = flag
await data.save(update_fields=["is_pass"])
user_id, group_id = data.user_qq, data.group_id
if not user_id:
await pass_keyword.send(f"未找到关键词/UID{x},请检查关键词/UID是否存在...")
continue
@ -163,7 +186,7 @@ async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg
else:
tmp["group"][group_id][user_id]["keyword"].append(x)
msg = " ".join(msg)
await pass_keyword.send(f'已成功{cmd[0][:2]}搜图关键词:{msg}....')
await pass_keyword.send(f"已成功{cmd[0][:2]}搜图关键词:{msg}....")
for user in tmp["private"]:
x = "".join(tmp["private"][user]["keyword"])
await bot.send_private_msg(

View File

@ -1,11 +1,13 @@
from nonebot import on_command
from utils.message_builder import image
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message
from ._data_source import gen_keyword_pic, get_keyword_num
from ._model.pixiv_keyword_user import PixivKeywordUser
from nonebot.params import CommandArg
import asyncio
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
from nonebot.params import CommandArg
from utils.message_builder import image
from ._data_source import gen_keyword_pic, get_keyword_num
from ._model.pixiv_keyword_user import PixivKeywordUser
__zx_plugin_name__ = "查看pix图库"
__plugin_usage__ = """
@ -35,12 +37,12 @@ show_pix = on_command("查看pix图库", priority=1, block=True)
@my_keyword.handle()
async def _(event: MessageEvent):
data = await PixivKeywordUser.get_all_user_dict()
if data.get(event.user_id) is None or not data[event.user_id]["keyword"]:
await my_keyword.finish("您目前没有提供任何Pixiv搜图关键字...", at_sender=True)
await my_keyword.send(
f"您目前提供的如下关键字:\n\t" + "".join(data[event.user_id]["keyword"])
data = await PixivKeywordUser.filter(user_qq=event.user_id).values_list(
"keyword", flat=True
)
if not data:
await my_keyword.finish("您目前没有提供任何Pixiv搜图关键字...", at_sender=True)
await my_keyword.send(f"您目前提供的如下关键字:\n\t" + "".join(data))
@show_keyword.handle()

Some files were not shown because too many files have changed in this diff Show More