update code

This commit is contained in:
HibiKier 2021-09-05 02:21:38 +08:00
parent 21a5feda43
commit 7afb099c12
84 changed files with 3377 additions and 1404 deletions

264
README.md
View File

@ -29,7 +29,6 @@
- [x] 图灵AI会把'你'等关键字替换为你的昵称),且带有 [AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus),够味
- [x] 签到/我的签到/好感度排行/好感度总排行(影响色图概率和开箱次数,支持配置)
- [x] 发送某文件夹下的随机图片(支持自定义,默认:美图,萝莉,壁纸)
- [x] 尝试搜索不色的图片 ↑↑
- [x] 色图(这不是基础功能嘛喂)
- [x] coser
- [x] 黑白草图生成器
@ -47,6 +46,7 @@
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
- [x] 金币红包
- [x] 微博热搜
- [x] B站主播/UP/番剧订阅
- [x] pil对图片的一些操作
- [x] BUFF饰品底价查询需要session
@ -69,7 +69,7 @@
- [x] 我的信息(只是为了看看什么时候入群)
- [x] 更新信息(如果继续更新的话)
- [x] go-cqhttp最新版下载和上传不需要请删除
- [x] 撤回 (使用[nonebot-plugin-withdraw](https://github.com/MeetWq/nonebot-plugin-withdraw)插件)
- [x] 撤回
- [x] 滴滴滴-(用户对超级用户发送消息)
- [x] 金币红包/金币排行
- [x] 俄罗斯轮盘/胜场排行/败场排行/欧洲人排行/慈善家排行
@ -89,9 +89,10 @@
- [x] 上传图片/连续上传图片 (上传图片至指定图库)
- [x] 移动图片 (同上)
- [x] 删除图片 (同上)
- [x] 群内B站订阅
### 已实现的超级用户功能
- [x] 添加/删除管理(是真寻的管理员权限,不是群管理员)
- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
- [x] 开启/关闭指定群的广播通知
- [x] 广播
- [x] 自检(检查系统状态)
@ -103,7 +104,6 @@
- [x] 节日红包发送
- [x] 修改群权限
- [x] ban
- [x] 添加/删除群白名单
- [x] 更新色图
- [x] 更新价格/更加图片csgo开箱
- [x] 重载原神/方舟/赛马娘/坎公骑冠剑卡池
@ -111,9 +111,10 @@
- [x] PIX相关操作
- [x] 检查更新真寻
- [x] 重启
- [x] 添加/删除群白名单
- [x] 添加/删除/查看群白名单
- [x] 功能开关(更多设置)
- [x] 功能状态
- [x] b了
#### 超级用户的被动技能
- [x] 邀请入群提醒(别人邀请真寻入群)
@ -123,7 +124,7 @@
- [x] 进群欢迎消息
- [x] 群早晚安
- [x] 每日开箱重置提醒
- [x] b站转发解析解析b站分享信息支持bvbilibili链接b站手机端转发卡片cvb23.tv
- [x] b站转发解析解析b站分享信息支持bvbilibili链接b站手机端转发卡片cvb23.tv且5分钟内不解析相同url
- [x] 丢人爬(爬表情包)
- [x] epic通知每日发送epic免费游戏链接
- [x] 原神黄历提醒
@ -201,6 +202,8 @@
| 添加pix关键词/uid/pid | 添加pix关键词/uid/pid *[关键词/uid/pid]| 添加关键词或uid或pid用于下次搜索关键词搜索相关taguid会收录作者下收藏符合标准的作品pid收录单张作品<br>示例添加pix关键词 原神<br> 添加pixuid 123441<br>添加pixpid 2748937|
| 查看pix图库 | 查看pix图库 [tags] | 查看已收录的tag相关图片数量<br>示例查看pix图库 原神 莫娜
|显示pix关键词 | 显示pix关键词 | 查看已收录的所有关键词/UID/PID
| b了 | b了 [at] | 使真寻完全忽略一个用户的所有信息
| B站订阅 | 添加订阅 [主播/UP/番剧] [id/链接/番名] / 删除订阅 [id] / 查看订阅 | 可以通过直接间链接或主播间id添加订阅主播开播提醒动态和投稿可以通过番名番剧的id或者番剧链接添加番剧订阅(是番剧idmd开头不是集数id,ep开头的)更新, 可以通过UP个人id或UP主页链接订阅UP动态和投稿
### 管理员功能
@ -218,6 +221,7 @@
| 上传图片 | 6 | 上传图片 \[图库] \[图片]... | 上传图片至指定图库,虽然并不打算开放给群员,但还是写了,支持批量图片<br>示例:上传图片 美图 \[图片]..
| 删除图片 | 6 | 删除图片 [图库] \[图片id] | 通过指定本地图片id来删除指定图库的图片<br>示例:删除图片 美图 1
| 移动图片 | 6 | 移动图片 \[移出的图库] \[移入的图库] \[图片id] | 移动指定图库中的图片到指定的新图库中移入的图片id更改为移入图库的最后一位移除的图库中原本图片的id又最后一位图片替代<br>示例:移动图片 美图 萝莉 22
|B站订阅 | 5 | 功能同上,就是在群中有权限限制 | 略
### 超级用户功能
@ -250,225 +254,12 @@
|pix检测更新 | pix检测更新 [update]? | 检测从未更新过的pid或uid-update参数将在检测后直接更新未更新过的pid或uid<br>示例pix检测更新 update
| 检查更新真寻 | 检查更新真寻 | 不再需要麻烦的clone第一步
| 关闭功能 | 关闭[功能] [group/private]/*[群号]? | 关闭色图:维护功能(关闭总开关)<br>关闭色图 g在群内限制功能<br>关闭色图 p在私聊限制功能<br>关闭色图 1234678禁用12345678的色图功能
| 群白名单 | 添加/删除群白名单 *[群号] | 白名单内的群不会受到 维护 限制
| 群白名单 | 添加/删除群白名单 *[群号] / 查看群白名单 | 白名单内的群不会受到 维护 限制
| 功能状态 | 功能状态 | 查看功能开关状态
| pix | pix [-s/-r] [keyword] | 可以通过pix -s 查看图库的涩图pix -r查看图库的r18图支持搜索当然pix图库只区分了r18和非r18如果-s查询到不色的图也问题不大
</details>
## 部分功能展示
<details>
<summary>部分功能展示及说明</summary>
### 帮助以及开关(功能控制)
群帮助将会在功能左侧展示该功能的开关,带有√或×的功能代表可以开关<br>
此插件使用 [nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager) 并魔改一点实现
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/help.PNG)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/kg1.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/kg3.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/kg2.png)
<br>
如果你希望某功能暂时停用<br>
私聊发送 npm block xx xx=功能名)来锁定<br>
使用npm unblock xx 进行解锁
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/ocgn.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/ocgn2.png)
### 签到
普普通通的签到,设置影响开箱次数和涩图触发成功的概率(可配置)<br>
开箱次数 = 初始开箱数量 + 好感度 / 3<br>
金币 = random.randint(100) + random.randint(好感度)【好感度获取的金币不会超过200】
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/sign.png)
### 黑白草图
整活生成器(从未设想的道路)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/w2b.png)
### 发送文件夹下随机图片
提供了 美图589获取该图库下文件名589.jpg的图片方法图库内图片名称需要有序如:0.jpg,1.jpg....
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/send_img.png)
### 色图
send_setu/check_setu_hash.py文件用于记录涩图hash和检测文件名是否连贯例如0.jpg, 1.jpg....
### 开箱csgo模拟开箱
我的开箱/群开箱统计/我的金色 功能是对开箱数据的统计展示 <br>
目前支持的武器箱(数据已备好):
* 狂牙大行动武器箱
* 突围大行动武器箱
* 命悬一线武器箱
* 裂空武器箱
* 光谱武器箱
<br>
BUFF账号可能会因为短时间内访问api次数过多被禁止访问api
如果是第一次启动请先使用命令 “更新价格”, “更新图片” 需要配置cookie如果经常超时请设置代理配置文件中的 buff_proxy!<br>
如果需要配置新的箱子,请在.config.py中配置好该箱子中的皮肤且列表名是箱子名称的大写拼音<br>
示例:光谱武器箱 GUANGPU_CASE_KNIFE,GUANGPU_CASE_RED...后面的颜色代表皮肤品质
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/kaixiang.png)
### BUFF皮肤底价查询
需要配置cookie<br>
如果经常超时请设置代理,配置文件中的 buff_proxy!
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/buff.png)
### coser
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/coser.png)
### 鸡汤/语录
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/jitang.png)
### 骂我
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/mawo.png)
### 鲁迅说
此插件使用 [nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/luxun.png)
### 假消息
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/jiaxiaoxi.png)
### 商店系统
商店内的道具支持自定义,但需要写触发后的效果...整不出活,到头来也就增加好感度概率的商品
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/shop.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/daoju.png)
### 昵称系统
养成方法第一步让可爱的小真寻叫自己昵称替换ai中的'你'等等)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/nicheng1.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/nicheng2.png)
### 抽卡8种手游的抽卡
已单独分离并上传至nb2商店不再放图片了项目地址[nonebot_plugin_gamedraw](https://github.com/HibiKier/nonebot_plugin_gamedraw)
### 我有一个朋友...
使用大佬的插件 [cappuccilo_plugins](https://github.com/pcrbot/cappuccilo_plugins#%E7%94%9F%E6%88%90%E5%99%A8%E6%8F%92%E4%BB%B6)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/one_firend.png)
### 原神黄历/今日素材/丘丘语翻译/地图资源查询
使用大佬的插件 [Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)
### 对图片的操作
只是一些简单对图片操作(娱乐整活)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/tupian.png)
### 识番
使用大佬的插件 [XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/shifan.png)
### 识图
使用nb2商店插件 [nonebot_plugin_picsearcher](https://github.com/synodriver/nonebot_plugin_picsearcher) (可配置图片返回的最大数量)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/shitu.png)
### epic免费游戏
访问rsshub获取数据解析<br>可以不玩,不能没有
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/epic.png)
### P站排行/搜图
访问rsshub获取数据解析
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/p_rank.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/p_sou.png)
### 翻译
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/fanyi.png)
### 自定义群欢迎消息
关键字 [at] 判断是否艾特入群用户
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/qhyxx.png)
### 查看当前群欢迎消息
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/qunhuanying.png)
### 自检
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/check.png)
### .ban/.unban
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/ban.png)
### 查看被动技能(被动技能除复读外都提供了开关)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/beidong.png)
### 自我介绍
只是一段简单自我介绍,但是,还是想放上来
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/jieshao.png)
### 我的信息/我的权限
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/info.png)
### 金币红包
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/redbag0.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/redbag1.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/redbag2.png)
### 俄罗斯轮盘
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/russian0.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/russian1.png)
![](https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/docs/russian2.png)
<br>
### 其他
点歌:使用 [nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) 插件<br>
<br><br>
## 其他功能请自己试一试
</details>
## 部署
@ -672,6 +463,36 @@ python bot.py
## 更新
### 2021/9/5
* 添加配置PIX_IMAGE_SIZE调整PIX下载图片大小当设置的图片404时改为原图
* 新增配置DEFAULT_GROUP_LEVEL默认群等级
* 新增超级用户功能 super ban将屏蔽被ban用户的所有消息指令b了
* b站转发解析支持纯BV号解析且五分钟内不会解析相同url
* 俄罗斯轮盘新增 连胜/最高连胜/连败/最高连败 纪录,新增 最高连胜排行榜/最高连败排行榜
* 增加扩展图库 OmegaPixivIllusts不想自己找图的人福音[Ailitonia](https://github.com/Ailitonia) 佬的高质量精品手筛图库)([传送门](https://github.com/Ailitonia/omega-miya/blob/master/archive_data/db_pixiv.7z) )可以手动导入图库也可以将解压文件放在bot.py同级目录重启bot
* 增加配置PIX_OMEGA_PIXIV_RATIOPIX功能发送PIX图库和扩展图库OmegaPixivIllusts图片的比例如果没有使用扩展图库OmegaPixivIllusts请设置为(10, 0)
* 增加配置WITHDRAW_PIX_TIME用于配置在开关PIX图片在群私聊的自动撤回
* 上传图库cases 开箱 也可以连抽(未更新过没有价格)
* 新增命令 查看群白名单
* plugins2info_dict新增键"default_status",设置加入新群时功能的默认开关状态
* 增加配置plugins2exists_dict可自定义是否阻塞某命令同时触发多次
* 增加配置plugins2cd_dict可自定义为命令添加cd
* 新增B站订阅直播/番剧/UP[测试],提供命令:添加订阅 [主播/UP/番剧] [id/链接/番名],删除订阅 [id],查看订阅
* 优化pix和色图的数据库查询
* 触发已关闭的功能的正则时不再触发ai
* 更换coser API
* PIX搜索pid功能在群聊无法搜索PIX图库的r18和OmegaPixivIllusts的r15以及r18超级用户除外
* PIX单次搜索的图片张数超级用户限制为至多30张普通用户10张
* PIX超级用户新增-s-r可以通过pix -s 查看图库的涩图pix -r查看图库的r18图支持搜索当然pix图库只区分了r18和非r18如果-s查询到不色的图也问题不大
* 优化P站排行和搜图现在需要艾特改为使用HIBIAPI在群内时将使用合并消息群聊搜图会屏蔽R-18
* win10下playwright相关功能无法使用但是不再需要删除文件
* 签到大改,优化签到方式与逻辑,改为图片形式发送,有概率额外获得随机道具(好感度有加成)
* 修改撤回功能,改为回复撤回,回复发送撤回
* 更改logging为loguru
* 删除了 发送图片 中的 [N]张图[keyword] 功能
* 修复私聊 关闭[功能] 默认不为 全部 而要添加参数 a
* 修复0权限用户可以修改禁言检测相关设置
### 2021/8/17
* 新增配置CHECK_NOTICE_INFO_CD修改群权限个人权限检测各种检测的提示消息cd
@ -859,3 +680,4 @@ python bot.py
[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)
[nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says)
[AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus)
[omega-miya](https://github.com/Ailitonia/omega-miya)

1
__version__ Normal file
View File

@ -0,0 +1 @@
__version__: v0.0.4.0

View File

@ -1,5 +1,7 @@
from typing import List, Optional, Tuple
from services.service_config import TL_M_KEY, SYSTEM_M_PROXY, ALAPI_M_TOKEN
from .path_config import DATA_PATH
from pathlib import Path
try:
import ujson as json
@ -11,7 +13,7 @@ except ModuleNotFoundError:
USE_CONFIG_FILE: bool = False
# 回复消息名称
NICKNAME: str = '小真寻'
NICKNAME: str = "小真寻"
# API KEY必要
RSSHUBAPP: str = "https://rsshub.app" # rsshub
@ -41,6 +43,9 @@ IMAGE_DIR_LIST: List[str] = ["美图", "萝莉", "壁纸"]
# 对被ban用户发送的消息
BAN_RESULT: str = "才不会给你发消息."
# PIX图库下载的画质 可能的值original原图master缩略图加快发送速度
PIX_IMAGE_SIZE: str = "master"
# 插件配置
MAXINFO_REIMU: int = 7 # 上车(reimu)功能查找目的地的最大数
@ -51,6 +56,11 @@ MAXINFO_GROUP_ANIME: int = 5 # 群搜索动漫返回的最大数量
MAX_FIND_IMG_COUNT: int = 3 # 识图最大返回数
# 参1延迟撤回色图时间(秒)0 为关闭 | 参2监控聊天类型0(私聊) 1(群聊) 2(群聊+私聊)
WITHDRAW_SETU_TIME: Tuple[int, int] = (0, 1)
# 参1延迟撤回PIX图片时间(秒)0 为关闭 | 参2监控聊天类型0(私聊) 1(群聊) 2(群聊+私聊)
WITHDRAW_PIX_TIME: Tuple[int, int] = (0, 1)
# PIX图库 与 额外图库OmegaPixivIllusts 混合搜索的比例 参1PIX图库 参2OmegaPixivIllusts扩展图库没有此图库请设置为0
PIX_OMEGA_PIXIV_RATIO: Tuple[int, int] = (10, 0)
# 各种卡池的开关
PRTS_FLAG = True # 明日方舟
@ -68,7 +78,7 @@ SEMAPHORE = 5 # 限制碧蓝航线和FGO并发数
ADMIN_DEFAULT_AUTH: int = 5 # 默认群管理员权限
MAX_SIGN_GOLD: int = 200 # 签到好感度加成额外获得的最大金币数
MAX_RUSSIAN_BET_GOLD: int = 1000 # 俄罗斯轮盘最大赌注金额
MAX_RUSSIAN_BET_GOLD: int = 1000 # 俄罗斯轮盘最大赌注金额
INITIAL_SETU_PROBABILITY: float = 0.7 # 色图概率
FUDU_PROBABILITY: float = 0.7 # 复读概率
@ -78,7 +88,7 @@ MUTE_DEFAULT_COUNT: int = 10 # 刷屏禁言默认检测次数
MUTE_DEFAULT_TIME: int = 7 # 刷屏检测默认规定时间
MUTE_DEFAULT_DURATION: int = 10 # 刷屏检测默禁言时长(分钟)
CHECK_NOTICE_INFO_CD = 300 # 群检测个人权限检测等各种检测提示信息cd
CHECK_NOTICE_INFO_CD = 300 # 群检测个人权限检测等各种检测提示信息cd
# 注:即在 MALICIOUS_CHECK_TIME 时间内触发相同命令 MALICIOUS_BAN_COUNT 将被ban MALICIOUS_BAN_TIME 分钟
MALICIOUS_BAN_TIME: int = 30 # 恶意命令触发检测触发后ban的时长分钟
@ -92,7 +102,9 @@ UPLOAD_LEVEL: int = 6 # 上传图片权限
BAN_LEVEL: int = 5 # BAN权限
OC_LEVEL: int = 2 # 开关群功能权限
MUTE_LEVEL: int = 5 # 更改禁言设置权限
MEMBER_ACTIVITY_LEVEL = 5 # 群员活跃检测设置权限
GROUP_BILIBILI_SUB_LEVEL = 5 # 群内bilibili订阅需要的权限
DEFAULT_GROUP_LEVEL = 5 # 默认群等级
# 是否开启HIBIAPI搜图功能该功能会搜索群友提交的xp
HIBIAPI_FLAG: bool = True
@ -128,79 +140,159 @@ admin_plugins_auth = {
"upload_img": UPLOAD_LEVEL,
"admin_help": 1,
"mute": MUTE_LEVEL,
"member_activity_handle": MEMBER_ACTIVITY_LEVEL,
}
# 需要cd的功能方便管理[秒]
# 自定义的功能需要cd也可以在此配置
# key模块名称
# cdcd 时长(秒)
# status此限制的开关状态
# check_type'private'/'group'/'all',限制私聊/群聊/全部
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user'用户N秒内触发1次'group'群N秒内触发1次
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑
plugins2cd_dict = {
"open_cases": {
"cd": 5,
"status": True,
"check_type": "all",
"limit_type": "user",
"rst": "着什么急啊,慢慢来!",
},
"send_setu": {
"cd": 5,
"status": True,
"check_type": "all",
"limit_type": "user",
"rst": "您冲得太快了,请稍候再冲",
},
"sign_in": {
"cd": 5,
"status": True,
"check_type": "group",
"limit_type": "user",
"rst": None,
}
}
# 用户调用阻塞(方便管理)
# 即 当用户调用此功能还未结束时
# 用发送消息阻止用户重复调用此命令直到该命令结束
# 参数同上 plugin2cd_dict
plugins2exists_dict = {
"send_setu": {
"status": False,
"check_type": "all",
"limit_type": "user",
"rst": "您有色图正在处理,请稍等.....",
},
"pixiv": {
"status": True,
"check_type": "all",
"limit_type": "user",
"rst": "P站排行榜或搜图正在搜索请不要重复触发命令...",
},
"pix": {
"status": True,
"check_type": "all",
"limit_type": "user",
"rst": "您有PIX图片正在处理请稍等...",
}
}
# 模块与对应命令和对应群权限
# 用于生成帮助图片 和 开关功能
# key模块名称
# level需要的群等级
# default_status加入群时功能的默认开关状态
# cmd关闭[cmd] 都会触发命令 关闭对应功能cmd列表第一个词为统计的功能名称
plugins2info_dict = {
"sign_in": {"level": 5, "cmd": ["签到"]},
"send_img": {"level": 5, "cmd": ["发送图片", "发图", "萝莉", "美图", "壁纸"]},
"send_setu": {"level": 9, "cmd": ["色图", "涩图", "瑟图", "查色图"]},
"white2black": {"level": 5, "cmd": ["黑白图", "黑白草图"]},
"coser": {"level": 9, "cmd": ["coser", "cos"]},
"quotations": {"level": 5, "cmd": ["语录"]},
"jitang": {"level": 5, "cmd": ["鸡汤"]},
"send_dinggong_voice": {"level": 5, "cmd": ["骂我", "骂老子", "骂劳资"]},
"open_cases": {"level": 5, "cmd": ["开箱", "我的开箱", "群开箱统计", "我的金色"]},
"luxun": {"level": 5, "cmd": ["鲁迅说", "鲁迅说过"]},
"fake_msg": {"level": 5, "cmd": ["假消息"]},
"buy": {"level": 5, "cmd": ["购买", "购买道具"]},
"my_gold": {"level": 5, "cmd": ["我的金币"]},
"my_props": {"level": 5, "cmd": ["我的道具"]},
"shop_handle": {"level": 5, "cmd": ["商店"]},
"update_pic": {"level": 5, "cmd": ["图片", "操作图片", "修改图片"]},
"search_buff_skin_price": {"level": 5, "cmd": ["查询皮肤"]},
"weather": {"level": 5, "cmd": ["天气", "查询天气", "天气查询"]},
"yiqing": {"level": 5, "cmd": ["疫情", "疫情查询", "查询疫情"]},
"what_anime": {"level": 5, "cmd": ["识番"]},
"search_anime": {"level": 5, "cmd": ["搜番"]},
"songpicker2": {"level": 5, "cmd": ["点歌"]},
"epic": {"level": 5, "cmd": ["epic"]},
"pixiv": {"level": 9, "cmd": ["pixiv", "p站排行", "搜图"]},
"poke": {"level": 5, "cmd": ["戳一戳", "拍一拍"]},
"sign_in": {"level": 5, "default_status": True, "cmd": ["签到"]},
"send_img": {
"level": 5,
"default_status": True,
"cmd": ["发送图片", "发图", "萝莉", "美图", "壁纸"],
},
"send_setu": {"level": 9, "default_status": True, "cmd": ["色图", "涩图", "瑟图", "查色图"]},
"white2black": {"level": 5, "default_status": True, "cmd": ["黑白图", "黑白草图"]},
"coser": {"level": 9, "default_status": True, "cmd": ["coser", "cos"]},
"quotations": {"level": 5, "default_status": True, "cmd": ["语录"]},
"jitang": {"level": 5, "default_status": True, "cmd": ["鸡汤"]},
"send_dinggong_voice": {
"level": 5,
"default_status": True,
"cmd": ["骂我", "骂老子", "骂劳资"],
},
"open_cases": {
"level": 5,
"default_status": True,
"cmd": ["开箱", "我的开箱", "群开箱统计", "我的金色"],
},
"luxun": {"level": 5, "default_status": True, "cmd": ["鲁迅说", "鲁迅说过"]},
"fake_msg": {"level": 5, "default_status": True, "cmd": ["假消息"]},
"buy": {"level": 5, "default_status": True, "cmd": ["购买", "购买道具"]},
"my_gold": {"level": 5, "default_status": True, "cmd": ["我的金币"]},
"my_props": {"level": 5, "default_status": True, "cmd": ["我的道具"]},
"shop_handle": {"level": 5, "default_status": True, "cmd": ["商店"]},
"update_pic": {"level": 5, "default_status": True, "cmd": ["图片", "操作图片", "修改图片"]},
"search_buff_skin_price": {"level": 5, "default_status": True, "cmd": ["查询皮肤"]},
"weather": {"level": 5, "default_status": True, "cmd": ["天气", "查询天气", "天气查询"]},
"yiqing": {"level": 5, "default_status": True, "cmd": ["疫情", "疫情查询", "查询疫情"]},
"what_anime": {"level": 5, "default_status": True, "cmd": ["识番"]},
"search_anime": {"level": 5, "default_status": True, "cmd": ["搜番"]},
"songpicker2": {"level": 5, "default_status": True, "cmd": ["点歌"]},
"epic": {"level": 5, "default_status": True, "cmd": ["epic"]},
"pixiv": {"level": 9, "default_status": True, "cmd": ["pixiv", "p站排行", "搜图"]},
"poke": {"level": 5, "default_status": True, "cmd": ["戳一戳", "拍一拍"]},
"draw_card": {
"level": 5,
"default_status": True,
"cmd": [
"抽卡",
"游戏抽卡",
"原神抽卡",
"方舟抽卡",
"坎公骑冠剑抽卡",
"pcr抽卡",
"fgo抽卡",
"碧蓝抽卡",
"碧蓝航线抽卡",
"阴阳师抽卡",
],
},
"ai": {"level": 5, "cmd": ["ai", "Ai", "AI", "aI"]},
"one_friend": {"level": 5, "cmd": ["我有一个朋友", "我有一个朋友想问问"]},
"translate": {"level": 5, "cmd": ["翻译", "英翻", "翻英", "日翻", "翻日", "韩翻", "翻韩"]},
"nonebot_plugin_picsearcher": {"level": 5, "cmd": ["识图"]},
"almanac": {"level": 5, "cmd": ["原神黄历", "黄历"]},
"material_remind": {"level": 5, "cmd": ["今日素材", "天赋材料"]},
"qiu_qiu_translation": {"level": 5, "cmd": ["丘丘翻译", "丘丘一下", "丘丘语翻译"]},
"query_resource_points": {"level": 5, "cmd": ["原神资源查询", "原神资源列表"]},
"russian": {"level": 5, "cmd": ["俄罗斯轮盘", "俄罗斯转盘", "装弹"]},
"gold_redbag": {"level": 5, "cmd": ["塞红包", "红包", "抢红包"]},
"poetry": {"level": 5, "cmd": ["念诗", "来首诗", "念首诗"]},
"comments_163": {"level": 5, "cmd": ["到点了", "12点了", "网易云热评", "网易云评论"]},
"cover": {"level": 5, "cmd": ["b封面", "B封面"]},
"pid_search": {"level": 9, "cmd": ["p搜", "P搜"]},
"ai": {"level": 5, "default_status": True, "cmd": ["ai", "Ai", "AI", "aI"]},
"one_friend": {"level": 5, "default_status": True, "cmd": ["我有一个朋友", "我有一个朋友想问问"]},
"translate": {
"level": 5,
"default_status": True,
"cmd": ["翻译", "英翻", "翻英", "日翻", "翻日", "韩翻", "翻韩"],
},
"nonebot_plugin_picsearcher": {"level": 5, "default_status": True, "cmd": ["识图"]},
"almanac": {"level": 5, "default_status": True, "cmd": ["原神黄历", "黄历"]},
"material_remind": {"level": 5, "default_status": True, "cmd": ["今日素材", "天赋材料"]},
"qiu_qiu_translation": {
"level": 5,
"default_status": True,
"cmd": ["丘丘翻译", "丘丘一下", "丘丘语翻译"],
},
"query_resource_points": {
"level": 5,
"default_status": True,
"cmd": ["原神资源查询", "原神资源列表"],
},
"russian": {"level": 5, "default_status": True, "cmd": ["俄罗斯轮盘", "俄罗斯转盘", "装弹"]},
"gold_redbag": {"level": 5, "default_status": True, "cmd": ["塞红包", "红包", "抢红包"]},
"poetry": {"level": 5, "default_status": True, "cmd": ["念诗", "来首诗", "念首诗"]},
"comments_163": {
"level": 5,
"default_status": True,
"cmd": ["到点了", "12点了", "网易云热评", "网易云评论"],
},
"cover": {"level": 5, "default_status": True, "cmd": ["b封面", "B封面"]},
"pid_search": {"level": 9, "default_status": True, "cmd": ["p搜", "P搜"]},
"pix": {
"level": 5,
"default_status": True,
"cmd": ["pix", "PIX", "pIX", "Pix", "PIx"],
},
"wbtop": {
"level": 5,
"cmd": ['微博热搜', "微博", "wbtop"]
},
"update_info": {
"level": 5,
"cmd": ['更新信息', '更新日志']
}
"wbtop": {"level": 5, "default_status": True, "cmd": ["微博热搜", "微博", "wbtop"]},
"update_info": {"level": 5, "default_status": True, "cmd": ["更新信息", "更新日志"]},
}
if TL_M_KEY:
@ -214,6 +306,12 @@ if ALAPI_M_TOKEN:
HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI
RSSHUBAPP = RSSHUBAPP[:-1] if RSSHUBAPP[-1] == "/" else RSSHUBAPP
# plugins2info_file = Path(DATA_PATH) / 'configs' / 'plugins2info.json'
# plugins2info_file.parent.mkdir(exist_ok=True, parents=True)
#
# with open(f'{DATA_PATH}/configs/')
# 配置文件应用
# if USE_CONFIG_FILE:
# config = get_config_data()

View File

@ -60,6 +60,20 @@ class BanUser(db.Model):
await cls.unban(user_qq)
return False
@classmethod
async def is_super_ban(cls, user_qq: int) -> bool:
"""
说明
判断用户是否被ban
参数
: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
@classmethod
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
"""

249
models/bilibili_sub.py Normal file
View File

@ -0,0 +1,249 @@
from services.log import logger
from services.db_context import db
from datetime import datetime
from typing import Optional, List
class BilibiliSub(db.Model):
__tablename__ = "bilibili_sub"
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())
_idx1 = db.Index("bilibili_sub_idx1", "sub_id", "sub_type", unique=True)
@classmethod
async def add_bilibili_sub(
cls,
sub_id: int,
sub_type: str,
sub_user: str,
*,
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 sub_type: 订阅类型
:param sub_user: 订阅此条目的用户
: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():
query = (
await cls.query.where(cls.sub_id == sub_id)
.with_for_update()
.gino.first()
)
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
@classmethod
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str) -> bool:
"""
说明
删除订阅
参数
:param sub_id: 订阅名称
:param sub_user: 删除此条目的用户
"""
try:
async with db.transaction():
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
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]":
"""
说明
分类获取所有数据
"""
live_data = []
up_data = []
season_data = []
query = await cls.query.gino.all()
for x in query:
if x.sub_type == "live":
live_data.append(x)
if x.sub_type == "up":
up_data.append(x)
if x.sub_type == "season":
season_data.append(x)
return live_data, up_data, season_data

View File

@ -1,7 +1,7 @@
from datetime import datetime
from services.db_context import db
from typing import List
from typing import List, Optional
class GroupInfoUser(db.Model):
@ -13,6 +13,7 @@ class GroupInfoUser(db.Model):
belonging_group = 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())
_idx1 = db.Index("info_group_users_idx1", "user_qq", "belonging_group", unique=True)
@ -141,3 +142,33 @@ class GroupInfoUser(db.Model):
if user.nickname:
return user.nickname
return ""
@classmethod
async def get_group_member_uid(cls, user_qq: int, belonging_group: int) -> Optional[str]:
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
)
user = await query.gino.first()
_max_uid = cls.query.where((cls.user_qq == 114514) & (cls.belonging_group == 114514)).with_for_update()
_max_uid_user = await _max_uid.gino.first()
_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()
for x in all_user:
if x.uid:
return x.uid
else:
if not user:
await GroupInfoUser.add_member_info(user_qq, belonging_group, '', datetime.min)
user = await cls.query.where(
(cls.user_qq == user_qq) & (cls.belonging_group == belonging_group)
).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

View File

@ -0,0 +1,138 @@
from typing import Optional, List
from datetime import datetime
from services.db_context import db
class OmegaPixivIllusts(db.Model):
__tablename__ = "omega_pixiv_illusts"
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)
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)
created_at = db.Column(db.DateTime(timezone=True))
updated_at = db.Column(db.DateTime(timezone=True))
_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,
nsfw_tag: int,
tags: str,
created_at: datetime,
updated_at: datetime,
):
"""
说明
添加图片信息
参数
:param pid: pid
:param title: 标题
:param width: 宽度
:param height: 长度
:param url: url链接
:param uid: 作者uid
:param uname: 作者名称
:param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18
:param tags: 相关tag
:param created_at: 创建日期
:param updated_at: 更新日期
"""
if not await cls.check_exists(pid):
await cls.create(
pid=pid,
title=title,
width=width,
height=height,
url=url,
uid=uid,
uname=uname,
nsfw_tag=nsfw_tag,
tags=tags,
)
return True
return False
@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"]]:
"""
说明
查找符合条件的图片
参数
:param keywords: 关键词
:param uid: 画师uid
:param pid: 图片pid
:param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18
:param num: 获取图片数量
"""
if nsfw_tag is not None:
query = cls.query.where(cls.nsfw_tag == nsfw_tag)
else:
query = cls.query
if keywords:
for keyword in keywords:
query = query.where(cls.tags.contains(keyword))
elif uid:
query = query.where(cls.uid == uid)
elif pid:
query = query.where(cls.uid == pid)
query = query.order_by(db.func.random()).limit(num)
return await query.gino.all()
@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) -> "int, int, int":
"""
说明
获取相关关键词(keyword, tag)在图库中的数量
参数
:param tags: 关键词/Tag
"""
query = cls.query
if tags:
for tag in tags:
query = query.where(cls.tags.contains(tag))
count = len(await query.where(cls.nsfw_tag == 0).gino.all())
setu_count = len(await query.where(cls.nsfw_tag == 1).gino.all())
r18_count = len(await query.where(cls.nsfw_tag == 2).gino.all())
return count, setu_count, r18_count
@classmethod
async def get_all_pid(cls) -> List[int]:
"""
说明
获取所有图片PID
"""
data = await cls.query.gino.all()
return [x.pid for x in data]

View File

@ -1,6 +1,5 @@
from typing import Optional, List
from services.db_context import db
import asyncio
class Pixiv(db.Model):
@ -24,18 +23,19 @@ class Pixiv(db.Model):
@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,
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,
nws
):
"""
说明
@ -65,7 +65,7 @@ class Pixiv(db.Model):
img_p=img_p,
uid=uid,
author=author,
is_r18=True if 'R-18' in tags else False,
is_r18=True if "R-18" in tags else False,
tags=tags,
)
return True
@ -97,44 +97,45 @@ class Pixiv(db.Model):
说明
获取所有PID
"""
pid = []
query = await cls.query.gino.all()
for image in query:
if image.pid not in pid:
pid.append(image.pid)
return pid
query = await cls.query.select("pid").gino.first()
pid = [x[0] for x in query]
return list(set(pid))
# 0非r18 1r18 2混合
@classmethod
async def query_images(
cls,
keyword: Optional[List[str]] = None,
keywords: Optional[List[str]] = None,
uid: Optional[int] = None,
pid: Optional[int] = None,
r18: int = 0,
r18: Optional[int] = 0,
num: int = 100
) -> List[Optional["Pixiv"]]:
"""
说明
查找符合条件的图片
参数
:param keyword: 关键词
:param keywords: 关键词
:param uid: 画师uid
:param pid: 图片pid
:param r18: 是否r180非r18 1r18 2混合
:param num: 查找图片的数量
"""
if r18 == 0:
query = await cls.query.where(cls.is_r18 == False).gino.all()
query = cls.query.where(cls.is_r18 == False)
elif r18 == 1:
query = await cls.query.where(cls.is_r18 == True).gino.all()
query = cls.query.where(cls.is_r18 == True)
else:
query = await cls.query.gino.all()
if keyword:
query = [x for x in query if set(x.tags.split(',')) > set(keyword)]
query = cls.query
if keywords:
for keyword in keywords:
query = query.where(cls.tags.contains(keyword))
elif uid:
query = [x for x in query if x.uid == uid]
query = query.where(cls.uid == uid)
elif pid:
query = [x for x in query if x.pid == pid]
return query
query = query.where(cls.uid == pid)
query = query.order_by(db.func.random()).limit(num)
return await query.gino.all()
@classmethod
async def check_exists(cls, pid: int, img_p: str) -> bool:
@ -151,41 +152,18 @@ class Pixiv(db.Model):
return bool(query)
@classmethod
async def get_keyword_num(cls, keyword: List[str]) -> "int, int":
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int":
"""
说明
获取相关关键词(keyword, tag)在图库中的数量
参数
:param keyword: 关键词/Tag
:param tags: 关键词/Tag
"""
query = await cls.query.gino.all()
i = int(len(query) / 200)
mod = len(query) % 200
tasks = []
start = 0
end = 200
count = 0
r18_count = 0
for _ in range(i):
tasks.append(asyncio.ensure_future(split_query_list(query[start: end], keyword)))
start += 200
end += 200
if mod:
tasks.append(asyncio.ensure_future(split_query_list(query[end:], keyword)))
result = await asyncio.gather(*tasks)
for x, j in result:
count += x
r18_count += j
# query = [x for x in query if set(x.tags.split(',')) > set(keyword)]
# r18_count = len([x for x in query if x.is_r18])
query = cls.query
if tags:
for tag in tags:
query = cls.query.where(cls.tags.contains(tag))
count = len(await query.where(cls.is_r18 == False).gino.all())
r18_count = len(await query.where(cls.is_r18 == True).gino.all())
return count, r18_count
async def split_query_list(query: List['Pixiv'], keyword: List[str]) -> 'int, int':
return await asyncio.get_event_loop().run_in_executor(None, _split_query_list, query, keyword)
def _split_query_list(query: List['Pixiv'], keyword: List[str]) -> 'int, int':
query = [x for x in query if set(x.tags.split(',')) > set(keyword)]
r18_count = len([x for x in query if x.is_r18])
return len(query) - r18_count, r18_count

View File

@ -12,6 +12,10 @@ class RussianUser(db.Model):
fail_count = db.Column(db.Integer(), default=0)
make_money = db.Column(db.Integer(), default=0)
lose_money = db.Column(db.Integer(), default=0)
winning_streak = db.Column(db.Integer(), default=0)
losing_streak = db.Column(db.Integer(), default=0)
max_winning_streak = db.Column(db.Integer(), default=0)
max_losing_streak = db.Column(db.Integer(), default=0)
_idx1 = db.Index("russian_group_users_idx1", "user_qq", "group_id", unique=True)
@ -52,12 +56,28 @@ class RussianUser(db.Model):
if not user:
user = await cls.create(user_qq=user_qq, group_id=group_id)
if itype == "win":
_max = (
user.max_winning_streak
if user.max_winning_streak > user.winning_streak + 1
else user.winning_streak + 1
)
await user.update(
win_count=user.win_count + 1,
winning_streak=user.winning_streak + 1,
losing_streak=0,
max_winning_streak=_max
).apply()
elif itype == "lose":
_max = (
user.max_losing_streak
if user.max_losing_streak > user.losing_streak + 1
else user.losing_streak + 1
)
await user.update(
fail_count=user.fail_count + 1,
losing_streak=user.losing_streak + 1,
winning_streak=0,
max_losing_streak=_max,
).apply()
return True
except Exception:

View File

@ -72,17 +72,19 @@ class Setu(db.Model):
(cls.local_id == local_id) & (cls.is_r18 == flag)
).gino.first()
if r18 == 0:
query = await cls.query.where(cls.is_r18 == False).gino.all()
query = cls.query.where(cls.is_r18 == False)
elif r18 == 1:
query = await cls.query.where(cls.is_r18 == True).gino.all()
query = cls.query.where(cls.is_r18 == True)
else:
query = await cls.query.gino.all()
query = cls.query
if tags:
query = [x for x in query if set(x.tags.split(",")) > set(tags)]
return query
for tag in tags:
query = query.where(cls.tags.contains(tag) | cls.title.contains(tag) | cls.author.contains(tag))
query = query.order_by(db.func.random()).limit(50)
return await query.gino.all()
@classmethod
async def get_image_count(cls, r18: int = 0):
async def get_image_count(cls, r18: int = 0) -> int:
"""
说明
查询图片数量

View File

@ -41,7 +41,17 @@ class SignGroupUser(db.Model):
)
@classmethod
async def get_all_impression(cls, belonging_group: int) -> "list, list":
async def sign(cls, user: "SignGroupUser", impression: float, checkin_time_last: datetime):
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()
@classmethod
async def get_all_impression(cls, belonging_group: int) -> "list, list, list":
"""
说明
获取该群所有用户 id 及对应 好感度

View File

@ -1,22 +1,22 @@
from models.group_remind import GroupRemind
from services.log import logger
from configs.path_config import DATA_PATH
import os
import aiofiles
import aiohttp
from utils.message_builder import image
from utils.utils import get_local_proxy, get_bot
from pathlib import Path
from configs.config import plugins2info_dict
from models.group_member_info import GroupInfoUser
import time
from datetime import datetime
from services.db_context import db
from models.level_user import LevelUser
from configs.config import ADMIN_DEFAULT_AUTH
from utils.static_data import group_manager
from utils.image_utils import CreateImg
from configs.config import plugins2info_dict
import aiofiles
import aiohttp
import asyncio
import time
import os
try:
import ujson as json
@ -267,3 +267,7 @@ async def update_member_info(group_id: int) -> bool:
user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
)
return True

View File

@ -46,6 +46,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
else:
if str(event.user_id) in bot.config.superusers:
block_type = get_message_text(event.json())
block_type = block_type if block_type else 'a'
_cmd = state["_prefix"]["raw_command"].strip()
if is_number(block_type):
if not int(block_type) in [g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id))]:

View File

@ -9,17 +9,19 @@ from configs.config import NICKNAME
__plugin_name__ = '管理帮助 [Hidden]'
__plugin_usage__ = f'''管理帮助(权限等级)
1.更新群组成员列表(1)
2.功能开关 --> 指令:开启/关闭xx功能(2)
3.查看群被动技能 --> 指令:群通知状态(2)
4.自定义群欢迎 --> 指令:自定义进群欢迎消息(2)
5.将用户拉入{NICKNAME}黑名单 --> .ban/.unban(5)
6.刷屏禁言相关 --> 指令:刷屏检测设置/设置检测时间
\t\t/设置检测次数/设置禁言时长(5)
8.上传图片/连续上传图片(6)
9.移动图片(7)
10.删除图片(7)
__plugin_usage__ = f'''[权限等级]管理帮助:
[1]1.更新群组成员列表
[2]2.功能开关 --> 指令:开启/关闭xx功能
[2]3.查看群被动技能 --> 指令:群通知状态
[2]4.自定义群欢迎 --> 指令:自定义进群欢迎消息
[5]5.将用户拉入{NICKNAME}黑名单 --> .ban/.unban
[5]6.刷屏禁言相关 -> 指令:刷屏检测设置/设置检测时间
\t\t/设置检测次数/设置禁言时长
[5]7.群订阅相关 -> 指令添加订阅 [主播/up/番剧] [id/番名/链接]
\t\t/删除订阅 [id]/ 查看订阅
[6]8.上传图片/连续上传图片(6)
[7]9.移动图片(7)
[7]10.删除图片(7)
对我说 {NICKNAME}帮助 指令 获取对应详细帮助
群主与管理员默认 5 级权限
'''
@ -37,11 +39,11 @@ passive_help = '''【被动技能开关(2)
admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True)
admin_help_img = CreateImg(1000, 600, font_size=24)
admin_help_img = CreateImg(1200, 600, font_size=24)
admin_help_img.text((10, 10), __plugin_usage__)
text_img = CreateImg(450, 600, font_size=24)
text_img.text((0, 0), passive_help)
admin_help_img.paste(text_img, (650, 50))
admin_help_img.paste(text_img, (850, 50))
admin_help_img.save(IMAGE_PATH + 'admin_help_img.png')

View File

@ -52,7 +52,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
result = await get_chat_result(msg, img, event.user_id, nickname)
logger.info(
f"USER {event.user_id} GROUP {event.group_id if not isinstance(event, PrivateMessageEvent) else ''} "
f"问题:{msg}\n回答:{result}"
f"问题:{msg} ---- 回答:{result}"
)
if result:
await ai.finish(Message(result))

View File

@ -23,7 +23,6 @@ index = 0
anime_data = json.load(open(DATA_PATH + "anime.json", "r", encoding="utf8"))
# 图灵AI
async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) -> str:
global index
if index == 5:
@ -104,7 +103,9 @@ async def xie_ai(text: str, sess: ClientSession):
if data["result"] == 0:
content = data["content"]
if "菲菲" in content:
content = content.replace("菲菲", f"{NICKNAME}")
content = content.replace("菲菲", NICKNAME)
if '艳儿' in content:
content = content.replace('艳儿', NICKNAME)
if "公众号" in content:
content = ""
if "{br}" in content:

View File

@ -34,11 +34,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
if code != 200:
await wbtop.finish(data, at_sender=True)
wbtop_data = data['data']
img = await asyncio.get_event_loop().run_in_executor(None, gen_wbtop_pic, wbtop_data)
await wbtop.send(img)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询微博热搜")
if not msg:
img = await asyncio.get_event_loop().run_in_executor(None, gen_wbtop_pic, wbtop_data)
await wbtop.send(img)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询微博热搜")
if is_number(msg) and 0 < int(msg) <= 50:
url = wbtop_data[int(msg) - 1]['url']
browser = await get_browser()

View File

@ -4,9 +4,9 @@ from models.level_user import LevelUser
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent
from nonebot.adapters.cqhttp.permission import GROUP
from utils.utils import get_message_at, get_message_text, is_number
from configs.config import NICKNAME
from nonebot.permission import SUPERUSER
from services.log import logger
@ -29,6 +29,8 @@ ban = on_command(
block=True,
)
super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True)
@ban.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
@ -155,5 +157,17 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
await ban.finish('qq号必须是数字\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
@super_ban.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
qq = get_message_at(event.json())
if qq:
qq = qq[0]
user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
user_name = user['card'] if user['card'] else user['nickname']
if not await BanUser.ban(qq, 10, 99999999):
await BanUser.unban(qq)
await BanUser.ban(qq, 10, 99999999)
await ban.send(f"{user_name} 已在黑名单!预计不解封了..")
else:
await super_ban.send('需要艾特被super ban的对象..')

View File

@ -0,0 +1,198 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message
from .data_source import (
add_live_sub,
delete_sub,
add_up_sub,
add_season_sub,
get_media_id,
get_sub_status,
SubManager,
)
from models.level_user import LevelUser
from configs.config import GROUP_BILIBILI_SUB_LEVEL
from utils.utils import get_message_text, is_number, scheduler, get_bot
from models.bilibili_sub import BilibiliSub
from typing import Optional
from services.log import logger
from nonebot import Driver
import nonebot
__plugin_name__ = "B站订阅"
__plugin_usage__ = """B站订阅帮助
添加订阅 [主播/UP/番剧] [id/链接/番名]
删除订阅 [id]
查看订阅"""
add_sub = on_command("添加订阅", priority=5, block=True)
del_sub = on_command("删除订阅", priority=5, block=True)
show_sub_info = on_command('查看订阅', priority=5, block=True)
driver: Driver = nonebot.get_driver()
sub_manager: Optional[SubManager] = None
@driver.on_startup
async def _():
global sub_manager
sub_manager = SubManager()
@add_sub.args_parser
async def _(bot: Bot, event: MessageEvent, state: T_State):
season_data = state["season_data"]
msg = get_message_text(event.json())
if not is_number(msg) or int(msg) < 1 or int(msg) > len(season_data):
await add_sub.reject("Id必须为数字且在范围内请重新输入...")
state["id"] = season_data[int(msg) - 1]["media_id"]
@add_sub.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json()).split()
if len(msg) < 2:
await add_sub.finish("参数不完全,请查看订阅帮助...")
sub_type = msg[0]
id_ = ""
if isinstance(event, GroupMessageEvent):
if not await LevelUser.check_level(
event.user_id, event.group_id, GROUP_BILIBILI_SUB_LEVEL
):
await add_sub.finish(
f"您的权限不足,群内订阅的需要 {GROUP_BILIBILI_SUB_LEVEL} 级权限..", at_sender=True
)
sub_user = f"{event.user_id}:{event.group_id}"
else:
sub_user = f"{event.user_id}"
state["sub_type"] = sub_type
state["sub_user"] = sub_user
if len(msg) > 1:
if "http" in msg[1]:
msg[1] = msg[1].split("?")[0]
msg[1] = msg[1][:-1] if msg[1][-1] == "/" else msg[1]
msg[1] = msg[1].split("/")[-1]
id_ = msg[1][2:] if msg[1].startswith("md") else msg[1]
if not is_number(id_):
if sub_type in ["season", "动漫", "番剧"]:
rst = "*以为您找到以下番剧请输入Id选择*\n"
state["season_data"] = await get_media_id(id_)
print(state["season_data"])
if len(state["season_data"]) == 0:
await add_sub.finish(f"未找到番剧:{msg}")
for i, x in enumerate(state["season_data"]):
rst += f'{i + 1}.{state["season_data"][x]["title"]}\n----------\n'
await add_sub.send("\n".join(rst.split("\n")[:-1]))
else:
await add_sub.finish("Id 必须为全数字!")
else:
state["id"] = int(id_)
@add_sub.got("id")
async def _(bot: Bot, event: MessageEvent, state: T_State):
sub_type = state["sub_type"]
sub_user = state["sub_user"]
id_ = state["id"]
if sub_type in ["主播", "直播"]:
await add_sub.send(await add_live_sub(id_, sub_user))
elif sub_type.lower() in ["up", "用户"]:
await add_sub.send(await add_up_sub(id_, sub_user))
elif sub_type in ["season", "动漫", "番剧"]:
await add_sub.send(await add_season_sub(id_, sub_user))
else:
await add_sub.finish("参数错误,第一参数必须为:主播/up/番剧!")
sub_manager.reload_flag = True
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 添加订阅:{sub_type} -> {sub_user} -> {id_}"
)
@del_sub.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if not is_number(msg):
await del_sub.finish('Id必须为数字', at_sender=True)
id_ = f'{event.user_id}:{event.group_id}' if isinstance(event, GroupMessageEvent) else f'{event.user_id}'
if await BilibiliSub.delete_bilibili_sub(int(msg), id_):
await del_sub.send(f'删除订阅id{msg} 成功...')
logger.info(
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{msg} 失败...')
@show_sub_info.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
id_ = f'{event.user_id}:{event.group_id}' if isinstance(event, GroupMessageEvent) else f'{event.user_id}'
data = await BilibiliSub.get_sub_data(id_)
live_rst = ''
up_rst = ''
season_rst = ''
for x in data:
if x.sub_type == 'live':
live_rst += f'\t直播间id{x.sub_id}\n' \
f'\t名称:{x.uname}\n' \
f'------------------\n'
if x.sub_type == 'up':
up_rst += f'\tUP{x.uname}\n' \
f'\tuid{x.uid}\n' \
f'------------------\n'
if x.sub_type == 'season':
season_rst += f'\t番名:{x.season_name}\n' \
f'\t当前集数:{x.season_current_episode}\n' \
f'------------------\n'
live_rst = '当前订阅的直播:\n' + live_rst if live_rst else live_rst
up_rst = '当前订阅的UP\n' if up_rst else up_rst
season_rst = '当前订阅的番剧:\n' if season_rst else season_rst
await show_sub_info.send(live_rst + up_rst + season_rst)
# 推送
@scheduler.scheduled_job(
"interval",
seconds=30,
)
async def _():
bot = get_bot()
sub = None
if bot:
try:
await sub_manager.reload_sub_data()
sub = await sub_manager.random_sub_data()
if sub:
rst = await get_sub_status(sub.sub_id, sub.sub_type)
await send_sub_msg(rst, sub, bot)
if sub.sub_type == "live":
rst = await get_sub_status(sub.sub_id, "up")
await send_sub_msg(rst, sub, bot)
except Exception as e:
logger.error(f"B站订阅推送发生错误 sub_id{sub.sub_id if sub else 0} {type(e)}{e}")
async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
"""
推送信息
:param rst: 回复
:param sub: BilibiliSub
:param bot: Bot
"""
if rst:
for x in sub.sub_users.split(",")[:-1]:
try:
if ":" in x:
await bot.send_group_msg(
group_id=int(x.split(":")[1]), message=Message(rst)
)
else:
await bot.send_private_msg(user_id=int(x), message=Message(rst))
except Exception as e:
logger.error(f"B站订阅推送发生错误 sub_id{sub.sub_id} {type(e)}{e}")

View File

@ -0,0 +1,379 @@
from bilibili_api.exceptions.ResponseCodeException import ResponseCodeException
from asyncio.exceptions import TimeoutError
from models.bilibili_sub import BilibiliSub
from bilibili_api.live import LiveRoom
from bilibili_api import bangumi
from utils.message_builder import image
from bilibili_api.user import User
from bilibili_api import user
from typing import Optional
from pathlib import Path
from configs.path_config import IMAGE_PATH
from datetime import datetime
from utils.browser import get_browser
from services.db_context import db
from services.log import logger
import aiohttp
import random
bilibili_search_url = "https://api.bilibili.com/x/web-interface/search/all/v2"
dynamic_path = Path(IMAGE_PATH) / "bilibili_sub" / "dynamic"
dynamic_path.mkdir(exist_ok=True, parents=True)
async def add_live_sub(live_id: int, sub_user: str) -> str:
"""
添加直播订阅
:param live_id: 直播房间号
:param sub_user: 订阅用户 id # 7384933:private or 7384933:2342344(group)
:return:
"""
try:
async with db.transaction():
try:
live = LiveRoom(live_id)
live_info = (await live.get_room_info())["room_info"]
except ResponseCodeException:
return f"未找到房间号Id{live_id} 的信息请检查Id是否正确"
uid = live_info["uid"]
room_id = live_info["room_id"]
short_id = live_info["short_id"]
title = live_info["title"]
live_status = live_info["live_status"]
if await BilibiliSub.add_bilibili_sub(
room_id,
"live",
sub_user,
uid=uid,
live_short_id=short_id,
live_status=live_status,
):
await _get_up_status(live_id)
uname = (await BilibiliSub.get_sub(live_id)).uname
return (
"已成功订阅主播:\n"
f"\ttitle{title}\n"
f"\tname {uname}\n"
f"\tlive_id{live_id}\n"
f"\tuid{uid}"
)
else:
return "添加订阅失败..."
except Exception as e:
logger.error(f"订阅主播live_id{live_id} 发生了错误 {type(e)}{e}")
return "添加订阅失败..."
async def add_up_sub(uid: int, sub_user: str) -> str:
"""
添加订阅 UP
:param uid: UP uid
:param sub_user: 订阅用户
"""
try:
async with db.transaction():
try:
u = user.User(uid)
user_info = await u.get_user_info()
except ResponseCodeException:
return f"未找到UpId{uid} 的信息请检查Id是否正确"
uname = user_info["name"]
dynamic_info = await u.get_dynamics(0)
dynamic_upload_time = 0
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
video_info = await u.get_videos()
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 "添加订阅失败..."
except Exception as e:
logger.error(f"订阅Up uid{uid} 发生了错误 {type(e)}{e}")
return "添加订阅失败..."
async def add_season_sub(media_id: int, sub_user: str) -> str:
"""
添加订阅 UP
:param media_id: 番剧 media_id
:param sub_user: 订阅用户
"""
try:
async with db.transaction():
try:
season_info = await bangumi.get_meta(media_id)
except ResponseCodeException:
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 "添加订阅失败..."
except Exception as e:
logger.error(f"订阅番剧 media_id{media_id} 发生了错误 {type(e)}{e}")
return "添加订阅失败..."
async def delete_sub(sub_id: str, sub_user: str) -> str:
"""
删除订阅
:param sub_id: 订阅 id
:param sub_user: 订阅用户 id # 7384933:private or 7384933:2342344(group)
"""
if await BilibiliSub.delete_bilibili_sub(sub_id, sub_user):
return f"已成功取消订阅:{sub_id}"
else:
return f"取消订阅:{sub_id} 失败请检查是否订阅过该Id...."
async def get_media_id(keyword: str) -> dict:
"""
获取番剧的 media_id
:param keyword: 番剧名称
"""
params = {"keyword": keyword}
async with aiohttp.ClientSession() as session:
for _ in range(3):
try:
_season_data = {}
async with session.get(
bilibili_search_url, timeout=5, params=params
) as response:
if response.status == 200:
data = await response.json()
if data.get("data"):
for item in data["data"]["result"]:
if item["result_type"] == "media_bangumi":
idx = 0
for x in item["data"]:
_season_data[idx] = {
"media_id": x["media_id"],
"title": x["title"]
.replace('<em class="keyword">', "")
.replace("</em>", ""),
}
idx += 1
return _season_data
except TimeoutError:
pass
return {}
async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
"""
获取订阅状态
:param id_: 订阅 id
:param sub_type: 订阅类型
:return:
"""
try:
if sub_type == "live":
return await _get_live_status(id_)
elif sub_type == "up":
return await _get_up_status(id_)
elif sub_type == "season":
return await _get_season_status(id_)
except ResponseCodeException:
return "获取信息失败...请检查订阅Id是否存在或稍后再试..."
# except Exception as e:
# logger.error(f"获取订阅状态发生预料之外的错误 id_{id_} {type(e)}{e}")
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
async def _get_live_status(id_: int) -> Optional[str]:
"""
获取直播订阅状态
:param id_: 直播间 id
"""
live = LiveRoom(id_)
live_info = (await live.get_room_info())["room_info"]
title = live_info["title"]
room_id = live_info["room_id"]
live_status = live_info["live_status"]
cover = live_info["cover"]
sub = await BilibiliSub.get_sub(id_)
if sub.live_status != live_status:
await BilibiliSub.update_sub_info(id_, live_status=live_status)
if sub.live_status == 0 and live_status == 1:
return (
f"{image(cover)}\n"
f"{sub.uname} 开播啦!\n"
f"标题:{title}\n"
f"直链https://live.bilibili.com/{room_id}"
)
return None
async def _get_up_status(id_: int) -> Optional[str]:
"""
获取用户投稿状态
:param id_: 用户 id
:return:
"""
_user = await BilibiliSub.get_sub(id_)
u = user.User(_user.uid)
user_info = await u.get_user_info()
uname = user_info["name"]
video_info = await u.get_videos()
latest_video_created = 0
video = None
if _user.uname != uname:
await BilibiliSub.update_sub_info(id_, uname=uname)
dynamic_img, dynamic_upload_time = await get_user_dynamic(u, _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)
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n"
if _user.latest_video_created != latest_video_created and video:
rst = rst + "-------------\n" if rst else rst
await BilibiliSub.update_sub_info(
id_, latest_video_created=latest_video_created
)
rst += (
f'{image(video["pic"])}\n'
f"{uname} 投稿了新视频啦\n"
f'标题:{video["title"]}\n'
f'Bvid{video["bvid"]}\n'
f'直链https://www.bilibili.com/video/{video["bvid"]}'
)
rst = None if rst == "-------------\n" else rst
return rst
async def _get_season_status(id_) -> Optional[str]:
"""
获取 番剧 更新状态
:param id_: 番剧 id
"""
season_info = await bangumi.get_meta(id_)
title = season_info["media"]["title"]
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode
new_ep = season_info["media"]["new_ep"]["index"]
if new_ep != _idx:
await BilibiliSub.update_sub_info(id_, season_current_episode=new_ep, season_update_time=datetime.now())
return (
f'{image(season_info["media"]["cover"])}\n' f"[{title}]更新啦\n" f"最新集数:{new_ep}"
)
return None
async def get_user_dynamic(
u: User, local_user: BilibiliSub
) -> "Optional[MessageSegment], int":
"""
获取用户动态
:param u: 用户类
:param local_user: 数据库存储的用户数据
:return: 最新动态截图与时间
"""
dynamic_info = await u.get_dynamics(0)
browser = await get_browser()
if dynamic_info.get("cards") and browser:
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
if local_user.dynamic_upload_time != dynamic_upload_time:
page = await browser.new_page()
await page.goto(
f"https://space.bilibili.com/{local_user.uid}/dynamic",
wait_until="networkidle",
timeout=10000,
)
await page.set_viewport_size({"width": 2560, "height": 1080})
# 删除置顶
await page.evaluate(
"""
xs = document.getElementsByClassName('first-card-with-title');
for (x of xs) {
x.remove();
}
"""
)
card = await page.query_selector(".card")
# 截图并保存
await card.screenshot(
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
timeout=100000,
)
await page.close()
return (
image(
f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
"bilibili_sub/dynamic",
),
dynamic_upload_time,
)
return None, None
class SubManager:
def __init__(self):
self.reload_flag = True
self.live_data = []
self.up_data = []
self.season_data = []
self.sub_list = []
async def reload_sub_data(self):
"""
重载数据
"""
if self.reload_flag or not self.sub_list:
(
self.live_data,
self.up_data,
self.season_data,
) = await BilibiliSub.get_all_sub_data()
for x, i, j in zip(self.live_data, self.up_data, self.season_data):
self.sub_list.append(x)
self.sub_list.append(i)
self.sub_list.append(j)
self.reload_flag = False
def append(self, data: BilibiliSub):
"""
增加新数据
:param data: 数据
"""
self.sub_list.append(data)
async def random_sub_data(self) -> Optional[BilibiliSub]:
"""
随机获取一条数据
:return:
"""
if not self.sub_list:
await self.reload_sub_data()
if self.sub_list:
sub = random.choice(self.sub_list)
self.sub_list.remove(sub)
return sub
return None

View File

@ -0,0 +1,72 @@
from utils.image_utils import CreateImg
from configs.path_config import IMAGE_PATH
from pathlib import Path
from bilibili_api import user
from io import BytesIO
import aiohttp
BORDER_PATH = Path(IMAGE_PATH) / 'border'
BORDER_PATH.mkdir(parents=True, exist_ok=True)
async def get_pic(url: str) -> bytes:
"""
获取图像
:param url: 图像链接
:return: 图像二进制
"""
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=2) as response:
return await response.read()
async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des: str):
"""
生成主播简介图片
:param uid: 主播 uid
:param title: 直播间标题
:param cover: 直播封面
:param tags: 直播标签
:param des: 直播简介
:return:
"""
u = user.User(uid)
user_info = await u.get_user_info()
name = user_info['name']
sex = user_info['sex']
face = user_info['face']
sign = user_info['sign']
ava = CreateImg(100, 100, background=BytesIO(await get_pic(face)))
ava.circle()
cover = CreateImg(470, 265, background=BytesIO(await get_pic(cover)))
print()
def _create_live_des_image(title: str, cover: CreateImg, tags: str, des: str, user_name: str, sex: str, sign: str, ava: CreateImg):
"""
生成主播简介图片
:param title: 直播间标题
:param cover: 直播封面
:param tags: 直播标签
:param des: 直播简介
:param user_name: 主播名称
:param sex: 主播性别
:param sign: 主播签名
:param ava: 主播头像
:return:
"""
border = BORDER_PATH / '0.png'
border_img = None
if border.exists():
border_img = CreateImg(1772, 2657, background=border)
bk = CreateImg(1772, 2657, font_size=30)
bk.paste(cover, (0, 100), center_type='by_width')

View File

@ -54,7 +54,7 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
@bt.got("keyword", prompt="虚空磁力查什么GKD")
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
_ulmt.set_True(event.user_id)
_ulmt.set_true(event.user_id)
keyword = state["keyword"]
page = state["page"]
await bt.send("开始搜索....", at_sender=True)
@ -72,16 +72,16 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
)
send_flag = True
except TimeoutError:
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
await bt.finish(f"搜索 {keyword} 超时...")
except ServerDisconnectedError:
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
await bt.finish(f"搜索 {keyword} 连接失败")
except Exception as e:
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
await bt.finish(f"bt 其他未知错误..")
logger.error(f"bt 错误 e{e}")
if not send_flag:
await bt.send(f"{keyword} 未搜索到...")
logger.info(f"USER {event.user_id} BT搜索 {keyword}{page}")
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)

View File

@ -44,7 +44,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@restart.got('flag', prompt='确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)')
async def _(bot: Bot, event: MessageEvent, state: T_State):
flag = state['flag']
if flag.lower() in ['true', '', '']:
if flag.lower() in ['true', '', '', '确定', '确定是']:
await restart.send('开始重启真寻..请稍等...')
open('is_restart', 'w')
os.system('./restart.sh')

View File

@ -1,9 +1,10 @@
from aiohttp.client_exceptions import ClientConnectorError
from nonebot.adapters.cqhttp import Bot
from nonebot.adapters.cqhttp import Bot, Message
from utils.user_agent import get_user_agent
from utils.utils import get_local_proxy
from utils.image_utils import CreateImg
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from typing import List
from services.log import logger
from pathlib import Path
@ -84,13 +85,6 @@ async def check_update(bot: Bot) -> int:
logger.info("真寻更新完毕,清理文件完成....")
logger.info("开始获取真寻更新日志.....")
update_info = data["body"]
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"真寻更新完成,版本:{_version} -> {latest_version}\n"
f"更新日期:{data['created_at']}\n"
f"更新日志:\n"
f"{update_info}",
)
width = 0
height = len(update_info.split('\n')) * 24
for m in update_info.split('\n'):
@ -99,6 +93,13 @@ async def check_update(bot: Bot) -> int:
A = CreateImg(width, height, font_size=20)
A.text((10, 10), update_info)
A.save(f'{IMAGE_PATH}/update_info.png')
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=Message(f"真寻更新完成,版本:{_version} -> {latest_version}\n"
f"更新日期:{data['created_at']}\n"
f"更新日志:\n"
f"{image('update_info.png')}"),
)
return 200
else:
logger.warning(f"下载真寻最新版本失败...版本号:{latest_version}")

View File

@ -2,8 +2,12 @@ from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from services.log import logger
from asyncio.exceptions import TimeoutError
from utils.message_builder import image
import requests
from configs.path_config import IMAGE_PATH
import aiohttp
import aiofiles
import re
__plugin_name__ = "coser"
@ -15,13 +19,31 @@ coser = on_command(
)
url_2 = "http://api.rosysun.cn/cos"
url = "http://81.70.100.130/api/cosplay.php"
@coser.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
img_url = requests.get(url_2).text
await coser.send(image(img_url))
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送COSER"
)
async with aiohttp.ClientSession() as session:
try:
for _ in range(3):
try:
async with session.get(url, timeout=2) as response:
r = re.search(r'±img=(.*)±', await response.text())
if r:
async with session.get(r.group(1), timeout=5, verify_ssl=False) as res:
async with aiofiles.open(f'{IMAGE_PATH}/temp/{event.user_id}_coser.jpg', 'wb') as f:
await f.write(await res.read())
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送COSER"
)
await coser.send(image(f'{event.user_id}_coser.jpg', 'temp'))
break
except TimeoutError:
pass
except Exception as e:
await coser.send('发生了预料之外的错误..请稍后再试或联系管理员修复...')
logger.error(f'coser 发送了未知错误 {type(e)}{e}')

View File

@ -0,0 +1,29 @@
from pathlib import Path
from services.db_context import db
from asyncpg.exceptions import DuplicateColumnError
import nonebot
driver = nonebot.get_driver()
@driver.on_startup
async def _init_database():
file = Path() / 'plugins' / 'database_scripts.py'
if file.exists():
update_sql = [
'ALTER TABLE russian_users ADD winning_streak Integer default 0;',
'ALTER TABLE russian_users ADD losing_streak Integer default 0;',
'ALTER TABLE russian_users ADD max_winning_streak Integer default 0;',
'ALTER TABLE russian_users ADD max_losing_streak Integer default 0;',
'ALTER TABLE group_info_users ADD uid Integer default 0;'
]
for sql in update_sql:
try:
query = db.text(sql)
await db.first(query)
except DuplicateColumnError:
pass
file.unlink()

View File

@ -1,7 +1,7 @@
import aiohttp
from bs4 import BeautifulSoup
import re
from datetime import datetime
from datetime import datetime, timedelta
from .config import DRAW_PATH
from pathlib import Path
from asyncio.exceptions import TimeoutError
@ -177,6 +177,11 @@ class GenshinAnnouncement:
data[itype]['time'] = trs[1].find('td').text
if data[itype]['time'][-1] == '\n':
data[itype]['time'] = data[itype]['time'][:-1]
if '版本更新后' in data[itype]['time']:
sp = data[itype]['time'].split('~')
end_time = datetime.strptime(sp[1].strip(), "%Y/%m/%d %H:%M:%S")
start_time = end_time - timedelta(days=20)
data[itype]['time'] = start_time.strftime('%Y/%m/%d') + ' ~ ' + end_time.strftime('%Y/%m/%d')
tmp = ''
for tm in data[itype]['time'].split('~'):
date_time_sp = tm.split('/')

View File

@ -9,7 +9,6 @@ from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
import aiohttp
import aiofiles
from collections import defaultdict
from asyncio.exceptions import TimeoutError
from configs.config import FUDU_PROBABILITY
@ -20,39 +19,39 @@ class Fudu:
def append(self, key, content):
self._create(key)
self.data[key]['data'].append(content)
self.data[key]["data"].append(content)
def clear(self, key):
self._create(key)
self.data[key]['data'] = []
self.data[key]['is_repeater'] = False
self.data[key]["data"] = []
self.data[key]["is_repeater"] = False
def size(self, key) -> int:
self._create(key)
return len(self.data[key]['data'])
return len(self.data[key]["data"])
def check(self, key, content) -> bool:
self._create(key)
return self.data[key]['data'][0] == content
return self.data[key]["data"][0] == content
def get(self, key):
self._create(key)
return self.data[key]['data'][0]
return self.data[key]["data"][0]
def is_repeater(self, key):
self._create(key)
return self.data[key]['is_repeater']
return self.data[key]["is_repeater"]
def set_repeater(self, key):
self._create(key)
self.data[key]['is_repeater'] = True
self.data[key]["is_repeater"] = True
def _create(self, key):
if self.data.get(key) is None:
self.data[key] = {'is_repeater': False, 'data': []}
self.data[key] = {"is_repeater": False, "data": []}
_fudulist = Fudu()
_fudu_list = Fudu()
fudu = on_message(permission=GROUP, priority=9)
@ -74,17 +73,20 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
else:
img_hash = ""
add_msg = msg + "|-|" + img_hash
if _fudulist.size(event.group_id) == 0:
_fudulist.append(event.group_id, add_msg)
elif _fudulist.check(event.group_id, add_msg):
_fudulist.append(event.group_id, add_msg)
if _fudu_list.size(event.group_id) == 0:
_fudu_list.append(event.group_id, add_msg)
elif _fudu_list.check(event.group_id, add_msg):
_fudu_list.append(event.group_id, add_msg)
else:
_fudulist.clear(event.group_id)
_fudulist.append(event.group_id, add_msg)
if _fudulist.size(event.group_id) > 2:
if random.random() < FUDU_PROBABILITY and not _fudulist.is_repeater(event.group_id):
_fudu_list.clear(event.group_id)
_fudu_list.append(event.group_id, add_msg)
if _fudu_list.size(event.group_id) > 2:
if random.random() < FUDU_PROBABILITY and not _fudu_list.is_repeater(
event.group_id
):
if random.random() < 0.2:
await fudu.finish("打断施法!")
_fudu_list.set_repeater(event.group_id)
if imgs and msg:
rst = msg + image(f"compare_{event.group_id}_img.jpg", "temp")
elif imgs:
@ -95,7 +97,6 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
rst = ""
if rst:
await fudu.send(rst)
_fudulist.set_repeater(event.group_id)
async def get_fudu_img_hash(url, group_id):
@ -109,4 +110,4 @@ async def get_fudu_img_hash(url, group_id):
img_hash = get_img_hash(IMAGE_PATH + f"temp/compare_{group_id}_img.jpg")
return str(img_hash)
except TimeoutError:
return ''
return ""

View File

@ -5,6 +5,7 @@ from utils.utils import get_message_text, scheduler
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message
from nonebot.typing import T_State
from services.log import logger
from configs.config import NICKNAME
from nonebot.permission import SUPERUSER
import re
@ -58,21 +59,20 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@qr_lst.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
mes_list = []
txt = get_resource_type_list()
txt_list = txt.split("\n")
if event.message_type == "group":
if isinstance(event, GroupMessageEvent):
mes_list = []
for txt in txt_list:
data = {
"type": "node",
"data": {
"name": f"这里是{list(bot.config.nickname)[0]}",
"name": f"这里是{NICKNAME}",
"uin": f"{bot.self_id}",
"content": txt,
},
}
mes_list.append(data)
if isinstance(event, GroupMessageEvent):
await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
else:
rst = ""

View File

@ -1,8 +1,6 @@
from nonebot import on_notice, on_request
from configs.path_config import IMAGE_PATH, DATA_PATH
from utils.message_builder import image
import os
import random
from models.group_member_info import GroupInfoUser
from datetime import datetime
from services.log import logger
@ -13,9 +11,12 @@ from nonebot.adapters.cqhttp import (
GroupDecreaseNoticeEvent,
)
from nonebot.adapters.cqhttp.exception import ActionFailed
from pathlib import Path
from configs.config import plugins2info_dict
from utils.static_data import group_manager
from models.group_info import GroupInfo
from pathlib import Path
import random
import os
try:
import ujson as json
except ModuleNotFoundError:
@ -37,46 +38,52 @@ add_group = on_request(priority=1, block=False)
@group_increase_handle.handle()
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
join_time = datetime.now()
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']} 更新成功")
if event.user_id == int(bot.self_id):
if event.group_id not in group_manager['group_manager'].keys():
for plugin in plugins2info_dict.keys():
if not plugins2info_dict[plugin]['default_status']:
group_manager.block_plugin(plugin, str(event.group_id))
else:
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
# 群欢迎消息
if await GroupRemind.get_status(event.group_id, "hy"):
msg = ""
img = ""
at_flag = False
custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
join_time = datetime.now()
user_info = await bot.get_group_member_info(
group_id=event.group_id, user_id=event.user_id
)
if custom_welcome_msg_json.exists():
data = json.load(open(custom_welcome_msg_json, "r"))
if data.get(str(event.group_id)):
msg = data[str(event.group_id)]
if msg.find("[at]") != -1:
msg = msg.replace("[at]", "")
at_flag = True
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"):
img = image(abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg")
if msg or img:
await group_increase_handle.send(
"\n" + msg.strip() + img, at_sender=at_flag
)
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:
await group_increase_handle.send(
"新人快跑啊!!本群现状↓(快使用自定义!)"
+ image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz")
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
# 群欢迎消息
if await GroupRemind.get_status(event.group_id, "hy"):
msg = ""
img = ""
at_flag = False
custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
)
if custom_welcome_msg_json.exists():
data = json.load(open(custom_welcome_msg_json, "r"))
if data.get(str(event.group_id)):
msg = data[str(event.group_id)]
if msg.find("[at]") != -1:
msg = msg.replace("[at]", "")
at_flag = True
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"):
img = image(abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg")
if msg or img:
await group_increase_handle.send(
"\n" + msg.strip() + img, at_sender=at_flag
)
else:
await group_increase_handle.send(
"新人快跑啊!!本群现状↓(快使用自定义!)"
+ image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz")
)
@group_decrease_handle.handle()

View File

@ -33,6 +33,8 @@ manager_group_whitelist = on_command(
"添加群白名单", aliases={"删除群白名单"}, priority=1, permission=SUPERUSER, block=True
)
show_group_whitelist = on_command('查看群白名单', priority=1, permission=SUPERUSER, block=True)
@add_group_level.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
@ -100,3 +102,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
)
else:
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
@show_group_whitelist.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
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('没有任何群在群白名单...')

View File

@ -54,7 +54,8 @@ entertainment_help = {
"pix_gallery": "偶尔也想看看美图? --> 指令:PIX [关键词/uid/pid:pid] [num]/查看pix图库 [关键词]/显示pix关键词",
'nbnhhsh': "会说话就多说点! --> 指令:nbnhhsh/能不能好好说话 [文本](空格划分)",
"roll": f"{NICKNAME}来帮你决定吧! --> 指令:roll/ roll [文本](空格划分)",
"wbtop": f"刚买完瓜,在吃瓜现场 --> 指令:微博热搜/微博热搜 [数字]"
"wbtop": f"刚买完瓜,在吃瓜现场 --> 指令:微博热搜/微博热搜 [数字]",
"bilibili_sub": f"非常快捷的订阅播报 --> 指令:添加订阅 [主播/up/番剧] [id/番名/链接] / 删除订阅 [id]/ 查看订阅"
}
# 其他
other_help = [

View File

@ -13,10 +13,6 @@ import nonebot
width = 1600
e_height = 0
u_height = 950
o_height = 1500
# f_height =
def create_help_img():
@ -28,9 +24,9 @@ def create_help_img():
+ len(utility_help) * 24
+ len(entertainment_help) * 24
+ len(other_help) * 24
) * 2
) + 800
A = CreateImg(width, h - 200, font_size=24)
e = CreateImg(width, len(entertainment_help) * 42, font_size=24)
e = CreateImg(width, len(entertainment_help) * 26 + 100, font_size=24)
rst = ""
i = 0
for cmd in entertainment_help:
@ -38,7 +34,7 @@ def create_help_img():
i += 1
e.text((10, 10), "娱乐功能:")
e.text((40, 40), rst)
u = CreateImg(width, len(utility_help) * 40 + 50, font_size=24, color="black")
u = CreateImg(width, len(utility_help) * 26 + 100, font_size=24, color="black")
rst = ""
i = 0
for cmd in utility_help:
@ -46,19 +42,18 @@ def create_help_img():
i += 1
u.text((10, 10), "实用功能:", fill=(255, 255, 255))
u.text((40, 40), rst, fill=(255, 255, 255))
o = CreateImg(width, len(other_help) * 40, font_size=24)
o = CreateImg(width, len(other_help) * 26 + 100, font_size=24)
rst = ""
i = 0
for i in range(len(other_help)):
rst += f"{i + 1}.{other_help[i]}\n"
i += 1
o.text((10, 10), "其他功能:")
o.text((40, 40), rst)
A.paste(e, (0, 0))
A.paste(u, (0, u_height))
A.paste(o, (0, o_height))
A.paste(u, (0, e.h))
A.paste(o, (0, e.h + u.h))
A.text(
(10, h * 0.68),
(10, e.h + u.h + o.h + 50),
f"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n{NICKNAME}说 “{NICKNAME}帮助 指令名” 获取对应详细帮助\n"
"可以通过 “滴滴滴- [消息]” 联系管理员(有趣的想法尽管来吧!<还有Bug和建议>"
"\n[群管理员请看 管理员帮助(群主与管理员自带 5 级权限)]\n\n"
@ -75,11 +70,11 @@ def create_group_help_img(group_id: int):
+ len(utility_help) * 24
+ len(entertainment_help) * 24
+ len(other_help) * 24
) * 2
A = CreateImg(width, h - 200, font_size=24)
u = CreateImg(width, len(utility_help) * 40, font_size=24, color="black")
o = CreateImg(width, len(other_help) * 40, font_size=24)
e = CreateImg(width, len(entertainment_help) * 42, font_size=24)
) + 800
A = CreateImg(width, h, font_size=24)
u = CreateImg(width, len(utility_help) * 26 + 100, font_size=24, color="black")
o = CreateImg(width, len(other_help) * 26 + 100, font_size=24)
e = CreateImg(width, len(entertainment_help) * 26 + 100, font_size=24)
rst = ""
i = 1
for cmd in entertainment_help.keys():
@ -107,17 +102,17 @@ def create_group_help_img(group_id: int):
o.text((40, 40), rst)
A.paste(e, (0, 0))
A.paste(u, (0, u_height))
A.paste(o, (0, o_height))
A.paste(u, (0, e.h))
A.paste(o, (0, e.h + u.h))
# A.text((width, 10), f'总开关【{"√" if data["总开关"] else "×"}】')
A.text(
(10, h * 0.68),
(10, e.h + u.h + o.h + 50),
f"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n{NICKNAME}说 “{NICKNAME}帮助 指令名” 获取对应详细帮助\n"
"可以通过 “滴滴滴- [消息]” 联系管理员(有趣的想法尽管来吧!<还有Bug和建议>"
f"\n[群管理员请看 管理员帮助(群主与管理员自带 {ADMIN_DEFAULT_AUTH} 级权限)]",
)
A.text(
(10, h * 0.77),
(10, e.h + u.h + o.h + 250),
f"【注】「色图概率:好感度 + {int(INITIAL_SETU_PROBABILITY*100)}%\n"
f"\t\t每 3 点好感度 + 1次开箱初始 {INITIAL_OPEN_CASE_COUNT}\n"
f"\t\t开启/关闭功能只需输入‘开启/关闭 指令名’(每个功能的第一个指令)」\n"

View File

@ -1,13 +1,18 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
from nonebot.adapters.cqhttp.exception import ActionFailed
from models.group_member_info import GroupInfoUser
from models.friend_user import FriendUser
from typing import Optional
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import (
Bot,
Event,
MessageEvent,
PrivateMessageEvent,
GroupMessageEvent,
PokeNotifyEvent
PokeNotifyEvent,
Message,
)
from configs.config import (
BAN_RESULT,
@ -17,24 +22,43 @@ from configs.config import (
MALICIOUS_BAN_COUNT,
CHECK_NOTICE_INFO_CD,
plugins2info_dict,
plugins2cd_dict,
plugins2exists_dict,
)
from models.ban_user import BanUser
from utils.utils import is_number, static_flmt, BanCheckLimiter
from utils.utils import (
is_number,
static_flmt,
BanCheckLimiter,
FreqLimiter,
UserExistLimiter,
)
from utils.static_data import withdraw_message_id_manager
from utils.message_builder import at
from services.log import logger
from models.level_user import LevelUser
from utils.static_data import group_manager
from utils.utils import FreqLimiter
import asyncio
try:
import ujson as json
except ModuleNotFoundError:
import json
withdraw_message_id_manager["message_id"] = []
# 检查是否被ban
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
try:
if (
await BanUser.is_super_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
):
raise IgnoredException("用户处于超级黑名单中")
except AttributeError:
pass
if not isinstance(event, MessageEvent):
return
if matcher.type == "message" and matcher.priority not in [1, 9]:
@ -48,9 +72,9 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
if time < 60:
time = str(time) + ""
else:
time = str(int(time / 60)) + ""
time = str(int(time / 60)) + ""
else:
time = str(time) + ""
time = str(time) + ""
if isinstance(event, GroupMessageEvent):
if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中")
@ -61,7 +85,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
group_id=event.group_id,
message=at(event.user_id)
+ BAN_RESULT
+ f" 在..在 {time}后才会理你喔",
+ f" 在..在 {time} 后才会理你喔",
)
except ActionFailed:
pass
@ -127,11 +151,16 @@ _flmt = FreqLimiter(CHECK_NOTICE_INFO_CD)
_flmt_g = FreqLimiter(CHECK_NOTICE_INFO_CD)
_flmt_s = FreqLimiter(CHECK_NOTICE_INFO_CD)
_flmt_c = FreqLimiter(CHECK_NOTICE_INFO_CD)
_exists_msg = {}
ignore_rst_module = ["ai", "poke"]
# 权限检测
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
global _exists_msg
if (
(not isinstance(event, MessageEvent) and matcher.module != "poke")
or await BanUser.is_ban(event.user_id)
@ -170,54 +199,70 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
raise IgnoredException("权限不足")
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
# 戳一戳单独判断
if isinstance(event, GroupMessageEvent) or (isinstance(event, PokeNotifyEvent) and event.group_id):
if isinstance(event, GroupMessageEvent) or (
isinstance(event, PokeNotifyEvent) and event.group_id
):
if _exists_msg.get(event.group_id) is None:
_exists_msg[event.group_id] = False
# 群权限
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
str(event.group_id)
):
try:
if _flmt_g.check(event.user_id):
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
_flmt_g.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id, message="群权限不足..."
)
except ActionFailed:
pass
_exists_msg[event.group_id] = True
raise IgnoredException("群权限不足")
# 插件状态
if not group_manager.get_plugin_status(module, str(event.group_id)):
try:
if module != "poke" and _flmt_s.check(event.group_id):
if module not in ignore_rst_module and _flmt_s.check(
event.group_id
):
_flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该群未开启此功能.."
)
except ActionFailed:
pass
_exists_msg[event.group_id] = True
raise IgnoredException("未开启此功能...")
# 管理员禁用
if not group_manager.get_plugin_status(
f"{module}:super", str(event.group_id)
):
try:
if _flmt_s.check(event.group_id):
if (
_flmt_s.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="管理员禁用了此群该功能..."
)
except ActionFailed:
pass
_exists_msg[event.group_id] = True
raise IgnoredException("管理员禁用了此群该功能...")
# 群聊禁用
if not group_manager.get_plugin_status(module, block_type="group"):
try:
if _flmt_c.check(event.group_id):
if (
_flmt_c.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该功能在群聊中已被禁用..."
)
except ActionFailed:
pass
_exists_msg[event.group_id] = True
raise IgnoredException("该插件在群聊中已被禁用...")
else:
# 私聊禁用
@ -238,21 +283,187 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
) and group_manager.check_group_is_white(event.group_id):
return
try:
if _flmt_c.check(event.user_id):
_flmt_c.start_cd(event.user_id)
if isinstance(event, GroupMessageEvent):
if isinstance(event, GroupMessageEvent):
if (
_flmt_c.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="此功能正在维护..."
)
else:
await bot.send_private_msg(
user_id=event.user_id, message="此功能正在维护..."
)
else:
await bot.send_private_msg(
user_id=event.user_id, message="此功能正在维护..."
)
except ActionFailed:
pass
if isinstance(event, GroupMessageEvent):
_exists_msg[event.group_id] = True
raise IgnoredException("此功能正在维护...")
check_flmt = {}
for plugin in plugins2cd_dict.keys():
if plugins2cd_dict[plugin]["status"]:
check_flmt[plugin] = FreqLimiter(plugins2cd_dict[plugin]["cd"])
check_elmt = {}
for plugin in plugins2exists_dict.keys():
if plugins2exists_dict[plugin]["status"]:
check_elmt[plugin] = UserExistLimiter()
# 命令cd 和 命令阻塞
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
global _exists_msg
if not isinstance(event, MessageEvent) and matcher.module != "poke":
return
module = matcher.module
if isinstance(event, GroupMessageEvent) and _exists_msg.get(event.group_id) is None:
_exists_msg[event.group_id] = False
if module in plugins2cd_dict.keys() and module in check_flmt.keys():
if (
(
isinstance(event, PrivateMessageEvent)
and plugins2cd_dict[module]["check_type"] == "private"
)
or (
isinstance(event, GroupMessageEvent)
and plugins2cd_dict[module]["check_type"] == "group"
)
or plugins2cd_dict[module]["check_type"] == "all"
) and plugins2cd_dict[module]["cd"] > 0:
cd_type_ = event.user_id
if plugins2cd_dict[module]["limit_type"] == "group" and isinstance(
event, GroupMessageEvent
):
cd_type_ = event.group_id
if not check_flmt[module].check(cd_type_):
rst = plugins2cd_dict[module]["rst"]
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} 正在cd中...")
else:
check_flmt[module].start_cd(cd_type_)
if module in plugins2exists_dict.keys() and module in check_elmt.keys():
if (
(
isinstance(event, PrivateMessageEvent)
and plugins2exists_dict[module]["check_type"] == "private"
)
or (
isinstance(event, GroupMessageEvent)
and plugins2exists_dict[module]["check_type"] == "group"
)
or plugins2exists_dict[module]["check_type"] == "all"
):
exists_type_ = event.user_id
if plugins2exists_dict[module]["limit_type"] == "group" and isinstance(
event, GroupMessageEvent
):
exists_type_ = event.group_id
if check_elmt[module].check(exists_type_):
rst = plugins2exists_dict[module]["rst"]
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{event.user_id}正在调用{module}....")
else:
check_elmt[module].set_true(exists_type_)
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
"""
发送信息
:param rst: pass
:param bot: pass
:param event: pass
"""
global _exists_msg
rst = await init_rst(rst, event)
try:
if isinstance(event, GroupMessageEvent):
_exists_msg[event.group_id] = True
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
else:
_exists_msg[event.user_id] = True
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
except ActionFailed:
pass
@run_postprocessor
async def _(
matcher: Matcher,
exception: Optional[Exception],
bot: Bot,
event: Event,
state: T_State,
):
if not isinstance(event, MessageEvent) and matcher.module != "poke":
return
module = matcher.module
if module in plugins2exists_dict.keys() and module in check_elmt.keys():
if not (
(
isinstance(event, GroupMessageEvent)
and plugins2exists_dict[module]["check_type"] == "private"
)
or (
isinstance(event, PrivateMessageEvent)
and plugins2exists_dict[module]["check_type"] == "group"
)
):
exists_type_ = event.user_id
if plugins2exists_dict[module]["limit_type"] == "group" and isinstance(
event, GroupMessageEvent
):
exists_type_ = event.group_id
check_elmt[module].set_false(exists_type_)
async def init_rst(rst: str, event: MessageEvent):
if "[uname]" in rst:
uname = event.sender.card if event.sender.card else event.sender.nickname
rst = rst.replace("[uname]", uname)
if "[nickname]" in rst:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
rst = rst.replace("[nickname]", nickname)
if "[at]" in rst and isinstance(event, GroupMessageEvent):
rst = rst.replace("[at]", str(at(event.user_id)))
return rst
# 消息撤回
@run_postprocessor
async def _(
matcher: Matcher,
exception: Optional[Exception],
bot: Bot,
event: Event,
state: T_State,
):
tasks = []
for id_, time in withdraw_message_id_manager["message_id"]:
tasks.append(asyncio.ensure_future(_withdraw_message(bot, id_, time)))
withdraw_message_id_manager["message_id"].remove((id_, time))
await asyncio.gather(*tasks)
async def _withdraw_message(bot: Bot, id_: int, time: int):
await asyncio.sleep(time)
await bot.delete_msg(message_id=id_, self_id=int(bot.self_id))
# 为什么AI会自己和自己聊天
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_State):
@ -265,8 +476,19 @@ async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_Sta
# 有命令就别说话了
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
global _exists_msg
if not isinstance(event, MessageEvent):
return
if matcher.type == "message":
if state["_prefix"]["raw_command"] and matcher.module == "ai":
if matcher.module == "ai":
if (
isinstance(event, GroupMessageEvent)
and _exists_msg.get(event.group_id) is True
):
_exists_msg[event.group_id] = False
elif (
isinstance(event, PrivateMessageEvent)
and _exists_msg.get(event.user_id) is True
):
_exists_msg[event.user_id] = False
raise IgnoredException("有命令就别说话了")

View File

@ -34,9 +34,9 @@ async def handle_event(bot: Bot, event: MessageEvent, state: T_State):
content = state["content"].strip()
if content.startswith(",") or content.startswith(""):
content = content[1:]
_ulmt.set_True(event.user_id)
_ulmt.set_true(event.user_id)
if len(content) > 20:
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
await luxun.finish("太长了, 鲁迅说不完!", at_sender=True)
else:
if len(content) >= 12:
@ -47,7 +47,7 @@ async def handle_event(bot: Bot, event: MessageEvent, state: T_State):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'} 鲁迅说过 {content}"
)
await luxun.send(img)
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
def process_pic(content, filename) -> str:

View File

@ -29,6 +29,7 @@ mute_setting = on_command(
aliases={"设置检测时间", "设置检测次数", "设置禁言时长", "刷屏检测设置"},
permission=GROUP,
block=True,
priority=5
)

View File

@ -1,85 +0,0 @@
from typing import Any, Dict
from nonebot import get_driver, on_command
from nonebot.adapters.cqhttp import Bot, Event, GroupMessageEvent, PrivateMessageEvent
from nonebot.rule import to_me
from nonebot.typing import T_State, T_CalledAPIHook
from .config import Config
global_config = get_driver().config
withdraw_config = Config(**global_config.dict())
msg_ids = {}
max_size = withdraw_config.withdraw_max_size
__plugin_name__ = "撤回"
__plugin_usage__ = (
"用法:撤回 [消息位置](默认0)\n" "示例:\n" "\t撤回0 -> 撤回倒数第一条消息(即最新发送的消息)" "\t撤回1 -> 撤回倒数第2条消息"
)
def get_key(msg_type, id):
return f"{msg_type}_{id}"
async def save_msg_id(
bot: Bot, e: Exception, api: str, data: Dict[str, Any], result: Any
) -> T_CalledAPIHook:
try:
if api == "send_msg":
msg_type = data["message_type"]
id = data["group_id"] if msg_type == "group" else data["user_id"]
elif api == "send_private_msg":
msg_type = "private"
id = data["user_id"]
elif api == "send_group_msg":
msg_type = "group"
id = data["group_id"]
else:
return
key = get_key(msg_type, id)
msg_id = result["message_id"]
if key not in msg_ids:
msg_ids[key] = []
msg_ids[key].append(msg_id)
if len(msg_ids) > max_size:
msg_ids[key].pop(0)
except:
pass
Bot._called_api_hook.add(save_msg_id)
withdraw = on_command("withdraw", aliases={"撤回"}, rule=to_me(), priority=1, block=True)
@withdraw.handle()
async def _(bot: Bot, event: Event, state: T_State):
if isinstance(event, GroupMessageEvent):
msg_type = "group"
id = event.group_id
elif isinstance(event, PrivateMessageEvent):
msg_type = "private"
id = event.user_id
else:
return
key = get_key(msg_type, id)
num = event.get_plaintext().strip()
if not num:
num = 0
elif num.isdigit() and 0 <= int(num) < len(msg_ids[key]):
num = int(num)
else:
return
try:
idx = -num - 1
await bot.delete_msg(message_id=msg_ids[key][idx])
msg_ids[key].pop(idx)
except:
await withdraw.finish("撤回失败,可能已超时")

View File

@ -1,8 +0,0 @@
from pydantic import BaseSettings
class Config(BaseSettings):
withdraw_max_size: int = 50
class Config:
extra = 'ignore'

View File

@ -1,11 +1,10 @@
import aiohttp
from utils.user_agent import get_user_agent
from io import BytesIO
from random import choice
from nonebot import on_regex
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from utils.utils import get_message_text, get_local_proxy, get_message_at
from utils.utils import get_message_text, get_message_at
from utils.message_builder import image
import re
from utils.image_utils import CreateImg
@ -16,15 +15,15 @@ __plugin_usage__ = "用法:我有一个朋友说/问 [消息] [at](不艾特
one_friend = on_regex(
"^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问).*",
priority=5,
priority=4,
block=True,
)
async def get_pic(qq):
url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=100"
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(url, proxy=get_local_proxy(), timeout=5) as response:
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=5) as response:
return await response.read()
@ -59,7 +58,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
text.text((0, 0), user_name)
A = CreateImg(700, 150, font_size=25, color="white")
A.paste(ava, (30, 25), True)
A.paste(text, (150, 40))
A.paste(text, (150, 38))
A.text((150, 85), msg, (125, 125, 125))
await one_friend.send(image(b64=A.pic2bs4()))

View File

@ -1,5 +1,5 @@
from nonebot import on_command
from utils.utils import FreqLimiter, scheduler, get_message_text, is_number
from utils.utils import scheduler, get_message_text, is_number
from nonebot.adapters.cqhttp.permission import GROUP
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
@ -33,8 +33,6 @@ __plugin_usage__ = (
"示例:我的金色"
)
_flmt = FreqLimiter(3)
cases_name = ["狂牙大行动", "突围大行动", "命悬一线", "裂空", "光谱"]
cases_matcher_group = MatcherGroup(priority=5, permission=GROUP, block=True)
@ -47,9 +45,9 @@ k_open_case = cases_matcher_group.on_command("开箱")
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if str(event.get_message()).strip() in ["帮助"]:
await k_open_case.finish(__plugin_usage__)
if not _flmt.check(event.user_id):
await k_open_case.finish("着什么急啊,慢慢来!", at_sender=True)
_flmt.start_cd(event.user_id)
# if not _flmt.check(event.user_id):
# await k_open_case.finish("着什么急啊,慢慢来!", at_sender=True)
# _flmt.start_cd(event.user_id)
case_name = get_message_text(event.json())
if case_name:
result = await open_case(event.user_id, event.group_id, case_name)
@ -98,7 +96,7 @@ open_shilian = cases_matcher_group.on_regex(".*连开箱")
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
# if not _flmt.check(event.user_id):
# await k_open_case.finish('着什么急啊,慢慢来!', at_sender=True)
_flmt.start_cd(event.user_id)
# _flmt.start_cd(event.user_id)
msg = get_message_text(event.json())
rs = re.search(r"(.*)连开箱(.*)", msg)
if rs:

View File

@ -3,14 +3,14 @@ from .config import *
from services.log import logger
from services.db_context import db
from models.open_cases_user import OpenCasesUser
from models.sigin_group_user import SignGroupUser
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_price import BuffPrice
from PIL import Image
from utils.image_utils import alpha2white_PIL, CreateImg
from utils.image_utils import alpha2white_pil, CreateImg
from configs.path_config import IMAGE_PATH
import asyncio
from utils.utils import cn2py
@ -221,7 +221,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
skin_name += ''.join(i)
# img = image(skin_name, "cases/" + case, "png")
wImg = CreateImg(200, 270, 200, 200)
wImg.paste(alpha2white_PIL(Image.open(IMAGE_PATH + f'cases/{case}/{skin_name}.png').resize((200, 200), Image.ANTIALIAS)), (0, 0))
wImg.paste(alpha2white_pil(Image.open(IMAGE_PATH + f'cases/{case}/{skin_name}.png').resize((200, 200), Image.ANTIALIAS)), (0, 0))
wImg.text((5, 200), skin)
wImg.text((5, 220), f'磨损:{str(mosun)[:9]}')
wImg.text((5, 240), f'价格:{price_result}')
@ -370,7 +370,7 @@ def _pst_my_knife(w, h, knifes_list):
style=pypinyin.NORMAL):
skin_name += ''.join(i)
knife_img = CreateImg(470, 600, 470, 470, font_size=20)
knife_img.paste(alpha2white_PIL(
knife_img.paste(alpha2white_pil(
Image.open(IMAGE_PATH + f'cases/{case}/{skin_name}.png').resize((470, 470), Image.ANTIALIAS)), (0, 0))
knife_img.text((5, 500), f'\t{name}({itype})')
knife_img.text((5, 530), f'\t磨损:{mosun}')

View File

@ -2,7 +2,7 @@ from nonebot import on_message
from services.log import logger
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from nonebot.typing import T_State
from utils.utils import get_message_json, get_local_proxy, get_message_text
from utils.utils import get_message_json, get_local_proxy, get_message_text, is_number
from utils.user_agent import get_user_agent
from nonebot.adapters.cqhttp.permission import GROUP
from bilibili_api import video
@ -23,11 +23,14 @@ if get_local_proxy():
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
_tmp = {}
@parse_bilibili_json.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if await GroupRemind.get_status(event.group_id, "blpar"):
vd_info = None
url = None
if get_message_json(event.json()):
try:
data = json.loads(get_message_json(event.json())[0]["data"])
@ -66,7 +69,6 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await page.goto(url, wait_until="networkidle", timeout=10000)
await page.set_viewport_size({"width": 2560, "height": 1080})
await page.click("#app > div")
# await page.click("text=继续阅读全文", timeout=3000)
div = await page.query_selector("#app > div")
await div.screenshot(
path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
@ -90,7 +92,20 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
# BV
if get_message_text(event.json()):
msg = get_message_text(event.json())
if "https://b23.tv" in msg:
if "BV" in msg:
index = msg.find('BV')
if len(msg[index + 2:]) >= 10:
msg = msg[index: index + 12]
url = f'https://www.bilibili.com/video/{msg}'
vd_info = await video.Video(bvid=msg).get_info()
elif 'av' in msg:
index = msg.find('av')
if len(msg[index + 2:]) >= 9:
msg = msg[index + 2: index + 11]
if is_number(msg):
url = f'https://www.bilibili.com/video/{msg}'
vd_info = await video.Video(aid=int(msg)).get_info()
elif "https://b23.tv" in msg:
url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13]
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
@ -101,33 +116,32 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
url = str(response.url).split("?")[0]
bvid = url.split("/")[-1]
vd_info = await video.Video(bvid=bvid).get_info()
if "https://www.bilibili.com/video" in msg:
url = msg.split("?")[0]
msg = url.split("/")[-1]
vd_info = await video.Video(bvid=msg).get_info()
if vd_info:
aid = vd_info["aid"]
title = vd_info["title"]
author = vd_info["owner"]["name"]
reply = vd_info["stat"]["reply"] # 回复
favorite = vd_info["stat"]["favorite"] # 收藏
coin = vd_info["stat"]["coin"] # 投币
# like = vd_info['stat']['like'] # 点赞
# danmu = vd_info['stat']['danmaku'] # 弹幕
date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
try:
await parse_bilibili_json.send(
image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
f"UP{author}\n"
f"上传日期:{date}\n"
f"回复:{reply},收藏:{favorite},投币:{coin}\n"
f"{url}"
)
except ActionFailed:
logger.warning(f"{event.group_id} 发送bilibili解析失败")
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
)
if (url in _tmp.keys() and time.time() - _tmp[url] > 30) or url not in _tmp.keys():
_tmp[url] = time.time()
aid = vd_info["aid"]
title = vd_info["title"]
author = vd_info["owner"]["name"]
reply = vd_info["stat"]["reply"] # 回复
favorite = vd_info["stat"]["favorite"] # 收藏
coin = vd_info["stat"]["coin"] # 投币
# like = vd_info['stat']['like'] # 点赞
# danmu = vd_info['stat']['danmaku'] # 弹幕
date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
try:
await parse_bilibili_json.send(
image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
f"UP{author}\n"
f"上传日期:{date}\n"
f"回复:{reply},收藏:{favorite},投币:{coin}\n"
f"{url}"
)
except ActionFailed:
logger.warning(f"{event.group_id} 发送bilibili解析失败")
else:
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
)
def resize(path: str):

View File

@ -1,14 +1,76 @@
from configs.config import HIBIAPI
from services.log import logger
from models.omega_pixiv_illusts import OmegaPixivIllusts
from pathlib import Path
from nonebot import Driver
from typing import List
from datetime import datetime
import nonebot
import asyncio
import os
driver: Driver = nonebot.get_driver()
illust_url = f"{HIBIAPI}/api/pixiv/illust"
@driver.on_startup
async def _init_omega_pixiv_illusts():
omega_pixiv_illusts = None
for file in os.listdir("."):
if "omega_pixiv_illusts" in file and ".sql" in file:
omega_pixiv_illusts = Path() / file
if omega_pixiv_illusts:
with open(omega_pixiv_illusts, "r", encoding="utf8") as f:
lines = f.readlines()
tasks = []
length = len([x for x in lines if "INSERT INTO" in x.upper()])
all_pid = await OmegaPixivIllusts.get_all_pid()
index = 0
logger.info('检测到OmegaPixivIllusts数据库准备开始更新....')
for line in lines:
if "INSERT INTO" in line.upper():
index += 1
tasks.append(asyncio.ensure_future(_tasks(line, all_pid, length, index)))
await asyncio.gather(*tasks)
omega_pixiv_illusts.unlink()
async def _tasks(line: str, all_pid: List[int], length: int, index: int):
data = line.split("VALUES", maxsplit=1)[-1].strip()
if data.startswith("("):
data = data[1:]
if data.endswith(");"):
data = data[:-2]
x = data.split(maxsplit=3)
pid = int(x[1][:-1].strip())
if pid in all_pid:
logger.info(f'添加OmegaPixivIllusts图库数据已存在 ---> pid{pid}')
return
uid = int(x[2][:-1].strip())
x = x[3].split(", '")
title = x[0].strip()[1:-1]
tmp = x[1].split(', ')
author = tmp[0].strip()[:-1]
nsfw_tag = int(tmp[1])
width = int(tmp[2])
height = int(tmp[3])
tags = x[2][:-1]
url = x[3][:-1]
if await OmegaPixivIllusts.add_image_data(
pid,
title,
width,
height,
url,
uid,
author,
nsfw_tag,
tags,
datetime.min,
datetime.min
):
logger.info(f"成功添加OmegaPixivIllusts图库数据 pid{pid} 本次预计存储 {length} 张,已更新第 {index}")
else:
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid{pid}")

View File

@ -4,16 +4,17 @@ from aiohttp.client_exceptions import (
ClientConnectorError,
)
from asyncpg.exceptions import UniqueViolationError
from models.omega_pixiv_illusts import OmegaPixivIllusts
from asyncio.locks import Semaphore
from aiohttp import ClientPayloadError
from aiohttp.client import ClientSession
from asyncio.exceptions import TimeoutError
from models.pixiv import Pixiv
from typing import List
from utils.utils import get_local_proxy
from utils.utils import get_local_proxy, change_picture_links
from utils.image_utils import CreateImg
from services.log import logger
from configs.config import HIBIAPI_BOOKMARKS, HIBIAPI
from configs.config import HIBIAPI_BOOKMARKS, HIBIAPI, PIX_IMAGE_SIZE
from configs.path_config import TEMP_PATH
import platform
import aiohttp
@ -215,19 +216,45 @@ async def download_image(img_url: str, session: ClientSession, _count: int = 1):
async def get_image(img_url: str, user_id: int) -> str:
try:
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get(
img_url,
proxy=get_local_proxy(),
) as response:
async with aiofiles.open(
f"{TEMP_PATH}/pix_{user_id}_{img_url[-10:-4]}.jpg", "wb"
) as f:
await f.write(await response.read())
return f"pix_{user_id}_{img_url[-10:-4]}.jpg"
except (ClientConnectorError, TimeoutError):
return await get_image(img_url, user_id)
async with aiohttp.ClientSession(headers=headers) as session:
if 'https://www.pixiv.net/artworks' in img_url:
pid = img_url.rsplit('/', maxsplit=1)[-1]
params = {"id": pid}
for _ in range(3):
try:
async with session.get(
illust_url,
params=params,
proxy=get_local_proxy(),
) as response:
if response.status == 200:
data = await response.json()
if data.get('illust'):
if data['illust']['page_count'] == 1:
img_url = data['illust']['meta_single_page']['original_image_url']
else:
img_url = data['illust']["meta_pages"][0]["image_urls"]["original"]
break
except (ClientConnectorError, TimeoutError):
pass
old_img_url = img_url
img_url = change_picture_links(img_url, PIX_IMAGE_SIZE)
for _ in range(3):
try:
async with session.get(
img_url,
proxy=get_local_proxy(),
) as response:
if response.status == 404:
img_url = old_img_url
continue
async with aiofiles.open(
f"{TEMP_PATH}/pix_{user_id}_{img_url[-10:-4]}.jpg", "wb"
) as f:
await f.write(await response.read())
return f"pix_{user_id}_{img_url[-10:-4]}.jpg"
except (ClientConnectorError, TimeoutError):
pass
# 检测UID或PID是否有效
@ -248,7 +275,9 @@ async def uid_pid_exists(id_: str) -> bool:
async def get_keyword_num(keyword: str) -> "int , int":
return await Pixiv.get_keyword_num(keyword.split())
count, r18_count = await Pixiv.get_keyword_num(keyword.split())
count_, setu_count, r18_count_ = await OmegaPixivIllusts.get_keyword_num(keyword.split())
return count, r18_count, count_, setu_count, r18_count_
async def remove_image(pid: int, img_p: str) -> bool:

View File

@ -1,17 +1,30 @@
from nonebot import on_command
from nonebot.adapters.cqhttp.event import GroupMessageEvent
from nonebot.adapters.cqhttp.message import Message
from utils.utils import get_message_text, is_number
from configs.config import PIX_OMEGA_PIXIV_RATIO, WITHDRAW_PIX_TIME
from models.omega_pixiv_illusts import OmegaPixivIllusts
from utils.message_builder import image
from services.log import logger
from nonebot.adapters.cqhttp import Bot, MessageEvent
from nonebot.adapters.cqhttp import (
Bot,
MessageEvent,
GroupMessageEvent,
PrivateMessageEvent,
)
from utils.static_data import withdraw_message_id_manager
from nonebot.typing import T_State
from .data_source import get_image
from models.pixiv import Pixiv
from nonebot import on_command
import random
pix = on_command("pix", aliases={"PIX"}, priority=5, block=True)
pix = on_command("pix", aliases={"PIX", "Pix"}, priority=5, block=True)
PIX_RATIO = PIX_OMEGA_PIXIV_RATIO[0] / (
PIX_OMEGA_PIXIV_RATIO[0] + PIX_OMEGA_PIXIV_RATIO[1]
)
OMEGA_RATIO = 1 - PIX_RATIO
@pix.handle()
@ -24,40 +37,97 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
pid = keyword.replace("pid", "").replace(":", "")
if not is_number(pid):
await pix.finish("PID必须是数字...", at_sender=True)
all_image = await Pixiv.query_images(pid=int(pid))
isr18 = 0 if isinstance(event, GroupMessageEvent) else 2
nsfw_tag = 0 if isinstance(event, GroupMessageEvent) else None
all_image = await Pixiv.query_images(pid=int(pid), r18=isr18)
if not all_image:
all_image = await OmegaPixivIllusts.query_images(
pid=int(pid), nsfw_tag=nsfw_tag
)
else:
x = keyword.split()
if '-s' in x:
x.remove('-s')
nsfw_tag = 1
elif '-r' in x:
x.remove('-r')
nsfw_tag = 2
else:
nsfw_tag = 0
if nsfw_tag != 0 and str(event.user_id) not in bot.config.superusers:
await pix.finish('你不能看这些噢,这些都是是留给管理员看的...')
if len(x) > 1:
if is_number(x[-1]):
num = int(x[-1])
if num > 11:
num = random.randint(1, 10)
await pix.send(f"太贪心了,就给你发 {num}张 好了")
if num > 10:
if str(event.user_id) not in bot.config.superusers or (
str(event.user_id) in bot.config.superusers and num > 30
):
num = random.randint(1, 10)
await pix.send(f"太贪心了,就给你发 {num}张 好了")
x = x[:-1]
keyword = " ".join(x)
all_image = await Pixiv.query_images(x)
pix_num = int(num * PIX_RATIO) + 15 if PIX_RATIO != 0 else 0
omega_num = num - pix_num + 15
tmp = await Pixiv.query_images(
x, r18=1 if nsfw_tag == 2 else 0, num=pix_num
) + await OmegaPixivIllusts.query_images(x, nsfw_tag=nsfw_tag, num=omega_num)
tmp_ = []
all_image = []
for x in tmp:
if x.pid not in tmp_:
all_image.append(x)
tmp_.append(x.pid)
if not all_image:
await pix.finish(f"未在图库中找到与 {keyword} 相关Tag/UID/PID的图片...", at_sender=True)
for _ in range(num):
img_url = None
author = None
if not all_image:
await pix.finish("坏了...发完了,没图了...")
img = random.choice(all_image)
all_image.remove(img)
img_url = img.img_url
if isinstance(img, OmegaPixivIllusts):
img_url = img.url
author = img.uname
print(img.nsfw_tag)
elif isinstance(img, Pixiv):
img_url = img.img_url
author = img.author
pid = img.pid
title = img.title
author = img.author
uid = img.uid
# tags = img.tags
await pix.send(
Message(
f"title{title}\n"
f"author{author}\n"
f"PID{pid}\nUID{uid}\n"
f"{image(await get_image(img_url, event.user_id), 'temp')}"
_img = await get_image(img_url, event.user_id)
if _img:
msg_id = await pix.send(
Message(
f"title{title}\n"
f"author{author}\n"
f"PID{pid}\nUID{uid}\n"
f"{image(_img, 'temp')}"
)
)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看PIX图库PID: {pid}"
)
else:
msg_id = await pix.send(f"下载图片似乎出了一点问题PID{pid}")
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看PIX图库PID: {pid},下载图片出错"
)
withdraw_message(event, msg_id["message_id"])
def withdraw_message(event: MessageEvent, id_: int):
if WITHDRAW_PIX_TIME[0]:
if (
(WITHDRAW_PIX_TIME[1] == 0 and isinstance(event, PrivateMessageEvent))
or (WITHDRAW_PIX_TIME[1] == 1 and isinstance(event, GroupMessageEvent))
or WITHDRAW_PIX_TIME[1] == 2
):
withdraw_message_id_manager["message_id"].append(
(id_, WITHDRAW_PIX_TIME[0])
)
)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看PIX图库PID: {pid}"
)

View File

@ -56,10 +56,16 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@show_pix.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
keyword = get_message_text(event.json())
count, r18_count = await get_keyword_num(keyword)
count, r18_count, count_, setu_count, r18_count_ = await get_keyword_num(keyword)
await show_pix.send(
f"PIX图库{keyword}\n"
f"总数:{count + r18_count}\n"
f"美图:{count}\n"
f"r18{r18_count}"
f"R18{r18_count}\n"
f"---------------\n"
f"Omega图库{keyword}\n"
f"总数:{count_ + setu_count + r18_count_}\n"
f"美图:{count_}\n"
f"色图:{setu_count}\n"
f"R18{r18_count_}"
)

View File

@ -1,17 +1,16 @@
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, Event, GroupMessageEvent, Message
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.matcher import Matcher
from nonebot import on_command
from utils.utils import get_message_text, UserExistLimiter, is_number
from utils.utils import get_message_text, is_number
from .data_source import get_pixiv_urls, download_pixiv_imgs, search_pixiv_urls
from utils.message_builder import at
from services.log import logger
from nonebot.adapters.cqhttp.exception import NetworkError
from asyncio.exceptions import TimeoutError
from aiohttp.client_exceptions import ClientConnectorError
from nonebot.exception import IgnoredException
from nonebot.message import run_preprocessor, run_postprocessor
from typing import Optional
from configs.config import NICKNAME
from typing import Type
from nonebot.rule import to_me
import time
__plugin_name__ = "P站"
@ -38,17 +37,13 @@ p站排行榜 [参数] [数量](可选) [日期](可选)
注意空格在线搜索会较慢
---------------------------------
'P站搜图帮助
可选参数
1.热度排序
2.时间排序
使用时选择参数序号即可R18仅可私聊
搜图 [关键词] [数量](可选) [排序方式](可选) [r18](可选)
搜图 [关键词] [数量](可选) [页数](可选默认1) [r18](不屏蔽R-18可选)
示例
搜图 樱岛麻衣
搜图 樱岛麻衣 5 1
搜图 樱岛麻衣 5 2 r18
搜图 樱岛麻衣 5
搜图 樱岛麻衣 5 r18
默认为 热度排序
注意空格在线搜索会较慢数量可能不符
注意空格在线搜索会较慢数量可能不符可能该页数量不够也可能被R-18屏蔽
"""
rank_dict = {
@ -63,142 +58,84 @@ rank_dict = {
"9": "week_r18g",
}
_ulmt = UserExistLimiter()
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if isinstance(event, MessageEvent):
if matcher.module == "pixiv":
if _ulmt.check(event.user_id):
if isinstance(event, GroupMessageEvent):
await bot.send_group_msg(
group_id=event.group_id,
message=Message(f"{at(event.user_id)}P站排行榜或搜图正在搜索噢不要重复触发命令呀"),
)
else:
await bot.send_private_msg(
user_id=event.user_id, message=f"P站排行榜或搜图正在搜索噢不要重复触发命令呀"
)
raise IgnoredException("pixiv插件正在访问")
@run_postprocessor
async def do_something(
matcher: Matcher,
exception: Optional[Exception],
bot: Bot,
event: Event,
state: T_State,
):
if isinstance(event, MessageEvent):
if matcher.module == "pixiv":
_ulmt.set_False(event.user_id)
pixiv_rank = on_command(
"p站排行", aliases={"P站排行榜", "p站排行榜", "P站排行榜"}, priority=5, block=True
"p站排行", aliases={"P站排行榜", "p站排行榜", "P站排行榜", "P站排行"}, priority=5, block=True, rule=to_me()
)
pixiv_keyword = on_command("搜图", priority=5, block=True)
pixiv_keyword = on_command("搜图", priority=5, block=True, rule=to_me())
@pixiv_rank.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json()).strip()
_ulmt.set_True(event.user_id)
msg = msg.split(" ")
msg = [m for m in msg if m]
code = 0
info_list = []
if not msg:
msg = ["1"]
if msg[0] in ["6", "7", "8", "9"]:
if event.message_type == "group":
await pixiv_rank.finish("羞羞脸!私聊里自己看!", at_sender=True)
if len(msg) == 0 or msg[0] == "":
text_list, urls, code = await get_pixiv_urls(rank_dict.get("1"))
elif len(msg) == 1:
if (n := len(msg)) == 0 or msg[0] == "":
info_list, code = await get_pixiv_urls(rank_dict.get("1"))
elif n == 1:
if msg[0] not in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:
await pixiv_rank.finish("要好好输入要看什么类型的排行榜呀!", at_sender=True)
text_list, urls, code = await get_pixiv_urls(rank_dict.get(msg[0]))
elif len(msg) == 2:
text_list, urls, code = await get_pixiv_urls(rank_dict.get(msg[0]), int(msg[1]))
elif len(msg) == 3:
info_list, code = await get_pixiv_urls(rank_dict.get(msg[0]))
elif n == 2:
info_list, code = await get_pixiv_urls(rank_dict.get(msg[0]), int(msg[1]))
elif n == 3:
if not check_date(msg[2]):
await pixiv_rank.finish("日期格式错误了", at_sender=True)
text_list, urls, code = await get_pixiv_urls(
rank_dict.get(msg[0]), int(msg[1]), msg[2]
info_list, code = await get_pixiv_urls(
rank_dict.get(msg[0]), int(msg[1]), date=msg[2]
)
else:
await pixiv_rank.finish("格式错了噢,看看帮助?", at_sender=True)
if code != 200:
await pixiv_keyword.finish(text_list[0])
else:
if not text_list or not urls:
await pixiv_rank.finish("没有找到啊,等等再试试吧~V", at_sender=True)
for i in range(len(text_list)):
try:
await pixiv_rank.send(
text_list[i] + await download_pixiv_imgs(urls[i], event.user_id)
)
except (NetworkError, TimeoutError, ClientConnectorError):
await pixiv_keyword.send("这张图网络炸了!", at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看了P站排行榜 code{msg[0]}"
)
await pixiv_rank.finish("格式错了噢,参数不够?看看帮助?", at_sender=True)
if code != 200 and info_list:
await pixiv_rank.finish(info_list[0])
if not info_list:
await pixiv_rank.finish("没有找到啊,等等再试试吧~V", at_sender=True)
await send_image(info_list, pixiv_rank, bot, event)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看了P站排行榜 code{msg[0]}"
)
@pixiv_keyword.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json()).strip()
_ulmt.set_True(event.user_id)
if event.message_type == "group":
if msg.find("r18") != -1:
msg = get_message_text(event.json())
if isinstance(event, GroupMessageEvent):
if 'r18' in msg.lower():
await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True)
if msg.find("r18") == -1:
r18 = 1
else:
r18 = 2
msg = msg.replace("r18", "").strip()
msg = msg.split(" ")
msg = [m for m in msg if m]
if len(msg) == 1:
keyword = msg[0].strip()
num = 5
order = "popular"
elif len(msg) == 2:
keyword = msg[0].strip()
if not is_number(msg[1].strip()):
r18 = 0 if 'r18' in msg else 1
msg = msg.replace("r18", "").strip().split()
msg = [m.strip() for m in msg if m]
keyword = None
info_list = None
num = 10
page = 1
if (n := len(msg)) == 1:
keyword = msg[0]
if n > 1:
if not is_number(msg[1]):
await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True)
num = int(msg[1].strip())
order = "popular"
elif len(msg) == 3:
keyword = msg[0].strip()
if not is_number(msg[1].strip()):
await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True)
num = int(msg[1].strip())
if not is_number(msg[2].strip()):
await pixiv_keyword.finish("排序方式必须是数字!", at_sender=True)
if msg[2].strip() == "1":
order = "popular"
else:
order = "xxx"
else:
await pixiv_keyword.finish("参数不正确,一定要好好看看帮助啊!", at_sender=True)
text_list, urls, code = await search_pixiv_urls(keyword, num, order, r18)
if code != 200:
await pixiv_keyword.finish(text_list[0])
else:
for i in range(len(text_list)):
try:
await pixiv_keyword.send(
text_list[i] + await download_pixiv_imgs(urls[i], event.user_id)
)
except (NetworkError, TimeoutError, ClientConnectorError):
await pixiv_keyword.send("这张图网络炸了!", at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})"
f" 查看了搜索 {keyword} R18{r18}"
)
num = int(msg[1])
if n > 2:
if not is_number(msg[2]):
await pixiv_keyword.finish("页数数量必须是数字!", at_sender=True)
page = int(msg[2])
if keyword:
info_list, code = await search_pixiv_urls(keyword, num, page, r18)
if code != 200:
await pixiv_keyword.finish(info_list[0])
await send_image(info_list, pixiv_keyword, bot, event)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看了搜索 {keyword} R18{r18}"
)
def check_date(date):
@ -207,3 +144,30 @@ def check_date(date):
return True
except:
return False
async def send_image(info_list: list, matcher: Type[Matcher], bot: Bot, event: MessageEvent):
if isinstance(event, GroupMessageEvent):
await pixiv_rank.send('开始下载整理数据...')
idx = 0
mes_list = []
for title, author, urls in info_list:
_message = f'title: {title}\nauthor: {author}\n' + await download_pixiv_imgs(urls, event.user_id, idx)
data = {
"type": "node",
"data": {
"name": f"这里是{NICKNAME}",
"uin": f"{bot.self_id}",
"content": _message,
},
}
mes_list.append(data)
idx += 1
await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
else:
for title, author, urls in info_list:
try:
await matcher.send(f'title: {title}\n'
f'author: {author}\n' + await download_pixiv_imgs(urls, event.user_id))
except (NetworkError, TimeoutError, ClientConnectorError):
await matcher.send("这张图网络直接炸掉了!", at_sender=True)

View File

@ -1,14 +1,13 @@
import aiohttp
import aiofiles
from configs.path_config import IMAGE_PATH
from utils.utils import get_local_proxy
from utils.user_agent import get_user_agent
from bs4 import BeautifulSoup
import feedparser
from utils.message_builder import image
from asyncio.exceptions import TimeoutError
from configs.config import RSSHUBAPP
from configs.config import HIBIAPI
from aiohttp.client_exceptions import ClientConnectorError
from typing import Optional
from pathlib import Path
import aiohttp
import aiofiles
import platform
if platform.system() == "Windows":
@ -17,82 +16,115 @@ if platform.system() == "Windows":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
async def get_pixiv_urls(mode: str, num: int = 5, date: str = "") -> "list, list, int":
url = f"{RSSHUBAPP}/pixiv/ranking/{mode}"
rank_url = f"{HIBIAPI}/api/pixiv/rank"
search_url = f"{HIBIAPI}/api/pixiv/search"
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
" rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Referer": "https://www.pixiv.net",
}
async def get_pixiv_urls(
mode: str, num: int = 10, page: int = 1, date: Optional[str] = None
) -> "list, int":
params = {"mode": mode, "page": page}
if date:
url += f"/{date}"
try:
return await parser_data(url, num)
except ClientConnectorError:
return await get_pixiv_urls(mode, num, date)
async def download_pixiv_imgs(urls: list, user_id: int) -> str:
result = ""
index = 0
for img in urls:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
for _ in range(3):
async with session.get(
img, proxy=get_local_proxy(), timeout=2
) as response:
async with aiofiles.open(
IMAGE_PATH + f"temp/{user_id}_{index}_pixiv.jpg", "wb"
) as f:
try:
await f.write(await response.read())
result += image(f"{user_id}_{index}_pixiv.jpg", "temp")
index += 1
break
except TimeoutError:
# result += '\n这张图下载失败了..\n'
pass
else:
result += "\n这张图下载失败了..\n"
return result
params["date"] = date
return await parser_data(rank_url, num, params, 'rank')
async def search_pixiv_urls(
keyword: str, num: int, order: str, r18: int
keyword: str, num: int, page: int, r18: int
) -> "list, list":
url = f"{RSSHUBAPP}/pixiv/search/{keyword}/{order}/{r18}"
return await parser_data(url, num)
params = {"word": keyword, 'page': page}
return await parser_data(search_url, num, params, 'search', r18)
async def parser_data(url: str, num: int) -> "list, list, int":
text_list = []
urls = []
async def parser_data(url: str, num: int, params: dict, type_: str, r18: int = 0) -> "list, int":
info_list = []
async with aiohttp.ClientSession() as session:
for _ in range(3):
try:
async with session.get(
url, proxy=get_local_proxy(), timeout=2
url, params=params, proxy=get_local_proxy(), timeout=5
) as response:
data = feedparser.parse(await response.text())["entries"]
break
except TimeoutError:
if response.status == 200:
data = await response.json()
if data.get("illusts"):
data = data["illusts"]
break
except (TimeoutError, ClientConnectorError):
pass
else:
return ["网络不太好,也许过一会就好了"], [], 998
try:
if len(data) == 0:
return ["没有搜索到喔"], [], 997
if num > len(data):
num = len(data)
data = data[:num]
for data in data:
soup = BeautifulSoup(data["summary"], "lxml")
title = "标题:" + data["title"]
pl = soup.find_all("p")
author = pl[0].text.split("-")[0].strip()
imgs = []
text_list.append(f"{title}\n{author}\n")
for p in pl[1:]:
imgs.append(p.find("img").get("src"))
urls.append(imgs)
except ValueError:
return ["是网站坏了啊,也许过一会就好了"], [], 999
return text_list, urls, 200
return ["网络不太好?没有该页数?也许过一会就好了..."], 998
num = num if num < 30 else 30
data = data[:num]
for x in data:
if type_ == 'search' and r18 == 1:
if 'R-18' in str(x['tags']):
continue
title = x["title"]
author = x["user"]["name"]
urls = []
if x["page_count"] == 1:
urls.append(x["image_urls"]["large"])
else:
for j in x["meta_pages"]:
urls.append(j["image_urls"]["large"])
info_list.append((title, author, urls))
return info_list, 200
# asyncio.get_event_loop().run_until_complete(get_pixiv_urls('day'))
async def download_pixiv_imgs(
urls: list, user_id: int, forward_msg_index: int = None
) -> str:
result = ""
index = 0
for url in urls:
async with aiohttp.ClientSession(headers=headers) as session:
for _ in range(3):
try:
async with session.get(
url, proxy=get_local_proxy(), timeout=3
) as response:
if response.status == 200:
try:
file = (
f"{IMAGE_PATH}/temp/{user_id}_{forward_msg_index}_{index}_pixiv.jpg"
if forward_msg_index is not None
else f"{IMAGE_PATH}/temp/{user_id}_{index}_pixiv.jpg"
)
file = Path(file)
if forward_msg_index is not None:
async with aiofiles.open(
file,
"wb",
) as f:
await f.write(await response.read())
result += image(
f"{user_id}_{forward_msg_index}_{index}_pixiv.jpg",
"temp",
)
else:
async with aiofiles.open(
file,
"wb",
) as f:
await f.write(await response.read())
result += image(
f"{user_id}_{index}_pixiv.jpg", "temp"
)
index += 1
break
except OSError:
file.unlink()
except (TimeoutError, ClientConnectorError):
# result += '\n这张图下载失败了..\n'
pass
else:
result += "\n这张图下载失败了..\n"
return result

View File

@ -43,7 +43,7 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
await reimu.finish("今天已经没车了,请明天再来...", at_sender=True)
if _ulmt.check(event.user_id):
await reimu.finish("您还没下车呢,请稍等...", at_sender=True)
_ulmt.set_True(event.user_id)
_ulmt.set_true(event.user_id)
msg = get_message_text(event.json())
args = msg.split(" ")
if msg in ["!", "", "?", "", ",", "", ".", ""]:
@ -70,9 +70,9 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
else:
logger.error("Not found reimuInfo")
await reimu.send("没找着")
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
except:
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
@scheduler.scheduled_job(

View File

@ -13,9 +13,9 @@ import time
from .data_source import rank
from configs.config import MAX_RUSSIAN_BET_GOLD, NICKNAME
__plugin_name__ = '俄罗斯轮盘'
__plugin_name__ = "俄罗斯轮盘"
__plugin_usage__ = '''俄罗斯轮盘帮助:
__plugin_usage__ = """俄罗斯轮盘帮助:
开启游戏装弹 [子弹数] [金额](默认200金币) [at](指定决斗对象为空则所有群友都可接受决斗)
示例装弹 1 10
接受对决接受对决/拒绝决斗
@ -24,24 +24,37 @@ __plugin_usage__ = '''俄罗斯轮盘帮助:
我的战绩我的战绩
排行榜胜场排行/败场排行/欧洲人排行/慈善家排行
同一时间群内只能有一场对决
'''
"""
rs_player = {}
rssian = on_command('俄罗斯轮盘', aliases={'装弹', '俄罗斯转盘'}, permission=GROUP, priority=5, block=True)
rssian = on_command(
"俄罗斯轮盘", aliases={"装弹", "俄罗斯转盘"}, permission=GROUP, priority=5, block=True
)
accept = on_command('接受对决', aliases={'接受决斗', '接受挑战'}, permission=GROUP, priority=5, block=True)
accept = on_command(
"接受对决", aliases={"接受决斗", "接受挑战"}, permission=GROUP, priority=5, block=True
)
refuse = on_command('拒绝对决', aliases={'拒绝决斗', '拒绝挑战'}, permission=GROUP, priority=5, block=True)
refuse = on_command(
"拒绝对决", aliases={"拒绝决斗", "拒绝挑战"}, permission=GROUP, priority=5, block=True
)
shot = on_command('开枪', aliases={'', '', ''}, permission=GROUP, priority=5, block=True)
shot = on_command(
"开枪", aliases={"", "", ""}, permission=GROUP, priority=5, block=True
)
settlement = on_command('结算', permission=GROUP, priority=5, block=True)
settlement = on_command("结算", permission=GROUP, priority=5, block=True)
record = on_command('我的战绩', permission=GROUP, priority=5, block=True)
record = on_command("我的战绩", permission=GROUP, priority=5, block=True)
rssian_rank = on_command('胜场排行', aliases={'胜利排行', '败场排行', '失败排行',
'欧洲人排行', '慈善家排行'}, permission=GROUP, priority=5, block=True)
rssian_rank = on_command(
"胜场排行",
aliases={"胜利排行", "败场排行", "失败排行", "欧洲人排行", "慈善家排行", "最高连胜排行", "最高连败排行"},
permission=GROUP,
priority=5,
block=True,
)
@accept.handle()
@ -49,38 +62,51 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
global rs_player
try:
if rs_player[event.group_id][1] == 0:
await accept.finish('目前没有发起对决,你接受个啥?速速装弹!', at_sender=True)
await accept.finish("目前没有发起对决,你接受个啥?速速装弹!", at_sender=True)
except KeyError:
await accept.finish('目前没有进行的决斗,请发送 装弹 开启决斗吧!', at_sender=True)
await accept.finish("目前没有进行的决斗,请发送 装弹 开启决斗吧!", at_sender=True)
if rs_player[event.group_id][2] != 0:
if rs_player[event.group_id][1] == event.user_id or rs_player[event.group_id][2] == event.user_id:
await accept.finish(f'你已经身处决斗之中了啊,给我认真一点啊!', at_sender=True)
if (
rs_player[event.group_id][1] == event.user_id
or rs_player[event.group_id][2] == event.user_id
):
await accept.finish(f"你已经身处决斗之中了啊,给我认真一点啊!", at_sender=True)
else:
await accept.finish('已经有人接受对决了,你还是乖乖等待下一场吧!', at_sender=True)
await accept.finish("已经有人接受对决了,你还是乖乖等待下一场吧!", at_sender=True)
if rs_player[event.group_id][1] == event.user_id:
await accept.finish('请不要自己枪毙自己!换人来接受对决...', at_sender=True)
if rs_player[event.group_id]['at'] != 0 and rs_player[event.group_id]['at'] != event.user_id:
await accept.finish(Message(f'这场对决是邀请 {at(rs_player[event.group_id]["at"])}的,不要捣乱!'), at_sender=True)
if time.time() - rs_player[event.group_id]['time'] > 30:
await accept.finish("请不要自己枪毙自己!换人来接受对决...", at_sender=True)
if (
rs_player[event.group_id]["at"] != 0
and rs_player[event.group_id]["at"] != event.user_id
):
await accept.finish(
Message(f'这场对决是邀请 {at(rs_player[event.group_id]["at"])}的,不要捣乱!'),
at_sender=True,
)
if time.time() - rs_player[event.group_id]["time"] > 30:
rs_player[event.group_id] = {}
await accept.finish('这场对决邀请已经过时了,请重新发起决斗...', at_sender=True)
await accept.finish("这场对决邀请已经过时了,请重新发起决斗...", at_sender=True)
user_money = await BagUser.get_gold(event.user_id, event.group_id)
if user_money < rs_player[event.group_id]['money']:
if rs_player[event.group_id]['at'] != 0 and rs_player[event.group_id]['at'] == event.user_id:
if user_money < rs_player[event.group_id]["money"]:
if (
rs_player[event.group_id]["at"] != 0
and rs_player[event.group_id]["at"] == event.user_id
):
rs_player[event.group_id] = {}
await accept.finish('你的金币不足以接受这场对决!对决还未开始便结束了,请重新装弹!', at_sender=True)
await accept.finish("你的金币不足以接受这场对决!对决还未开始便结束了,请重新装弹!", at_sender=True)
else:
await accept.finish('你的金币不足以接受这场对决!', at_sender=True)
await accept.finish("你的金币不足以接受这场对决!", at_sender=True)
player2_name = event.sender.card if event.sender.card else event.sender.nickname
rs_player[event.group_id][2] = event.user_id
rs_player[event.group_id]['player2'] = player2_name
rs_player[event.group_id]['time'] = time.time()
rs_player[event.group_id]["player2"] = player2_name
rs_player[event.group_id]["time"] = time.time()
await accept.send(Message(f'{player2_name}接受了对决!\n'
f'{at(rs_player[event.group_id][1])}先开枪!'))
await accept.send(
Message(f"{player2_name}接受了对决!\n" f"{at(rs_player[event.group_id][1])}先开枪!")
)
@refuse.handle()
@ -88,74 +114,107 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
global rs_player
try:
if rs_player[event.group_id][1] == 0:
await accept.finish('你要拒绝啥?明明都没有人发起对决的说!', at_sender=True)
await accept.finish("你要拒绝啥?明明都没有人发起对决的说!", at_sender=True)
except KeyError:
await refuse.finish('目前没有进行的决斗,请发送 装弹 开启决斗吧!', at_sender=True)
if rs_player[event.group_id]['at'] != 0 and event.user_id != rs_player[event.group_id]['at']:
await accept.finish('又不是找你决斗,你拒绝什么啊!气!', at_sender=True)
if rs_player[event.group_id]['at'] == event.user_id:
at_player_name = (await GroupInfoUser.get_member_info(event.user_id, event.group_id)).user_name
await accept.send(Message(f'{at(rs_player[event.group_id][1])}\n'
f'{at_player_name}拒绝了你的对决!'))
await refuse.finish("目前没有进行的决斗,请发送 装弹 开启决斗吧!", at_sender=True)
if (
rs_player[event.group_id]["at"] != 0
and event.user_id != rs_player[event.group_id]["at"]
):
await accept.finish("又不是找你决斗,你拒绝什么啊!气!", at_sender=True)
if rs_player[event.group_id]["at"] == event.user_id:
at_player_name = (
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
).user_name
await accept.send(
Message(f"{at(rs_player[event.group_id][1])}\n" f"{at_player_name}拒绝了你的对决!")
)
rs_player[event.group_id] = {}
@settlement.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
global rs_player
if not rs_player.get(event.group_id) or rs_player[event.group_id][1] == 0 or rs_player[event.group_id][2] == 0:
await settlement.finish('比赛并没有开始...无法结算...', at_sender=True)
if event.user_id != rs_player[event.group_id][1] and event.user_id != rs_player[event.group_id][2]:
await settlement.finish('吃瓜群众不要捣乱!黄牌警告!', at_sender=True)
if time.time() - rs_player[event.group_id]['time'] <= 30:
await settlement.finish(f'{rs_player[event.group_id]["player1"]}'
f' {rs_player[event.group_id]["player2"]} 比赛并未超时,请继续比赛...')
win_name = rs_player[event.group_id]["player1"] if \
rs_player[event.group_id][2] == rs_player[event.group_id]['next'] else \
rs_player[event.group_id]["player2"]
await settlement.send(f'这场对决是 {win_name} 胜利了')
if (
not rs_player.get(event.group_id)
or rs_player[event.group_id][1] == 0
or rs_player[event.group_id][2] == 0
):
await settlement.finish("比赛并没有开始...无法结算...", at_sender=True)
if (
event.user_id != rs_player[event.group_id][1]
and event.user_id != rs_player[event.group_id][2]
):
await settlement.finish("吃瓜群众不要捣乱!黄牌警告!", at_sender=True)
if time.time() - rs_player[event.group_id]["time"] <= 30:
await settlement.finish(
f'{rs_player[event.group_id]["player1"]}'
f' {rs_player[event.group_id]["player2"]} 比赛并未超时,请继续比赛...'
)
win_name = (
rs_player[event.group_id]["player1"]
if rs_player[event.group_id][2] == rs_player[event.group_id]["next"]
else rs_player[event.group_id]["player2"]
)
await settlement.send(f"这场对决是 {win_name} 胜利了")
await end_game(bot, event)
@rssian.args_parser
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg = get_message_text(event.json())
if msg in ['取消', '算了']:
await rssian.finish('已取消操作...')
if msg in ["取消", "算了"]:
await rssian.finish("已取消操作...")
try:
if rs_player[event.group_id][1] != 0:
await rssian.finish('决斗已开始...', at_sender=True)
await rssian.finish("决斗已开始...", at_sender=True)
except KeyError:
pass
if not is_number(msg):
await rssian.reject('输入子弹数量必须是数字啊喂!')
await rssian.reject("输入子弹数量必须是数字啊喂!")
if int(msg) < 1 or int(msg) > 6:
await rssian.reject('子弹数量必须大于0小于7')
state['bullet_num'] = int(msg)
await rssian.reject("子弹数量必须大于0小于7")
state["bullet_num"] = int(msg)
@rssian.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
global rs_player
msg = get_message_text(event.json())
if msg == '帮助':
if msg == "帮助":
await rssian.finish(__plugin_usage__)
try:
if rs_player[event.group_id][1] and not rs_player[event.group_id][2] and \
time.time() - rs_player[event.group_id]['time'] <= 30:
await rssian.finish(f'现在是 {rs_player[event.group_id]["player1"]} 发起的对决\n请等待比赛结束后再开始下一轮...')
if rs_player[event.group_id][1] and rs_player[event.group_id][2] and\
time.time() - rs_player[event.group_id]['time'] <= 30:
await rssian.finish(f'{rs_player[event.group_id]["player1"]}'
f' {rs_player[event.group_id]["player2"]}的对决还未结束!')
if rs_player[event.group_id][1] and rs_player[event.group_id][2] and\
time.time() - rs_player[event.group_id]['time'] > 30:
await shot.send('决斗已过时,强行结算...')
if (
rs_player[event.group_id][1]
and not rs_player[event.group_id][2]
and time.time() - rs_player[event.group_id]["time"] <= 30
):
await rssian.finish(
f'现在是 {rs_player[event.group_id]["player1"]} 发起的对决\n请等待比赛结束后再开始下一轮...'
)
if (
rs_player[event.group_id][1]
and rs_player[event.group_id][2]
and time.time() - rs_player[event.group_id]["time"] <= 30
):
await rssian.finish(
f'{rs_player[event.group_id]["player1"]}'
f' {rs_player[event.group_id]["player2"]}的对决还未结束!'
)
if (
rs_player[event.group_id][1]
and rs_player[event.group_id][2]
and time.time() - rs_player[event.group_id]["time"] > 30
):
await shot.send("决斗已过时,强行结算...")
await end_game(bot, event)
if not rs_player[event.group_id][2] and time.time() - rs_player[event.group_id]['time'] > 30:
if (
not rs_player[event.group_id][2]
and time.time() - rs_player[event.group_id]["time"] > 30
):
rs_player[event.group_id][1] = 0
rs_player[event.group_id][2] = 0
rs_player[event.group_id]['at'] = 0
rs_player[event.group_id]["at"] = 0
except KeyError:
pass
if msg:
@ -163,126 +222,167 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if len(msg) == 1:
msg = msg[0]
if is_number(msg) and not (int(msg) < 1 or int(msg) > 6):
state['bullet_num'] = int(msg)
state["bullet_num"] = int(msg)
else:
money = msg[1].strip()
msg = msg[0].strip()
if is_number(msg) and not (int(msg) < 1 or int(msg) > 6):
state['bullet_num'] = int(msg)
state["bullet_num"] = int(msg)
if is_number(money) and 0 < int(money) <= MAX_RUSSIAN_BET_GOLD:
state['money'] = int(money)
state["money"] = int(money)
else:
state['money'] = 200
await rssian.send(f'赌注金额超过限制MAX_RUSSIAN_BET_GOLD已改为200默认')
state['at'] = get_message_at(event.json())
state["money"] = 200
await rssian.send(f"赌注金额超过限制MAX_RUSSIAN_BET_GOLD已改为200默认")
state["at"] = get_message_at(event.json())
@rssian.got("bullet_num", prompt='请输入装填子弹的数量!(最多6颗)')
@rssian.got("bullet_num", prompt="请输入装填子弹的数量!(最多6颗)")
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
global rs_player
bullet_num = state['bullet_num']
at_ = state['at'] if state.get('at') else []
money = state['money'] if state.get('money') else 200
bullet_num = state["bullet_num"]
at_ = state["at"] if state.get("at") else []
money = state["money"] if state.get("money") else 200
user_money = await BagUser.get_gold(event.user_id, event.group_id)
if bullet_num < 0 or bullet_num > 6:
await rssian.reject('子弹数量必须大于0小于7速速重新装弹')
await rssian.reject("子弹数量必须大于0小于7速速重新装弹")
if money > MAX_RUSSIAN_BET_GOLD:
await rssian.finish(f'太多了!单次金额不能超过{MAX_RUSSIAN_BET_GOLD}', at_sender=True)
await rssian.finish(f"太多了!单次金额不能超过{MAX_RUSSIAN_BET_GOLD}", at_sender=True)
if money > user_money:
await rssian.finish('你没有足够的钱支撑起这场挑战', at_sender=True)
await rssian.finish("你没有足够的钱支撑起这场挑战", at_sender=True)
player1_name = event.sender.card if event.sender.card else event.sender.nickname
if at_:
at_ = at_[0]
try:
at_player_name = (await GroupInfoUser.get_member_info(at_, event.group_id)).user_name
at_player_name = (
await GroupInfoUser.get_member_info(at_, event.group_id)
).user_name
except AttributeError:
at_player_name = at(at_)
msg = f'{player1_name}{at(at_)} 发起了决斗!请 {at_player_name} 在30秒内回复接受对决 or ‘拒绝对决’,超时此次决斗作废!'
msg = f"{player1_name}{at(at_)} 发起了决斗!请 {at_player_name} 在30秒内回复接受对决 or ‘拒绝对决’,超时此次决斗作废!"
else:
at_ = 0
msg = '若30秒内无人接受挑战则此次对决作废【首次游玩请发送 ’俄罗斯轮盘帮助‘ 来查看命令】'
msg = "若30秒内无人接受挑战则此次对决作废【首次游玩请发送 ’俄罗斯轮盘帮助‘ 来查看命令】"
rs_player[event.group_id] = {1: event.user_id,
'player1': player1_name,
2: 0,
'player2': '',
'at': at_,
'next': event.user_id,
'money': money,
'bullet': random_bullet(bullet_num),
'bullet_num': bullet_num,
'null_bullet_num': 7 - bullet_num,
'index': 0,
'time': time.time()}
rs_player[event.group_id] = {
1: event.user_id,
"player1": player1_name,
2: 0,
"player2": "",
"at": at_,
"next": event.user_id,
"money": money,
"bullet": random_bullet(bullet_num),
"bullet_num": bullet_num,
"null_bullet_num": 7 - bullet_num,
"index": 0,
"time": time.time(),
}
await rssian.send(Message(('' * bullet_num)[:-1] + f',装填完毕\n挑战金额:{money}\n'
f'第一枪的概率为:{str(float(bullet_num) / 7.0 * 100)[:5]}%\n'
f'{msg}'))
await rssian.send(
Message(
("" * bullet_num)[:-1] + f",装填完毕\n挑战金额:{money}\n"
f"第一枪的概率为:{str(float(bullet_num) / 7.0 * 100)[:5]}%\n"
f"{msg}"
)
)
@shot.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
global rs_player
try:
if time.time() - rs_player[event.group_id]['time'] > 30:
if time.time() - rs_player[event.group_id]["time"] > 30:
if rs_player[event.group_id][2] == 0:
rs_player[event.group_id][1] = 0
await shot.finish('这场对决已经过时了,请重新装弹吧!', at_sender=True)
await shot.finish("这场对决已经过时了,请重新装弹吧!", at_sender=True)
else:
await shot.send('决斗已过时,强行结算...')
await shot.send("决斗已过时,强行结算...")
await end_game(bot, event)
return
except KeyError:
await shot.finish('目前没有进行的决斗,请发送 装弹 开启决斗吧!', at_sender=True)
await shot.finish("目前没有进行的决斗,请发送 装弹 开启决斗吧!", at_sender=True)
if rs_player[event.group_id][1] == 0:
await shot.finish('没有对决,也还没装弹呢,请先输入 装弹 吧!', at_sender=True)
if rs_player[event.group_id][1] == event.user_id and rs_player[event.group_id][2] == 0:
await shot.finish('baka你是要枪毙自己嘛笨蛋', at_sender=True)
await shot.finish("没有对决,也还没装弹呢,请先输入 装弹 吧!", at_sender=True)
if (
rs_player[event.group_id][1] == event.user_id
and rs_player[event.group_id][2] == 0
):
await shot.finish("baka你是要枪毙自己嘛笨蛋", at_sender=True)
if rs_player[event.group_id][2] == 0:
await shot.finish('请这位勇士先发送 接受对决 来站上擂台...', at_sender=True)
player1_name = rs_player[event.group_id]['player1']
player2_name = rs_player[event.group_id]['player2']
if rs_player[event.group_id]['next'] != event.user_id:
if event.user_id != rs_player[event.group_id][1] and event.user_id != rs_player[event.group_id][2]:
await shot.finish(random.choice([
f'不要打扰 {player1_name}{player2_name} 的决斗啊!',
f'给我好好做好一个观众!不然{NICKNAME}就要生气了',
f'不要捣乱啊baka{(await GroupInfoUser.get_member_info(event.user_id, event.group_id)).user_name}'
]), at_sender=True)
await shot.finish(f'你的左轮不是连发的!该 '
f'{(await GroupInfoUser.get_member_info(int(rs_player[event.group_id]["next"]), event.group_id)).user_name} 开枪了')
if rs_player[event.group_id]['bullet'][rs_player[event.group_id]['index']] != 1:
await shot.send(Message(random.choice([
'呼呼,没有爆裂的声响,你活了下来',
'虽然黑洞洞的枪口很恐怖,但好在没有子弹射出来,你活下来了',
'\"\",你没死,看来运气不错',
]) + f'\n下一枪中弹的概率'
f'{str(float((rs_player[event.group_id]["bullet_num"])) / float(rs_player[event.group_id]["null_bullet_num"] - 1 + rs_player[event.group_id]["bullet_num"]) * 100)[:5]}%\n'
f'轮到 {at(rs_player[event.group_id][1] if event.user_id == rs_player[event.group_id][2] else rs_player[event.group_id][2])}'))
await shot.finish("请这位勇士先发送 接受对决 来站上擂台...", at_sender=True)
player1_name = rs_player[event.group_id]["player1"]
player2_name = rs_player[event.group_id]["player2"]
if rs_player[event.group_id]["next"] != event.user_id:
if (
event.user_id != rs_player[event.group_id][1]
and event.user_id != rs_player[event.group_id][2]
):
await shot.finish(
random.choice(
[
f"不要打扰 {player1_name}{player2_name} 的决斗啊!",
f"给我好好做好一个观众!不然{NICKNAME}就要生气了",
f"不要捣乱啊baka{(await GroupInfoUser.get_member_info(event.user_id, event.group_id)).user_name}",
]
),
at_sender=True,
)
await shot.finish(
f"你的左轮不是连发的!该 "
f'{(await GroupInfoUser.get_member_info(int(rs_player[event.group_id]["next"]), event.group_id)).user_name} 开枪了'
)
if rs_player[event.group_id]["bullet"][rs_player[event.group_id]["index"]] != 1:
await shot.send(
Message(
random.choice(
[
"呼呼,没有爆裂的声响,你活了下来",
"虽然黑洞洞的枪口很恐怖,但好在没有子弹射出来,你活下来了",
'"",你没死,看来运气不错',
]
)
+ f"\n下一枪中弹的概率"
f'{str(float((rs_player[event.group_id]["bullet_num"])) / float(rs_player[event.group_id]["null_bullet_num"] - 1 + rs_player[event.group_id]["bullet_num"]) * 100)[:5]}%\n'
f"轮到 {at(rs_player[event.group_id][1] if event.user_id == rs_player[event.group_id][2] else rs_player[event.group_id][2])}"
)
)
rs_player[event.group_id]["null_bullet_num"] -= 1
rs_player[event.group_id]['next'] = rs_player[event.group_id][1] if \
event.user_id == rs_player[event.group_id][2] else rs_player[event.group_id][2]
rs_player[event.group_id]['time'] = time.time()
rs_player[event.group_id]['index'] += 1
rs_player[event.group_id]["next"] = (
rs_player[event.group_id][1]
if event.user_id == rs_player[event.group_id][2]
else rs_player[event.group_id][2]
)
rs_player[event.group_id]["time"] = time.time()
rs_player[event.group_id]["index"] += 1
else:
await shot.send(random.choice([
'\"嘭!\",你直接去世了',
'眼前一黑,你直接穿越到了异世界...(死亡)',
'终究还是你先走一步...',
]) + f'\n{rs_player[event.group_id]["index"] + 1} 发子弹送走了你...', at_sender=True)
win_name = player1_name if event.user_id == rs_player[event.group_id][2] else player2_name
await shot.send(
random.choice(
[
'"嘭!",你直接去世了',
"眼前一黑,你直接穿越到了异世界...(死亡)",
"终究还是你先走一步...",
]
)
+ f'\n{rs_player[event.group_id]["index"] + 1} 发子弹送走了你...',
at_sender=True,
)
win_name = (
player1_name
if event.user_id == rs_player[event.group_id][2]
else player2_name
)
await asyncio.sleep(0.5)
await shot.send(f'这场对决是 {win_name} 胜利了')
await shot.send(f"这场对决是 {win_name} 胜利了")
await end_game(bot, event)
async def end_game(bot: Bot, event: GroupMessageEvent):
global rs_player
player1_name = rs_player[event.group_id]['player1']
player2_name = rs_player[event.group_id]['player2']
if rs_player[event.group_id]['next'] == rs_player[event.group_id][1]:
player1_name = rs_player[event.group_id]["player1"]
player2_name = rs_player[event.group_id]["player2"]
if rs_player[event.group_id]["next"] == rs_player[event.group_id][1]:
win_user_id = rs_player[event.group_id][2]
lose_user_id = rs_player[event.group_id][1]
win_name = player2_name
@ -293,60 +393,74 @@ async def end_game(bot: Bot, event: GroupMessageEvent):
win_name = player1_name
lose_name = player2_name
rand = random.randint(0, 5)
money = rs_player[event.group_id]['money']
money = rs_player[event.group_id]["money"]
if money > 10:
fee = int(money * float(rand) / 100)
fee = 1 if fee < 1 and rand != 0 else fee
else:
fee = 0
await RussianUser.add_count(win_user_id, event.group_id, 'win')
await RussianUser.add_count(lose_user_id, event.group_id, 'lose')
await RussianUser.money(win_user_id, event.group_id, 'win', money - fee)
await RussianUser.money(lose_user_id, event.group_id, 'lose', money)
await RussianUser.add_count(win_user_id, event.group_id, "win")
await RussianUser.add_count(lose_user_id, event.group_id, "lose")
await RussianUser.money(win_user_id, event.group_id, "win", money - fee)
await RussianUser.money(lose_user_id, event.group_id, "lose", money)
await BagUser.add_gold(win_user_id, event.group_id, money - fee)
await BagUser.spend_gold(lose_user_id, event.group_id, money)
win_user = await RussianUser.ensure(win_user_id, event.group_id)
lose_user = await RussianUser.ensure(lose_user_id, event.group_id)
bullet_str = ''
for x in rs_player[event.group_id]['bullet']:
bullet_str += '__ ' if x == 0 else '| '
logger.info(f'俄罗斯轮盘:胜者:{win_name} - 败者:{lose_name} - 金币:{money}')
await bot.send(event, message=f'结算:\n'
f'\t胜者:{win_name}\n'
f'\t赢取金币:{money - fee}\n'
f'\t累计胜场:{win_user.win_count}\n'
f'\t累计赚取金币:{win_user.make_money}\n'
f'-------------------\n'
f'\t败者:{lose_name}\n'
f'\t输掉金币:{money}\n'
f'\t累计败场:{lose_user.fail_count}\n'
f'\t累计输掉金币:{lose_user.lose_money}\n'
f'-------------------\n'
f'哼哼,{NICKNAME}从中收取了 {float(rand)}%({fee}金币) 作为手续费!\n'
f'子弹排列:{bullet_str[:-1]}')
bullet_str = ""
for x in rs_player[event.group_id]["bullet"]:
bullet_str += "__ " if x == 0 else "| "
logger.info(f"俄罗斯轮盘:胜者:{win_name} - 败者:{lose_name} - 金币:{money}")
await bot.send(
event,
message=f"结算:\n"
f"\t胜者:{win_name}\n"
f"\t赢取金币:{money - fee}\n"
f"\t累计胜场:{win_user.win_count}\n"
f"\t累计赚取金币:{win_user.make_money}\n"
f"-------------------\n"
f"\t败者:{lose_name}\n"
f"\t输掉金币:{money}\n"
f"\t累计败场:{lose_user.fail_count}\n"
f"\t累计输掉金币:{lose_user.lose_money}\n"
f"-------------------\n"
f"哼哼,{NICKNAME}从中收取了 {float(rand)}%({fee}金币) 作为手续费!\n"
f"子弹排列:{bullet_str[:-1]}",
)
rs_player[event.group_id] = {}
@record.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
user = await RussianUser.ensure(event.user_id, event.group_id)
await record.send(f'俄罗斯轮盘\n'
f'胜利场次:{user.win_count}\n'
f'失败场次:{user.fail_count}\n'
f'赚取金币:{user.make_money}\n'
f'输掉金币:{user.lose_money}', at_sender=True)
await record.send(
f"俄罗斯轮盘\n"
f"总胜利场次:{user.win_count}\n"
f"当前连胜:{user.winning_streak}\n"
f"最高连胜:{user.max_winning_streak}\n"
f"总失败场次:{user.fail_count}\n"
f"当前连败:{user.losing_streak}\n"
f"最高连败:{user.max_losing_streak}\n"
f"赚取金币:{user.make_money}\n"
f"输掉金币:{user.lose_money}",
at_sender=True,
)
@rssian_rank.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if state["_prefix"]["raw_command"] in ['胜场排行', '胜利排行']:
await rssian_rank.finish(await rank(event.group_id, 'win_rank'))
if state["_prefix"]["raw_command"] in ['败场排行', '失败排行']:
await rssian_rank.finish(await rank(event.group_id, 'lose_rank'))
if state["_prefix"]["raw_command"] == '欧洲人排行':
await rssian_rank.finish(await rank(event.group_id, 'make_money'))
if state["_prefix"]["raw_command"] == '慈善家排行':
await rssian_rank.finish(await rank(event.group_id, 'spend_money'))
if state["_prefix"]["raw_command"] in ["胜场排行", "胜利排行"]:
await rssian_rank.finish(await rank(event.group_id, "win_rank"))
if state["_prefix"]["raw_command"] in ["败场排行", "失败排行"]:
await rssian_rank.finish(await rank(event.group_id, "lose_rank"))
if state["_prefix"]["raw_command"] == "欧洲人排行":
await rssian_rank.finish(await rank(event.group_id, "make_money"))
if state["_prefix"]["raw_command"] == "慈善家排行":
await rssian_rank.finish(await rank(event.group_id, "spend_money"))
if state["_prefix"]["raw_command"] == "最高连胜排行":
await rssian_rank.finish(await rank(event.group_id, "max_winning_streak"))
if state["_prefix"]["raw_command"] == "最高连败排行":
await rssian_rank.finish(await rank(event.group_id, "max_losing_streak"))
# 随机子弹排列

View File

@ -14,9 +14,15 @@ async def rank(group_id: int, itype) -> str:
elif itype == 'make_money':
rank_name = '\t赢取金币排行榜\n'
all_user_data = [user.make_money for user in all_users]
else:
elif itype == 'spend_money':
rank_name = '\t输掉金币排行榜\n'
all_user_data = [user.lose_money for user in all_users]
elif itype == 'max_winning_streak':
rank_name = '\t最高连胜排行榜\n'
all_user_data = [user.max_winning_streak for user in all_users]
else:
rank_name = '\t最高连败排行榜\n'
all_user_data = [user.max_losing_streak for user in all_users]
rst = ''
if all_users:
rst = await init_rank(all_user_id, all_user_data, group_id)

View File

@ -31,7 +31,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
async def _(bot: Bot, event: MessageEvent, state: T_State):
if _ulmt.check(event.user_id):
await search_anime.finish("您有动漫正在搜索,请稍等...", at_sender=True)
_ulmt.set_True(event.user_id)
_ulmt.set_true(event.user_id)
if get_message_text(event.json()):
state["anime"] = get_message_text(event.json())
@ -55,4 +55,4 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
else:
logger.warning(f"未找到番剧 {key_word}")
await search_anime.send(f"未找到番剧 {key_word}(也有可能是超时,再尝试一下?)")
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)

View File

@ -44,7 +44,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@search_skin.got("skin", prompt="要查询该武器的什么皮肤呢?")
async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
result = ""
_ulmt.set_True(event.user_id)
_ulmt.set_true(event.user_id)
if state["name"] in ["ak", "ak47"]:
state["name"] = "ak-47"
name = state["name"] + " | " + state["skin"]
@ -53,7 +53,7 @@ async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
except FileNotFoundError:
await search_skin.finish(F'请先对{NICKNAME}"设置cookie"来设置cookie')
if status_code in [996, 997, 998]:
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
await search_skin.finish(result)
if result:
logger.info(
@ -61,7 +61,7 @@ async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询皮肤:"
+ name
)
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
await search_skin.finish(result)
else:
logger.info(
@ -69,7 +69,7 @@ async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}"
f" 查询皮肤:{name} 没有查询到"
)
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)
await search_skin.finish("没有查询到哦,请检查格式吧")

View File

@ -37,7 +37,6 @@ cmd = set(IMAGE_DIR_LIST)
send_img = on_command("img", aliases=cmd, priority=5, block=True)
pa = on_keyword({"丢人爬", "爪巴"}, priority=5, block=True)
pa_reg = on_regex("^爬$", priority=5, block=True)
search_img = on_regex(".*[份|发|张|个|次|点]图.*?", priority=6, block=True)
search_url = "https://api.fantasyzone.cc/tu/search.php"
@ -112,70 +111,3 @@ num_key = {
"": 9,
}
@search_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
r = re.search("[来要]?(.*)[份发张个次点]图(.*)", msg)
num = r.group(1)
if num in num_key.keys():
num = num_key[num]
elif is_number(num):
num = int(num)
else:
return
keyword = r.group(2)
params = {"search": keyword, "r18": 0}
async with aiohttp.ClientSession() as session:
exists_id = []
for _ in range(num):
for _ in range(10):
try:
async with session.get(
search_url, timeout=5, params=params
) as response:
data = json.loads(await response.text())
except TimeoutError:
pass
else:
if data["id"] == "null":
await send_img.finish(f"没有搜索到 {keyword} 的图片...", at_sender=True)
if data["id"] in exists_id:
continue
title = data["title"]
author = data["userName"]
pid = data["id"]
img_url = data["url"]
exists_id.append(pid)
for _ in range(5):
try:
await download_pic(img_url, event.user_id, session)
except TimeoutError:
pass
else:
break
else:
await search_img.finish("图片下载失败...", at_sender=True)
await search_img.send(
Message(
f"title{title}\n"
f"pid{pid}\n"
f"author{author}\n"
f'{image(f"send_img_{event.user_id}.png", "temp")}'
)
)
break
else:
await search_img.send("图片下载惜败了....", at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送搜索了 {num}{keyword} 的图片"
)
async def download_pic(img_url: str, user_id: int, session):
async with session.get(img_url, timeout=2) as res:
async with aiofiles.open(
f"{IMAGE_PATH}/temp/send_img_{user_id}.png", "wb"
) as f:
await f.write(await res.read())

View File

@ -1,15 +1,12 @@
import random
from nonebot import on_command, on_regex
from services.log import logger
from models.sigin_group_user import SignGroupUser
from nonebot.exception import IgnoredException
from nonebot.message import run_preprocessor, run_postprocessor
from models.sign_group_user import SignGroupUser
from nonebot.message import run_postprocessor
from nonebot.matcher import Matcher
from typing import Optional, Type
from gino.exceptions import UninitializedError
from utils.utils import (
FreqLimiter,
UserExistLimiter,
is_number,
get_message_text,
get_message_imgs,
@ -35,9 +32,8 @@ from .data_source import (
)
from nonebot.adapters.cqhttp.exception import ActionFailed
from configs.config import ONLY_USE_LOCAL_SETU, WITHDRAW_SETU_TIME, NICKNAME
from utils.message_builder import at
from utils.static_data import withdraw_message_id_manager
import re
import asyncio
try:
import ujson as json
@ -65,27 +61,7 @@ __plugin_usage__ = f"""示例:
色图 萝莉|少女 白丝|黑丝
色图 萝莉 猫娘"""
_flmt = FreqLimiter(5)
_ulmt = UserExistLimiter()
setu_data_list = []
withdraw_message_id = []
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
if isinstance(event, MessageEvent):
if matcher.module == "send_setu":
if _ulmt.check(event.user_id):
if isinstance(event, GroupMessageEvent):
await bot.send_group_msg(
group_id=event.group_id,
message=Message(f"{at(event.user_id)}您有色图正在处理,请稍等....."),
)
else:
await bot.send_private_msg(
user_id=event.user_id, message=f"您有色图正在处理,请稍等....."
)
raise IgnoredException("色图正在处理!")
@run_postprocessor
@ -96,17 +72,9 @@ async def do_something(
event: Event,
state: T_State,
):
global setu_data_list, withdraw_message_id
global setu_data_list
if isinstance(event, MessageEvent):
if matcher.module == "send_setu":
# 解除占用
_ulmt.set_False(event.user_id)
tasks = []
# 撤回色图
for id_ in withdraw_message_id[:]:
tasks.append(asyncio.ensure_future(withdraw_message(bot, event, id_)))
withdraw_message_id.remove(id_)
await asyncio.gather(*tasks)
# 添加数据至数据库
try:
await add_data_to_database(setu_data_list)
@ -127,7 +95,6 @@ find_setu = on_command("查色图", priority=5, block=True)
@setu.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
global withdraw_message_id
msg = get_message_text(event.json())
if isinstance(event, GroupMessageEvent):
impression = (
@ -136,10 +103,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
luox = get_luoxiang(impression)
if luox:
await setu.finish(luox)
_ulmt.set_True(event.user_id)
if not _flmt.check(event.user_id):
await setu.finish("您冲得太快了,请稍候再冲", at_sender=True)
_flmt.start_cd(event.user_id)
r18 = 0
num = 1
# 是否看r18
@ -166,7 +129,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送色图 {setu_list[0].local_id}.png"
)
withdraw_message_id.append(msg_id["message_id"])
if msg_id:
withdraw_message(event, msg_id["message_id"])
return
await send_setu_handle(setu, event, state["_prefix"]["raw_command"], msg, num, r18)
@ -195,9 +159,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
luox = get_luoxiang(impression)
if luox:
await setu.finish(luox, at_sender=True)
if not _flmt.check(event.user_id):
await setu.finish("您冲得太快了,请稍候再冲", at_sender=True)
_flmt.start_cd(event.user_id)
msg = get_message_text(event.json())
num = 1
msg = re.search(r"(.*)[份发张个次点](.*)[瑟涩色]图", msg)
@ -251,16 +212,16 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
async def send_setu_handle(
matcher: Type[Matcher], event: MessageEvent, command: str, msg: str, num: int, r18: int
):
global setu_data_list, withdraw_message_id
error_info = ""
global setu_data_list
# 非 id在线搜索
tags = msg.split()
# 真寻的色图?怎么可能
if f"{NICKNAME}" in tags:
await matcher.finish("咳咳咳,虽然我很可爱,但是我木有自己的色图~~~有的话记得发我一份呀")
# 本地先拿图,下载失败补上去
setu_list, code = await get_setu_list(tags=msg.split(), r18=r18)
if not ONLY_USE_LOCAL_SETU and (tags or not setu_list or num > len(setu_list)):
setu_list, code = None, 200
msg_id = None
if not ONLY_USE_LOCAL_SETU and tags:
# 先尝试获取在线图片
urls, text_list, add_databases_list, code = await get_setu_urls(tags, num, r18, command)
for x in add_databases_list:
@ -280,8 +241,9 @@ async def send_setu_handle(
f" 发送色图 {index}.png"
)
msg_id = await matcher.send(Message(f"{text_list[i]}\n{setu_img}"))
withdraw_message_id.append(msg_id["message_id"])
else:
if setu_list is None:
setu_list, _ = await get_setu_list(tags=tags, r18=r18)
if setu_list:
setu_image = random.choice(setu_list)
setu_list.remove(setu_image)
@ -298,17 +260,18 @@ async def send_setu_handle(
)
else:
msg_id = await matcher.send(text_list[i] + "\n" + setu_img)
withdraw_message_id.append(msg_id["message_id"])
if msg_id:
withdraw_message(event, msg_id["message_id"])
except ActionFailed:
await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
return
# 本地无图 或 超过上下限
if code != 200 or (not setu_list and ONLY_USE_LOCAL_SETU):
if code == 999:
await matcher.finish('网络连接失败...', at_sender=True)
await matcher.finish(setu_list[0], at_sender=True)
elif not setu_list:
await matcher.finish(error_info, at_sender=True)
if code != 200:
await matcher.finish('网络连接失败...', at_sender=True)
if setu_list is None:
setu_list, code = await get_setu_list(tags=tags, r18=r18)
if code != 200:
await matcher.finish(setu_list[0], at_sender=True)
# 开始发图
for _ in range(num):
if not setu_list:
@ -322,7 +285,7 @@ async def send_setu_handle(
+ (await check_local_exists_or_download(setu_image))[0]
)
)
withdraw_message_id.append(msg_id["message_id"])
withdraw_message(event, msg_id["message_id"])
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
@ -333,13 +296,11 @@ async def send_setu_handle(
# 撤回图片
async def withdraw_message(bot: Bot, event: MessageEvent, id_: int):
def withdraw_message(event: MessageEvent, id_: int):
if WITHDRAW_SETU_TIME[0]:
if (
(WITHDRAW_SETU_TIME[1] == 0 and isinstance(event, PrivateMessageEvent))
or (WITHDRAW_SETU_TIME[1] == 1 and isinstance(event, GroupMessageEvent))
or WITHDRAW_SETU_TIME[1] == 2
):
await asyncio.sleep(WITHDRAW_SETU_TIME[0])
await bot.delete_msg(message_id=id_, self_id=int(bot.self_id))
logger.info(f"自动撤回色图 消息id{id_}")
withdraw_message_id_manager['message_id'].append((id_, WITHDRAW_SETU_TIME[0]))

View File

@ -62,6 +62,8 @@ async def get_setu_urls(
for x in random_idx:
x_urls.append(urls[x])
x_text_lst.append(text_list[x])
if not x_urls:
return ["没找到符合条件的色图..."], [], [], 401
return x_urls, x_text_lst, add_databases_list, 200
else:
return ["没找到符合条件的色图..."], [], [], 401

View File

@ -23,6 +23,7 @@ from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from datetime import datetime, timedelta
from configs.config import NICKNAME
from apscheduler.jobstores.base import ConflictingIdError
import random
import time

View File

@ -1,15 +1,14 @@
from models.sigin_group_user import SignGroupUser
from models.sign_group_user import SignGroupUser
async def effect(user_id: int, group_id: int, name: str) -> bool:
if name == "好感双倍加持卡Ⅰ":
if name in ["好感双倍加持卡Ⅰ", "好感度双倍加持卡Ⅰ"]:
user = await SignGroupUser.ensure(user_id, group_id)
await user.update(add_probability=0.1).apply()
if name == "好感双倍加持卡Ⅱ":
if name in ["好感双倍加持卡Ⅱ", "好感度双倍加持卡Ⅱ"]:
user = await SignGroupUser.ensure(user_id, group_id)
await user.update(add_probability=0.2).apply()
if name == "好感双倍加持卡Ⅲ":
if name in ["好感双倍加持卡Ⅲ", "好感度双倍加持卡Ⅲ"]:
user = await SignGroupUser.ensure(user_id, group_id)
print(user.user_qq)
await user.update(add_probability=0.3).apply()
return True

View File

@ -9,9 +9,11 @@ from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from nonebot.adapters.cqhttp.permission import GROUP
from utils.message_builder import image
from nonebot import on_command
from utils.utils import get_message_text
from utils.utils import get_message_text, scheduler
from pathlib import Path
from configs.path_config import DATA_PATH
from services.log import logger
from .utils import clear_sign_data_pic
try:
import ujson as json
@ -52,16 +54,18 @@ total_sign_rank = on_command(
@sign.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
nickname = event.sender.card if event.sender.card else event.sender.nickname
await sign.send(
await group_user_check_in(event.user_id, event.group_id),
await group_user_check_in(nickname, event.user_id, event.group_id),
at_sender=True,
)
@my_sign.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
nickname = event.sender.card if event.sender.card else event.sender.nickname
await my_sign.send(
await group_user_check(event.user_id, event.group_id),
await group_user_check(nickname, event.user_id, event.group_id),
at_sender=True,
)
@ -89,3 +93,15 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await total_sign_rank.send("设置成功,签到总榜将会显示您的头像名称以及好感度!", at_sender=True)
with open(_file, "w", encoding="utf8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
@scheduler.scheduled_job(
'interval',
hours=1,
)
async def _():
try:
clear_sign_data_pic()
logger.info('清理日常签到图片数据数据完成....')
except Exception as e:
logger.error(f'清理日常签到图片数据数据失败..{type(e)}: {e}')

76
plugins/sign_in/config.py Normal file
View File

@ -0,0 +1,76 @@
from configs.path_config import IMAGE_PATH
from pathlib import Path
SIGN_RESOURCE_PATH = Path(IMAGE_PATH) / 'sign' / 'sign_res'
SIGN_TODAY_CARD_PATH = Path(IMAGE_PATH) / 'sign' / 'today_card'
SIGN_BORDER_PATH = Path(SIGN_RESOURCE_PATH) / 'border'
SIGN_BACKGROUND_PATH = Path(SIGN_RESOURCE_PATH) / 'background'
SIGN_TODAY_CARD_PATH.mkdir(exist_ok=True, parents=True)
SIGN_BORDER_PATH.mkdir(exist_ok=True, parents=True)
SIGN_BACKGROUND_PATH.mkdir(exist_ok=True, parents=True)
SIGN_CARD1_PROB = 0.2 # 好感度双倍加持卡Ⅰ
SIGN_CARD2_PROB = 0.09 # 好感度双倍加持卡Ⅱ
SIGN_CARD3_PROB = 0.05 # 好感度双倍加持卡Ⅲ
PROB_DATA = {
SIGN_CARD3_PROB: '好感度双倍加持卡Ⅲ',
SIGN_CARD2_PROB: '好感度双倍加持卡Ⅱ',
SIGN_CARD1_PROB: '好感度双倍加持卡Ⅰ'
}
lik2relation = {
'0': '路人',
'1': '陌生',
'2': '初识',
'3': '普通',
'4': '熟悉',
'5': '信赖',
'6': '相知',
'7': '厚谊',
'8': '亲密'
}
level2attitude = {
'0': '排斥',
'1': '警惕',
'2': '可以交流',
'3': '一般',
'4': '是个好人',
'5': '好朋友',
'6': '可以分享小秘密',
'7': '喜欢',
'8': '恋人'
}
weekdays = {
1: 'Mon',
2: 'Tue',
3: 'Wed',
4: 'Thu',
5: 'Fri',
6: 'Sat',
7: 'Sun'
}
lik2level = {
9999: '9',
400: '8',
270: '7',
200: '6',
140: '5',
90: '4',
50: '3',
25: '2',
10: '1',
0: '0'
}

View File

@ -1,39 +1,47 @@
import random
from datetime import datetime, timedelta
from io import BytesIO
from services.log import logger
from services.db_context import db
from models.sigin_group_user import SignGroupUser
from models.sign_group_user import SignGroupUser
from models.group_member_info import GroupInfoUser
from models.bag_user import BagUser
from configs.config import MAX_SIGN_GOLD, NICKNAME
from utils.image_utils import CreateImg
import aiohttp
from configs.config import NICKNAME
from nonebot.adapters.cqhttp import MessageSegment
from asyncio.exceptions import TimeoutError
from utils.image_utils import CreateImg
from services.db_context import db
from .utils import get_card, SIGN_TODAY_CARD_PATH
from services.log import logger
from .random_event import random_event
from io import BytesIO
import random
import aiohttp
import math
import asyncio
import os
async def group_user_check_in(user_qq: int, group: int) -> str:
async def group_user_check_in(
nickname: str, user_qq: int, group: int
) -> MessageSegment:
"Returns string describing the result of checking in"
present = datetime.now()
async with db.transaction():
# 取得相应用户
user = await SignGroupUser.ensure(user_qq, group, for_update=True)
# 如果同一天签到过,特殊处理
if user.checkin_time_last.date() == present.date():
return _handle_already_checked_in(user)
return await _handle_check_in(user_qq, group, present) # ok
# if (
# user.checkin_time_last + timedelta(hours=8)
# ).date() >= present.date() or f"{user}_{group}_sign_{datetime.now().date()}" in os.listdir(
# SIGN_TODAY_CARD_PATH
# ):
# gold = await BagUser.get_gold(user_qq, group)
# return await get_card(user, nickname, -1, gold, "")
return await _handle_check_in(nickname, user_qq, group, present) # ok
def _handle_already_checked_in(user: SignGroupUser) -> str:
return f"已经签到过啦~ 好感度:{user.impression:.2f}"
async def _handle_check_in(user_qq: int, group: int, present: datetime) -> str:
async def _handle_check_in(
nickname: str, user_qq: int, group: int, present: datetime
) -> MessageSegment:
user = await SignGroupUser.ensure(user_qq, group, for_update=True)
impression_added = random.random()
present = present + timedelta(hours=8)
critx2 = random.random()
add_probability = user.add_probability
specify_probability = user.specify_probability
@ -41,56 +49,36 @@ async def _handle_check_in(user_qq: int, group: int, present: datetime) -> str:
impression_added *= 2
elif critx2 < specify_probability:
impression_added *= 2
new_impression = user.impression + impression_added
message = random.choice(
(
"谢谢,你是个好人!",
"对了,来喝杯茶吗?",
)
)
await user.update(
checkin_count=user.checkin_count + 1,
checkin_time_last=present,
impression=new_impression,
add_probability=0,
specify_probability=0,
).apply()
# glod = await random_glod(user_qq, group, specify_probability)
if user.impression < 1:
impression = 1
else:
impression = user.impression
await SignGroupUser.sign(user, impression_added, present)
gold = random.randint(1, 100)
imgold = random.randint(1, int(impression))
if imgold > MAX_SIGN_GOLD:
imgold = MAX_SIGN_GOLD
await BagUser.add_gold(user_qq, group, gold + imgold)
gift, gift_type = random_event(user.impression)
if gift_type == "gold":
await BagUser.add_gold(user_qq, group, gold + gift)
gift = f"额外金币 + {gift}"
else:
await BagUser.add_props(user_qq, group, gift)
gift += ' + 1'
if critx2 + add_probability > 0.97 or critx2 < specify_probability:
logger.info(
f"(USER {user.user_qq}, GROUP {user.belonging_group})"
f" CHECKED IN successfully. score: {new_impression:.2f} (+{impression_added * 2:.2f}).获取金币:{gold+imgold}"
f" CHECKED IN successfully. score: {user.impression:.2f} "
f"(+{impression_added * 2:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
)
return f"{message} 好感度:{new_impression:.2f} (+{impression_added/2:.2f}×2)\n获取金币:{gold} \n好感度额外获得金币:{imgold}"
return await get_card(user, nickname, impression_added, gold, gift, True)
else:
logger.info(
f"(USER {user.user_qq}, GROUP {user.belonging_group})"
f" CHECKED IN successfully. score: {new_impression:.2f} (+{impression_added:.2f}).获取金币:{gold+imgold}"
f" CHECKED IN successfully. score: {user.impression:.2f} "
f"(+{impression_added:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
)
return f"{message} 好感度:{new_impression:.2f} (+{impression_added:.2f})\n获取金币:{gold} \n好感度额外获得金币:{imgold}"
return await get_card(user, nickname, impression_added, gold, gift)
async def group_user_check(user_qq: int, group: int) -> str:
async def group_user_check(nickname: str, user_qq: int, group: int) -> MessageSegment:
# heuristic: if users find they have never checked in they are probable to check in
user = await SignGroupUser.ensure(user_qq, group)
gold = await BagUser.get_gold(user_qq, group)
return "好感度:{:.2f}\n金币:{}\n历史签到数:{}\n上次签到日期:{}".format(
user.impression,
gold,
user.checkin_count,
user.checkin_time_last.date()
if user.checkin_time_last != datetime.min
else "从未",
)
return await get_card(user, nickname, None, gold, "", is_card_view=True)
async def group_impression_rank(group: int) -> str:
@ -108,7 +96,7 @@ async def group_impression_rank(group: int) -> str:
user_name = (
await GroupInfoUser.get_member_info(user_qq, group)
).user_name
except Exception as e:
except AttributeError:
logger.info(f"USER {user_qq}, GROUP {group} 不在群内")
_count += 1
impression_list.remove(impression)

View File

@ -0,0 +1,24 @@
from configs.config import MAX_SIGN_GOLD
from typing import Union
from .config import PROB_DATA
import random
def random_event(impression: float) -> 'Union[str, int], str':
"""
签到随机事件
:param impression: 好感度
:return: 额外奖励 类型
"""
rand = random.random() - impression / 1000
for prob in PROB_DATA.keys():
if rand <= prob:
return PROB_DATA[prob], 'props'
gold = random.randint(1, random.randint(1, int(1 if impression < 1 else impression)))
gold = MAX_SIGN_GOLD if gold > MAX_SIGN_GOLD else gold
return gold, 'gold'

330
plugins/sign_in/utils.py Normal file
View File

@ -0,0 +1,330 @@
from .config import (
SIGN_RESOURCE_PATH,
SIGN_TODAY_CARD_PATH,
SIGN_BORDER_PATH,
SIGN_BACKGROUND_PATH,
lik2level,
lik2relation,
level2attitude,
weekdays,
)
from models.sign_group_user import SignGroupUser
from models.group_member_info import GroupInfoUser
from nonebot.adapters.cqhttp import MessageSegment
from utils.image_utils import CreateImg
from utils.message_builder import image
from configs.config import NICKNAME
from pathlib import Path
from datetime import datetime
from typing import Optional, List
from nonebot import Driver
from io import BytesIO
import asyncio
import nonebot
import aiohttp
import os
driver: Driver = nonebot.get_driver()
@driver.on_startup
async def init_image():
SIGN_RESOURCE_PATH.mkdir(parents=True, exist_ok=True)
await GroupInfoUser.add_member_info(114514, 114514, "", datetime.min)
generate_progress_bar_pic()
clear_sign_data_pic()
async def _get_pic(qq):
url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=100"
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=5) as response:
return await response.read()
async def get_card(
user: "SignGroupUser",
nickname: str,
add_impression: Optional[float],
gold: Optional[int],
gift: str,
is_double: bool = False,
is_card_view: bool = False,
) -> MessageSegment:
user_id = user.user_qq
date = datetime.now().date()
_type = 'view' if is_card_view else 'sign'
card_file = Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.belonging_group}_{_type}_{date}.png"
if card_file.exists():
return image(f"{user_id}_{user.belonging_group}_{_type}_{date}.png", "sign/today_card")
else:
if add_impression == -1:
card_file = Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.belonging_group}_view_{date}.png"
if card_file.exists():
return image(f"{user_id}_{user.belonging_group}_view_{date}.png", "sign/today_card")
is_card_view = True
ava = BytesIO(await _get_pic(user_id))
uid = await GroupInfoUser.get_group_member_uid(
user.user_qq, user.belonging_group
)
impression_list = None
if is_card_view:
_, impression_list, _ = await SignGroupUser.get_all_impression(
user.belonging_group
)
return await asyncio.get_event_loop().run_in_executor(
None,
_generate_card,
user,
nickname,
user_id,
add_impression,
gold,
gift,
uid,
ava,
impression_list,
is_double,
is_card_view,
)
def _generate_card(
user: "SignGroupUser",
nickname: str,
user_id: int,
impression: Optional[float],
gold: Optional[int],
gift: str,
uid: str,
ava_bytes: BytesIO,
impression_list: List[float],
is_double: bool = False,
is_card_view: bool = False,
) -> MessageSegment:
ava_bk = CreateImg(140, 140, is_alpha=True)
ava_border = CreateImg(
140,
140,
background=SIGN_BORDER_PATH / 'ava_border_01.png',
)
ava = CreateImg(102, 102, background=ava_bytes)
ava.circle()
ava_bk.paste(ava, center_type="center")
ava_bk.paste(ava_border, alpha=True, center_type="center")
info_img = CreateImg(250, 150, color=(255, 255, 255, 0), font_size=15)
level, next_impression, previous_impression = get_level_and_next_impression(
user.impression
)
info_img.text((0, 0), f"· 好感度等级:{level} [{lik2relation[level]}]")
info_img.text((0, 20), f"· {NICKNAME}对你的态度:{level2attitude[level]}")
info_img.text((0, 40), f"· 距离升级还差 {next_impression - user.impression:.2f} 好感度")
bar_bk = CreateImg(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png")
bar = CreateImg(220, 20, background=SIGN_RESOURCE_PATH / "bar.png")
bar_bk.paste(
bar,
(
-int(
220
* (
(next_impression - user.impression)
/ (next_impression - previous_impression)
)
),
0,
),
True,
)
font_size = 30
if '好感度双倍加持卡' in gift:
font_size = 20
gift_border = CreateImg(
270, 100, background=SIGN_BORDER_PATH / "gift_border_02.png", font_size=font_size
)
gift_border.text((0, 0), gift, center_type="center")
bk = CreateImg(
876, 424, background=SIGN_BACKGROUND_PATH / "background_01.jpg", font_size=25
)
A = CreateImg(876, 274, background=SIGN_RESOURCE_PATH / "white.png")
line = CreateImg(2, 180, color="black")
A.transparent(2)
A.paste(ava_bk, (25, 80), True)
A.paste(line, (200, 70))
nickname_img = CreateImg(
0,
0,
plain_text=nickname,
color=(255, 255, 255, 0),
font_size=50,
font_color=(255, 255, 255),
)
if uid:
uid = f"{uid}".rjust(12, "0")
uid = uid[:4] + " " + uid[4:8] + " " + uid[8:]
else:
uid = "XXXX XXXX XXXX"
uid_img = CreateImg(
0,
0,
plain_text=f"UID: {uid}",
color=(255, 255, 255, 0),
font_size=30,
font_color=(255, 255, 255),
)
sign_day_img = CreateImg(
0,
0,
plain_text=f"{user.checkin_count}",
color=(255, 255, 255, 0),
font_size=40,
font_color=(211, 64, 33),
)
lik_text1_img = CreateImg(
0, 0, plain_text="当前", color=(255, 255, 255, 0), font_size=20
)
lik_text2_img = CreateImg(
0,
0,
plain_text=f"好感度:{user.impression:.2f}",
color=(255, 255, 255, 0),
font_size=30,
)
watermark = CreateImg(
0,
0,
plain_text=f"{NICKNAME}@{datetime.now().year}",
color=(255, 255, 255, 0),
font_size=15,
font_color=(155, 155, 155),
)
today_data = CreateImg(300, 300, color=(255, 255, 255, 0), font_size=20)
if is_card_view:
today_sign_text_img = CreateImg(
0, 0, plain_text="", color=(255, 255, 255, 0), font_size=30
)
if impression_list:
impression_list.sort(reverse=True)
index = impression_list.index(user.impression)
rank_img = CreateImg(
0,
0,
plain_text=f"* 此群好感排名第 {index + 1}",
color=(255, 255, 255, 0),
font_size=30,
)
A.paste(rank_img, ((A.w - rank_img.w - 10), 20), True)
today_data.text(
(0, 0),
f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}",
)
today_data.text((0, 25), f"总金币:{gold}")
today_data.text((0, 50), f'色图概率:{(70 + user.impression if user.impression < 100 else 100):.2f}%')
today_data.text((0, 75), f'开箱次数:{(20 + int(user.impression / 3))}')
_type = "view"
else:
A.paste(gift_border, (570, 140), True)
today_sign_text_img = CreateImg(
0, 0, plain_text="今日签到", color=(255, 255, 255, 0), font_size=30
)
if is_double:
today_data.text((0, 0), f"好感度 + {impression / 2:.2f} × 2")
else:
today_data.text((0, 0), f"好感度 + {impression:.2f}")
today_data.text((0, 25), f"金币 + {gold}")
_type = "sign"
current_date = datetime.now()
week = current_date.isoweekday()
data = current_date.date()
hour = current_date.hour
minute = current_date.minute
second = current_date.second
data_img = CreateImg(
0,
0,
plain_text=f"时间:{data} {weekdays[week]} {hour}:{minute}:{second}",
color=(255, 255, 255, 0),
font_size=20,
)
bk.paste(nickname_img, (30, 15), True)
bk.paste(uid_img, (30, 85), True)
bk.paste(A, (0, 150), alpha=True)
bk.text((30, 167), "Accumulative check-in for")
_x = bk.getsize("Accumulative check-in for")[0] + sign_day_img.w + 45
bk.paste(sign_day_img, (346, 158), True)
bk.text((_x, 167), "days")
bk.paste(data_img, (220, 370), True)
bk.paste(lik_text1_img, (220, 240), True)
bk.paste(lik_text2_img, (262, 234), True)
bk.paste(bar_bk, (225, 275), True)
bk.paste(info_img, (220, 305), True)
bk.paste(today_sign_text_img, (550, 180), True)
bk.paste(today_data, (580, 220), True)
bk.paste(watermark, (15, 400), True)
bk.save(SIGN_TODAY_CARD_PATH / f"{user_id}_{user.belonging_group}_{_type}_{data}.png")
return image(f"{user_id}_{user.belonging_group}_{_type}_{data}.png", "sign/today_card")
def generate_progress_bar_pic():
bg_2 = (254, 1, 254)
bg_1 = (0, 245, 246)
bk = CreateImg(1000, 50, is_alpha=True)
img_x = CreateImg(50, 50, color=bg_2)
img_x.circle()
img_x.crop((25, 0, 50, 50))
img_y = CreateImg(50, 50, color=bg_1)
img_y.circle()
img_y.crop((0, 0, 25, 50))
A = CreateImg(950, 50)
width, height = A.size
step_r = (bg_2[0] - bg_1[0]) / width
step_g = (bg_2[1] - bg_1[1]) / width
step_b = (bg_2[2] - bg_1[2]) / width
for y in range(0, width):
bg_r = round(bg_1[0] + step_r * y)
bg_g = round(bg_1[1] + step_g * y)
bg_b = round(bg_1[2] + step_b * y)
for x in range(0, height):
A.point((y, x), fill=(bg_r, bg_g, bg_b))
bk.paste(img_y, (0, 0), True)
bk.paste(A, (25, 0))
bk.paste(img_x, (975, 0), True)
bk.save(SIGN_RESOURCE_PATH / "bar.png")
A = CreateImg(950, 50)
bk = CreateImg(1000, 50, is_alpha=True)
img_x = CreateImg(50, 50)
img_x.circle()
img_x.crop((25, 0, 50, 50))
img_y = CreateImg(50, 50)
img_y.circle()
img_y.crop((0, 0, 25, 50))
bk.paste(img_y, (0, 0), True)
bk.paste(A, (25, 0))
bk.paste(img_x, (975, 0), True)
bk.save(SIGN_RESOURCE_PATH / "bar_white.png")
def get_level_and_next_impression(impression: float):
if impression == 0:
return lik2level[10], 10, 0
keys = list(lik2level.keys())
for i in range(len(keys)):
if impression > keys[i]:
return lik2level[keys[i]], keys[i - 1], keys[i]
return lik2level[10], 10, 0
def clear_sign_data_pic():
date = datetime.now().date()
for file in os.listdir(SIGN_TODAY_CARD_PATH):
if str(date) not in file:
os.remove(SIGN_TODAY_CARD_PATH / file)

View File

@ -183,7 +183,10 @@ async def _():
for data in [_prefix_count_dict, _prefix_user_count_dict]:
for x in _prefix_count_dict["day_statistics"].keys():
for key in _prefix_count_dict["day_statistics"][x].keys():
data["day_statistics"][x][key] = 0
try:
data["day_statistics"][x][key] = 0
except KeyError:
pass
data["day_index"] += 1
with open(DATA_PATH + "_prefix_count.json", "w", encoding="utf8") as f:
json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False)

View File

@ -225,14 +225,15 @@ def _clear_data() -> float:
size = 0
for dir_name in ['temp', 'rar', 'r18_rar']:
dir_name = f'{IMAGE_PATH}/{dir_name}'
for file in os.listdir(dir_name):
try:
file_size = os.path.getsize(os.path.join(dir_name, file))
os.remove(os.path.join(dir_name, file))
except Exception as e:
logger.error(f"清理临时数据错误...e{e}")
file_size = 0
size += file_size
if os.path.exists(dir_name):
for file in os.listdir(dir_name):
try:
file_size = os.path.getsize(os.path.join(dir_name, file))
os.remove(os.path.join(dir_name, file))
except Exception as e:
logger.error(f"清理临时数据错误...e{e}")
file_size = 0
size += file_size
return float(size)

View File

@ -11,7 +11,7 @@ from utils.message_builder import image
result = """超级用户帮助:
*可多个类型参数 可省略参数
1.添加/删除管理 [at] [level]
2.查看群组/查看好友
2.所有群组/好友
3.广播- [msg]
4.更新色图
5./t命令帮助
@ -19,14 +19,14 @@ result = """超级用户帮助:
7.开启/关闭广播通知 [群号]
8.退群 [群号]
9.自检
10.更新价格/更加图片 [武器箱]
10.更新价格/更加图片 ?[武器箱]
11.更新好友信息
12.更新群群信息
13.重载原神/方舟/赛马娘/坎公骑冠剑卡池
14.添加商品 [名称]-[价格]-[描述]-[折扣]-[限时时间]
15.删除商品 [名称(序号)]
16.修改商品 -name [名称(序号)] -price [价格] -des [描述] -discount [折扣] -time [限时]
17.节日红包 [金额] [数量] [祝福语](可省) *?[指定群
17.节日红包 [金额] [数量] ?[祝福语] *?[指定群]
18.更新原神今日素材
19.更新原神资源信息
20.添加pix关键词/uid/pid *[关键词/uid/pid] ?[-f](强制通过不检测)
@ -36,10 +36,13 @@ result = """超级用户帮助:
24.删除pix图片 *[pid] ?[-b](同时加入黑名单)
25.查看pix图库 [keyword]
26.pix检测更新 [update]
27.检查更新真寻
28.真寻重启
29.添加/删除群白名单 *[群号]
30.关闭[功能] ?[群号/private/group](有群号时禁用指定群)"""
27.pix [-s/-r] ?[tag]
28.检查更新真寻
29.真寻重启
30.添加/删除群白名单 *[群号]
31.关闭[功能] ?[群号/private/group](有群号时禁用指定群)
32.功能状态
33.查看群白名单"""
height = len(result.split('\n')) * 24
A = CreateImg(1000, height, font_size=20)

View File

@ -31,7 +31,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await lasted_gocqhttp.finish("gocqhttp没有更新")
if _ulmt.check(event.group_id):
await lasted_gocqhttp.finish("gocqhttp正在更新请勿重复使用该命令", at_sender=True)
_ulmt.set_True(event.group_id)
_ulmt.set_true(event.group_id)
try:
for file in os.listdir(path):
await upload_gocq_lasted(path, file, event.group_id)
@ -39,7 +39,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await lasted_gocqhttp.send(f"gocqhttp更新了已上传成功\n更新内容:\n{info}")
except Exception as e:
logger.error(f"更新gocq错误 e{e}")
_ulmt.set_False(event.group_id)
_ulmt.set_false(event.group_id)
# 更新gocq

View File

@ -42,7 +42,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@what_anime.got("img_url", prompt="虚空识番来图来图GKD")
async def _(bot: Bot, event: MessageEvent, state: T_State):
img_url = state["img_url"][0]
_ulmt.set_True(event.user_id)
_ulmt.set_true(event.user_id)
await what_anime.send("开始识别.....")
anime_data_report = await get_anime(img_url)
if anime_data_report:
@ -58,4 +58,4 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'} 识番 {img_url} 未找到!!"
)
await what_anime.send(f"没有寻找到该番剧,果咩..", at_sender=True)
_ulmt.set_False(event.user_id)
_ulmt.set_false(event.user_id)

15
plugins/withdraw.py Normal file
View File

@ -0,0 +1,15 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from nonebot.typing import T_State
import re
withdraw_msg = on_command('撤回', priority=5, block=True)
@withdraw_msg.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
r = re.search(r'\[CQ:reply,id=(\d*)]', event.raw_message)
if r:
await bot.delete_msg(message_id=int(r.group(1)), self_id=int(bot.self_id))

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -1,30 +1,26 @@
import logging
from datetime import datetime
from datetime import datetime, timedelta
from configs.path_config import LOG_PATH
import sys
# CRITICAL 50
# ERROR 40
# WARNING 30
# INFO 20
# DEBUG 10
# NOTSET 0
from loguru import logger as logger_
from nonebot.log import default_format, default_filter
# _handler = logging.StreamHandler(sys.stdout)
# _handler.setFormatter(
# logging.Formatter('[%(asctime)s %(name)s] %(levelname)s: %(message)s')
# )
logger = logging.getLogger('hibiki')
logger.setLevel(level=logging.DEBUG)
formatter = logging.Formatter('[%(asctime)s] - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
logger = logger_
file_handler = logging.FileHandler(LOG_PATH + str(datetime.now().date()) + '.log', mode='a', encoding='utf-8')
file_handler.setLevel(level=logging.INFO)
file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(formatter)
logger.add(
f'{LOG_PATH}/{datetime.now().date()}.log',
level='INFO',
rotation='00:00',
format=default_format,
filter=default_filter,
retention=timedelta(days=30))
logger.add(
f'{LOG_PATH}/error_{datetime.now().date()}.log',
level='ERROR',
rotation='00:00',
format=default_format,
filter=default_filter,
retention=timedelta(days=30))
logger.addHandler(file_handler)
logger.addHandler(stream_handler)

View File

@ -1,48 +1,11 @@
{
"update_file": [
"configs/config.py",
"configs/path_config.py",
"plugins/aconfig",
"plugins/admin_bot_manage",
"plugins/admin_help",
"plugins/ai",
"plugins/alapi",
"plugins/auto_invite",
"plugins/ban",
"plugins/check_zhenxun_update",
"plugins/delete_img",
"plugins/fudu.py",
"plugins/genshin/query_resource_points",
"plugins/group_handle",
"plugins/help",
"plugins/hook.py",
"plugins/jitang.py",
"plugins/move_img",
"plugins/mute.py",
"plugins/nickname.py",
"plugins/one_friend",
"plugins/open_cases",
"plugins/parse_bilibili_json.py",
"plugins/pixiv",
"plugins/reimu",
"plugins/remind",
"plugins/roll.py",
"plugins/russian",
"plugins/search_anime",
"plugins/search_buff_skin_price",
"plugins/send_img",
"plugins/send_setu",
"plugins/shop/gold_redbag",
"plugins/sign_in/group_user_checkin.py",
"plugins/statistics_hook.py",
"plugins/super_help",
"plugins/update_info.py",
"plugins/update_setu",
"plugins/upload_img",
"plugins/weather",
"plugins/yiqing",
"utils/image_utils.py"
"plugins",
"utils",
"services",
"models"
],
"add_file": ["plugins/group_manager", "resources/img/other/webtop.png", "utils/static_data"],
"delete_file": ["plugins/group_level", "plugins/nonebot_plugin_manager"]
"add_file": [],
"delete_file": []
}

View File

@ -4,6 +4,7 @@ from playwright.async_api import Browser, async_playwright
import nonebot
from nonebot import Driver
from services.log import logger
import platform
driver: Driver = nonebot.get_driver()
@ -13,14 +14,16 @@ _browser: Optional[Browser] = None
async def init(**kwargs) -> Optional[Browser]:
# try:
global _browser
browser = await async_playwright().start()
_browser = await browser.chromium.launch(**kwargs)
return _browser
# except NotImplementedError:
# logger.warning("win环境下 初始化playwright失败....请替换环境至linux")
# return None
if platform.system() == "Windows":
return None
try:
global _browser
browser = await async_playwright().start()
_browser = await browser.chromium.launch(**kwargs)
return _browser
except NotImplementedError:
logger.warning("win环境下 初始化playwright失败....请替换环境至linux")
return None
async def get_browser(**kwargs) -> Browser:

View File

@ -45,7 +45,9 @@ def get_img_hash(image_file: str) -> ImageHash:
return hash_value
def compressed_image(in_file: Union[str, Path], out_file: Union[str, Path] = None, ratio: float = 0.9):
def compressed_image(
in_file: Union[str, Path], out_file: Union[str, Path] = None, ratio: float = 0.9
):
"""
说明
压缩图片
@ -56,15 +58,19 @@ def compressed_image(in_file: Union[str, Path], out_file: Union[str, Path] = Non
"""
in_file = Path(IMAGE_PATH) / in_file if isinstance(in_file, str) else in_file
if out_file:
out_file = Path(IMAGE_PATH) / out_file if isinstance(out_file, str) else out_file
out_file = (
Path(IMAGE_PATH) / out_file if isinstance(out_file, str) else out_file
)
else:
out_file = in_file
h, w, d = cv2.imread(str(in_file.absolute())).shape
img = cv2.resize(cv2.imread(str(in_file.absolute())), (int(w * ratio), int(h * ratio)))
img = cv2.resize(
cv2.imread(str(in_file.absolute())), (int(w * ratio), int(h * ratio))
)
cv2.imwrite(str(out_file.absolute()), img)
def alpha2white_PIL(pic: Image) -> Image:
def alpha2white_pil(pic: Image) -> Image:
"""
说明
将图片透明背景转化为白色
@ -131,16 +137,19 @@ class CreateImg:
def __init__(
self,
w,
h,
paste_image_width=0,
paste_image_height=0,
color="white",
image_type="RGBA",
font_size=10,
background="",
ttf="yz.ttf",
ratio=1,
w: int,
h: int,
paste_image_width: int = 0,
paste_image_height: int = 0,
color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = "white",
image_mode: str = "RGBA",
font_size: int = 10,
background: Union[Optional[str], BytesIO] = None,
ttf: str = "yz.ttf",
ratio: float = 1,
is_alpha: bool = False,
plain_text: Optional[str] = None,
font_color: Optional[Tuple[int, int, int]] = None,
):
"""
参数
@ -149,11 +158,13 @@ class CreateImg:
:param paste_image_width: 当图片做为背景图时设置贴图的宽度用于贴图自动换行
:param paste_image_height: 当图片做为背景图时设置贴图的高度用于贴图自动换行
:param color: 生成图片的颜色
:param image_type: 图片的类型
:param image_mode: 图片的类型
:param font_size: 文字大小
:param background: 打开图片的路径
:param ttf: 字体默认在 resource/ttf/ 路径下
:param ratio: 倍率压缩
:param is_alpha: 是否背景透明
:param plain_text: 纯文字文本
"""
self.w = int(w)
self.h = int(h)
@ -161,9 +172,14 @@ class CreateImg:
self.paste_image_height = int(paste_image_height)
self.current_w = 0
self.current_h = 0
self.ttfont = ImageFont.truetype(TTF_PATH + ttf, int(font_size))
self.font = ImageFont.truetype(TTF_PATH + ttf, int(font_size))
if not background:
self.markImg = Image.new(image_type, (self.w, self.h), color)
if plain_text:
ttf_w, ttf_h = self.getsize(plain_text)
self.w = self.w if self.w > ttf_w else ttf_w
self.h = self.h if self.h > ttf_h else ttf_h
self.markImg = Image.new(image_mode, (self.w, self.h), color)
self.markImg.convert(image_mode)
else:
if not w and not h:
self.markImg = Image.open(background)
@ -181,14 +197,26 @@ class CreateImg:
self.markImg = Image.open(background).resize(
(self.w, self.h), Image.ANTIALIAS
)
if is_alpha:
array = self.markImg.load()
for i in range(w):
for j in range(h):
pos = array[i, j]
is_edit = (sum([1 for x in pos[0:3] if x > 240]) == 3)
if is_edit:
array[i, j] = (255, 255, 255, 0)
self.draw = ImageDraw.Draw(self.markImg)
self.size = self.w, self.h
if plain_text:
fill = font_color if font_color else (0, 0, 0)
self.text((0, 0), plain_text, fill)
def paste(
self,
img: "CreateImg" or Image,
pos: Tuple[int, int] = None,
alpha: bool = False,
center_type: Optional[str] = None,
):
"""
说明
@ -197,7 +225,26 @@ class CreateImg:
:param img: 已打开的图片文件可以为 CreateImg Image
:param pos: 贴图位置左上角
:param alpha: 图片背景是否为透明
:param center_type: 居中类型可能的值 center: 完全居中by_width: 水平居中by_height: 垂直居中
"""
if center_type:
if center_type not in ["center", "by_height", "by_width"]:
raise ValueError(
"center_type must be 'center', 'by_width' or 'by_height'"
)
width, height = 0, 0
if not pos:
pos = (0, 0)
if center_type == "center":
width = int((self.w - img.w) / 2)
height = int((self.h - img.h) / 2)
elif center_type == "by_width":
width = int((self.w - img.w) / 2)
height = pos[1]
elif center_type == "by_height":
width = pos[0]
height = int((self.h - img.h) / 2)
pos = (width, height)
if isinstance(img, CreateImg):
img = img.markImg
if self.current_w == self.w:
@ -222,10 +269,38 @@ class CreateImg:
参数
:param msg: 文字内容
"""
return self.ttfont.getsize(msg)
return self.font.getsize(msg)
def point(self, pos: Tuple[int, int], fill: Optional[Tuple[int, int, int]] = None):
"""
说明
绘制多个或单独的像素
参数
:param pos: 坐标
:param fill: 填错颜色
"""
self.draw.point(pos, fill=fill)
def ellipse(
self,
pos: Tuple[int, int, int, int],
fill: Optional[Tuple[int, int, int]] = None,
outline: Optional[Tuple[int, int, int]] = None,
width: int = 1,
):
"""
说明
绘制圆
参数
:param pos: 坐标范围
:param fill: 填充颜色
:param outline: 描线颜色
:param width: 描线宽度
"""
self.draw.ellipse(pos, fill, outline, width)
def text(
self, pos: Tuple[int, int], text: str, fill: Tuple[int, int, int] = (0, 0, 0)
self, pos: Tuple[int, int], text: str, fill: Tuple[int, int, int] = (0, 0, 0), center_type: Optional[str] = None
):
"""
说明
@ -234,8 +309,24 @@ class CreateImg:
:param pos: 文字位置
:param text: 文字内容
:param fill: 文字颜色
:param center_type: 居中类型可能的值 center: 完全居中by_width: 水平居中by_height: 垂直居中
"""
self.draw.text(pos, text, fill=fill, font=self.ttfont)
if center_type:
if center_type not in ["center", "by_height", "by_width"]:
raise ValueError(
"center_type must be 'center', 'by_width' or 'by_height'"
)
w, h = self.w, self.h
ttf_w, ttf_h = self.getsize(text)
if center_type == 'center':
w = int((w - ttf_w) / 2)
h = int((h - ttf_h) / 2)
elif center_type == 'by_width':
w = int((w - ttf_w) / 2)
elif center_type == 'by_height':
h = int((h - ttf_h) / 2)
pos = (w, h)
self.draw.text(pos, text, fill=fill, font=self.font)
def save(self, path: str):
"""
@ -291,13 +382,14 @@ class CreateImg:
参数
:param word: 文本内容
"""
return self.ttfont.getsize(word)[0] > self.w
return self.font.getsize(word)[0] > self.w
def transparent(self, n: int = 0):
def transparent(self, alpha_ratio: float = 1, n: int = 0):
"""
说明
图片透明化
参数
:param alpha_ratio: 透明化程度
:param n: 透明化大小内边距
"""
self.markImg = self.markImg.convert("RGBA")
@ -305,7 +397,7 @@ class CreateImg:
for i in range(n, x - n):
for k in range(n, y - n):
color = self.markImg.getpixel((i, k))
color = color[:-1] + (100,)
color = color[:-1] + (int(100 * alpha_ratio),)
self.markImg.putpixel((i, k), color)
def pic2bs4(self) -> str:

View File

@ -1,14 +1,13 @@
from configs.path_config import IMAGE_PATH, VOICE_PATH
from nonebot.adapters.cqhttp.message import MessageSegment
from services.log import logger
from typing import Optional
from typing import Union
from pathlib import Path
import os
import ujson
def image(
img_name: str = None, path: str = None, abspath: str = None, b64: str = None
img_name: Union[str, Path] = None, path: str = None, abspath: str = None, b64: str = None
) -> MessageSegment or str:
"""
说明
@ -29,6 +28,8 @@ def image(
elif b64:
return MessageSegment.image(b64 if "base64://" in b64 else "base64://" + b64)
else:
# if isinstance(img_name, Path):
# return MessageSegment.image(img_name)
if "http" in img_name:
return MessageSegment.image(img_name)
if len(img_name.split(".")) == 1:

View File

@ -2,10 +2,13 @@ from typing import Optional
from .group_manager import GroupManager
from pathlib import Path
from .data_source import init
from .data_class import StaticData
# 群权限
# 群管理
group_manager: Optional[GroupManager] = GroupManager(
Path() / "data" / "manager" / "group_manager.json"
)
withdraw_message_id_manager: Optional[StaticData] = StaticData(None)
init(group_manager)

View File

@ -1,4 +1,4 @@
from typing import Union
from typing import Union, Optional
from pathlib import Path
import ujson as json
@ -8,12 +8,13 @@ class StaticData:
静态数据共享类
"""
def __init__(self, file: Path):
file.parent.mkdir(exist_ok=True, parents=True)
self.file = file
def __init__(self, file: Optional[Path]):
self.data = {}
if file.exists():
self.data: dict = json.load(open(file, "r", encoding="utf8"))
if file:
file.parent.mkdir(exist_ok=True, parents=True)
self.file = file
if file.exists():
self.data: dict = json.load(open(file, "r", encoding="utf8"))
def set(self, key, value):
self.data[key] = value

View File

@ -1,4 +1,5 @@
from typing import Optional
from configs.config import DEFAULT_GROUP_LEVEL
from typing import Optional, List
from pathlib import Path
from .data_class import StaticData
@ -132,6 +133,13 @@ class GroupManager(StaticData):
if group_id in self.data['super']['white_group_list']:
self.data['super']['white_group_list'].remove(group_id)
def get_group_white_list(self) -> List[str]:
"""
说明
获取所有群白名单
"""
return self.data['super']['white_group_list']
def _set_plugin_status(
self,
plugin_cmd: str,
@ -183,4 +191,6 @@ class GroupManager(StaticData):
参数
:param group_id: 群号
"""
self.data["group_manager"][group_id] = {"level": 5, "close_plugins": []}
self.data["group_manager"][group_id] = {"level": DEFAULT_GROUP_LEVEL, "close_plugins": []}

View File

@ -3,7 +3,7 @@ from collections import defaultdict
from nonebot import require
from configs.path_config import TXT_PATH
from configs.config import SYSTEM_PROXY
from typing import List, Union
from typing import List, Union, Optional
from nonebot.adapters import Bot
import nonebot
import pytz
@ -48,16 +48,16 @@ class UserExistLimiter:
self.flag_data = defaultdict(bool)
self.time = time.time()
def set_True(self, key: Union[str, int, float]):
def set_true(self, key: Union[str, int, float]):
self.time = time.time()
self.flag_data[key] = True
def set_False(self, key: Union[str, int, float]):
def set_false(self, key: Union[str, int, float]):
self.flag_data[key] = False
def check(self, key: Union[str, int, float]) -> bool:
if time.time() - self.time > 30:
self.set_False(key)
self.set_false(key)
return False
return self.flag_data[key]
@ -169,12 +169,15 @@ def is_number(s: str) -> bool:
return False
def get_bot() -> Bot:
def get_bot() -> Optional[Bot]:
"""
说明
获取 bot 对象
"""
return list(nonebot.get_bots().values())[0]
try:
return list(nonebot.get_bots().values())[0]
except IndexError:
return None
def get_message_at(data: str) -> List[int]:
@ -322,3 +325,21 @@ def cn2py(word: str) -> str:
for i in pypinyin.pinyin(word, style=pypinyin.NORMAL):
temp += "".join(i)
return temp
def change_picture_links(url: str, mode: str):
"""
说明
根据配置改变图片大小
参数
:param url: 图片原图链接
:param mode: 模式
"""
if mode == 'master':
img_sp = url.rsplit('.', maxsplit=1)
url = img_sp[0]
img_type = img_sp[1]
url = url.replace('original', 'master') + f'_master1200.{img_type}'
return url