diff --git a/README.md b/README.md
index 717a7acf..65dc33d3 100644
--- a/README.md
+++ b/README.md
@@ -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站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv)
+- [x] b站转发解析(解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv),且5分钟内不解析相同url
- [x] 丢人爬(爬表情包)
- [x] epic通知(每日发送epic免费游戏链接)
- [x] 原神黄历提醒
@@ -201,6 +202,8 @@
| 添加pix关键词/uid/pid | 添加pix关键词/uid/pid *[关键词/uid/pid]| 添加关键词或uid或pid用于下次搜索,关键词搜索相关tag,uid会收录作者下收藏符合标准的作品,pid收录单张作品
示例:添加pix关键词 原神
添加pixuid 123441
添加pixpid 2748937|
| 查看pix图库 | 查看pix图库 [tags] | 查看已收录的tag相关图片数量
示例:查看pix图库 原神 莫娜
|显示pix关键词 | 显示pix关键词 | 查看已收录的所有关键词/UID/PID
+| b了 | b了 [at] | 使真寻完全忽略一个用户的所有信息
+| B站订阅 | 添加订阅 [主播/UP/番剧] [id/链接/番名] / 删除订阅 [id] / 查看订阅 | 可以通过直接间链接或主播间id添加订阅主播开播提醒,动态和投稿,可以通过番名,番剧的id,或者番剧链接添加番剧订阅(是番剧id,md开头,不是集数id,ep开头的)更新, 可以通过UP个人id或UP主页链接订阅UP动态和投稿
### 管理员功能
@@ -218,6 +221,7 @@
| 上传图片 | 6 | 上传图片 \[图库] \[图片]... | 上传图片至指定图库,虽然并不打算开放给群员,但还是写了,支持批量图片
示例:上传图片 美图 \[图片]..
| 删除图片 | 6 | 删除图片 [图库] \[图片id] | 通过指定本地图片id来删除指定图库的图片
示例:删除图片 美图 1
| 移动图片 | 6 | 移动图片 \[移出的图库] \[移入的图库] \[图片id] | 移动指定图库中的图片到指定的新图库中,移入的图片id更改为移入图库的最后一位,移除的图库中原本图片的id又最后一位图片替代
示例:移动图片 美图 萝莉 22
+|B站订阅 | 5 | 功能同上,就是在群中有权限限制 | 略
### 超级用户功能
@@ -250,225 +254,12 @@
|pix检测更新 | pix检测更新 [update]? | 检测从未更新过的pid或uid,-update参数将在检测后直接更新未更新过的pid或uid
示例:pix检测更新 update
| 检查更新真寻 | 检查更新真寻 | 不再需要麻烦的clone第一步
| 关闭功能 | 关闭[功能] [group/private]/*[群号]? | 关闭色图:维护功能(关闭总开关)
关闭色图 g:在群内限制功能
关闭色图 p:在私聊限制功能
关闭色图 1234678:禁用12345678的色图功能
-| 群白名单 | 添加/删除群白名单 *[群号] | 白名单内的群不会受到 维护 限制
+| 群白名单 | 添加/删除群白名单 *[群号] / 查看群白名单 | 白名单内的群不会受到 维护 限制
| 功能状态 | 功能状态 | 查看功能开关状态
+| pix | pix [-s/-r] [keyword] | 可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
-## 部分功能展示
-
-部分功能展示及说明
-
-### 帮助以及开关(功能控制)
-
-群帮助将会在功能左侧展示该功能的开关,带有√或×的功能代表可以开关
-此插件使用 [nonebot_plugin_manager](https://github.com/Jigsaw111/nonebot_plugin_manager) 并魔改一点实现
-
-
-
-
-
-
-
-如果你希望某功能暂时停用
-私聊发送 npm block xx (xx=功能名)来锁定
-使用npm unblock xx 进行解锁
-
-
-
-
-### 签到
-普普通通的签到,设置影响开箱次数和涩图触发成功的概率(可配置)
-开箱次数 = 初始开箱数量 + 好感度 / 3
-金币 = random.randint(100) + random.randint(好感度)【好感度获取的金币不会超过200】
-
-
-
-### 黑白草图
-
-整活生成器(从未设想的道路)
-
-
-
-### 发送文件夹下随机图片
-
-提供了 美图589(获取该图库下文件名589.jpg的图片)方法,图库内图片名称需要有序(如:0.jpg,1.jpg....)
-
-
-
-### 色图
-
-略,send_setu/check_setu_hash.py文件用于记录涩图hash和检测文件名是否连贯(例如:0.jpg, 1.jpg....)
-
-### 开箱(csgo模拟开箱)
-
-我的开箱/群开箱统计/我的金色 功能是对开箱数据的统计展示
-
-目前支持的武器箱(数据已备好):
-* 狂牙大行动武器箱
-* 突围大行动武器箱
-* 命悬一线武器箱
-* 裂空武器箱
-* 光谱武器箱
-
- BUFF账号可能会因为短时间内访问api次数过多被禁止访问api!!
- 如果是第一次启动请先使用命令 “更新价格”, “更新图片” (需要配置cookie!!如果经常超时请设置代理,配置文件中的 buff_proxy!)
- 如果需要配置新的箱子,请在.config.py中配置好该箱子中的皮肤,且列表名是箱子名称的大写拼音
- 示例:光谱武器箱 GUANGPU_CASE_KNIFE,GUANGPU_CASE_RED...后面的颜色代表皮肤品质
-
-
-
-
-### BUFF皮肤底价查询
-
-需要配置cookie!!!!!!!!
-如果经常超时请设置代理,配置文件中的 buff_proxy!
-
-
-
-
-### coser
-
-
-
-### 鸡汤/语录
-
-
-
-### 骂我
-
-
-
-### 鲁迅说
-
-此插件使用 [nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says)
-
-
-
-### 假消息
-
-
-
-### 商店系统
-
-商店内的道具支持自定义,但需要写触发后的效果...整不出活,到头来也就增加好感度概率的商品
-
-
-
-
-
-### 昵称系统
-
-养成方法第一步,让可爱的小真寻叫自己昵称!(替换ai中的'你'等等)
-
-
-
-
-### 抽卡(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)
-
-
-
-
-### 原神黄历/今日素材/丘丘语翻译/地图资源查询
-
-使用大佬的插件 [Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)
-
-### 对图片的操作
-
-只是一些简单对图片操作(娱乐整活)
-
-
-
-### 识番
-
-使用大佬的插件 [XUN_Langskip](https://github.com/Angel-Hair/XUN_Bot)
-
-
-
-
-### 识图
-
-使用nb2商店插件 [nonebot_plugin_picsearcher](https://github.com/synodriver/nonebot_plugin_picsearcher) (可配置图片返回的最大数量)
-
-
-
-### epic免费游戏
-
-访问rsshub获取数据解析
可以不玩,不能没有
-
-
-
-
-### P站排行/搜图
-
-访问rsshub获取数据解析
-
-
-
-
-
-### 翻译
-
-
-
-### 自定义群欢迎消息
-
-关键字 [at] 判断是否艾特入群用户
-
-
-
-### 查看当前群欢迎消息
-
-
-
-### 自检
-
-
-
-### .ban/.unban
-
-
-
-### 查看被动技能(被动技能除复读外都提供了开关)
-
-
-
-### 自我介绍
-
-只是一段简单自我介绍,但是,还是想放上来
-
-
-
-### 我的信息/我的权限
-
-
-
-### 金币红包
-
-
-
-
-
-### 俄罗斯轮盘
-
-
-
-
-
-
-### 其他
-
-点歌:使用 [nonebot_plugin_songpicker2](https://github.com/maxesisn/nonebot_plugin_songpicker2) 插件
-
-## 其他功能请自己试一试 )
-
-
## 部署
@@ -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_RATIO,PIX功能发送PIX图库和扩展图库OmegaPixivIllusts图片的比例,如果没有使用扩展图库OmegaPixivIllusts,请设置为(10, 0)
+* 增加配置WITHDRAW_PIX_TIME,用于配置在开关PIX图片在群私聊的自动撤回
+* 上传图库cases, 开箱 也可以连抽(未更新过没有价格)
+* 新增命令 查看群白名单
+* plugins2info_dict新增键"default_status",设置加入新群时功能的默认开关状态
+* 增加配置plugins2exists_dict,可自定义是否阻塞某命令同时触发多次
+* 增加配置plugins2cd_dict,可自定义为命令添加cd
+* 新增B站订阅(直播/番剧/UP)[测试],提供命令:添加订阅 [主播/UP/番剧] [id/链接/番名],删除订阅 [id],查看订阅
+* 优化pix和色图的数据库查询
+* 触发已关闭的功能的正则时不再触发ai
+* 更换coser API
+* PIX搜索pid功能在群聊无法搜索PIX图库的r18和OmegaPixivIllusts的r15以及r18,超级用户除外
+* PIX单次搜索的图片张数超级用户限制为至多30张,普通用户10张
+* PIX超级用户新增-s,-r,可以通过pix -s 查看图库的涩图,pix -r查看图库的r18图,支持搜索,当然,pix图库只区分了r18和非r18,如果-s查询到不色的图也问题不大
+* 优化P站排行和搜图,现在需要艾特,改为使用HIBIAPI,在群内时将使用合并消息(群聊搜图会屏蔽R-18)
+* win10下playwright相关功能无法使用,但是不再需要删除文件
+* 签到大改,优化签到方式与逻辑,改为图片形式发送,有概率额外获得随机道具(好感度有加成)
+* 修改撤回功能,改为回复撤回,回复发送撤回
+* 更改logging为loguru
+* 删除了 发送图片 中的 [N]张图[keyword] 功能
+* 修复私聊 关闭[功能] 默认不为 全部 而要添加参数 ‘a’
+* 修复0权限用户可以修改禁言检测相关设置
+
### 2021/8/17
* 新增配置CHECK_NOTICE_INFO_CD,修改群权限,个人权限检测各种检测的提示消息cd
@@ -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)
diff --git a/__version__ b/__version__
new file mode 100644
index 00000000..f56c9dbb
--- /dev/null
+++ b/__version__
@@ -0,0 +1 @@
+__version__: v0.0.4.0
\ No newline at end of file
diff --git a/configs/config.py b/configs/config.py
index 19ff4aeb..906a99ba 100644
--- a/configs/config.py
+++ b/configs/config.py
@@ -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 混合搜索的比例 参1:PIX图库 参2:OmegaPixivIllusts扩展图库(没有此图库请设置为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:模块名称
+# cd:cd 时长(秒)
+# 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()
diff --git a/models/ban_user.py b/models/ban_user.py
index 8c9243b1..53f488dd 100644
--- a/models/ban_user.py
+++ b/models/ban_user.py
@@ -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:
"""
diff --git a/models/bilibili_sub.py b/models/bilibili_sub.py
new file mode 100644
index 00000000..f201c575
--- /dev/null
+++ b/models/bilibili_sub.py
@@ -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
diff --git a/models/group_member_info.py b/models/group_member_info.py
index 14c20ef4..a2ef57ac 100644
--- a/models/group_member_info.py
+++ b/models/group_member_info.py
@@ -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
+
diff --git a/models/omega_pixiv_illusts.py b/models/omega_pixiv_illusts.py
new file mode 100644
index 00000000..13ba0135
--- /dev/null
+++ b/models/omega_pixiv_illusts.py
@@ -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]
+
diff --git a/models/pixiv.py b/models/pixiv.py
index 28e023a3..328be221 100644
--- a/models/pixiv.py
+++ b/models/pixiv.py
@@ -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 1:r18 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: 是否r18,0:非r18 1:r18 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
diff --git a/models/russian_user.py b/models/russian_user.py
index 0de17014..26e5a207 100644
--- a/models/russian_user.py
+++ b/models/russian_user.py
@@ -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:
diff --git a/models/setu.py b/models/setu.py
index 23fb31c6..48c50b35 100644
--- a/models/setu.py
+++ b/models/setu.py
@@ -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:
"""
说明:
查询图片数量
diff --git a/models/sigin_group_user.py b/models/sign_group_user.py
similarity index 84%
rename from models/sigin_group_user.py
rename to models/sign_group_user.py
index 34ab0fbe..d605c164 100644
--- a/models/sigin_group_user.py
+++ b/models/sign_group_user.py
@@ -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 及对应 好感度
diff --git a/plugins/admin_bot_manage/data_source.py b/plugins/admin_bot_manage/data_source.py
index c73f8d10..5d08e24b 100644
--- a/plugins/admin_bot_manage/data_source.py
+++ b/plugins/admin_bot_manage/data_source.py
@@ -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
+
+
+
+
diff --git a/plugins/admin_bot_manage/switch_rule.py b/plugins/admin_bot_manage/switch_rule.py
index 88d7d23a..80d6c5ac 100644
--- a/plugins/admin_bot_manage/switch_rule.py
+++ b/plugins/admin_bot_manage/switch_rule.py
@@ -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))]:
diff --git a/plugins/admin_help/__init__.py b/plugins/admin_help/__init__.py
index 628fb1b1..37f15767 100644
--- a/plugins/admin_help/__init__.py
+++ b/plugins/admin_help/__init__.py
@@ -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')
diff --git a/plugins/ai/__init__.py b/plugins/ai/__init__.py
index a08a5823..7781e929 100644
--- a/plugins/ai/__init__.py
+++ b/plugins/ai/__init__.py
@@ -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))
diff --git a/plugins/ai/data_source.py b/plugins/ai/data_source.py
index f4a03247..f4e07af3 100644
--- a/plugins/ai/data_source.py
+++ b/plugins/ai/data_source.py
@@ -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:
diff --git a/plugins/alapi/wbtop.py b/plugins/alapi/wbtop.py
index d3a83691..817e3a61 100644
--- a/plugins/alapi/wbtop.py
+++ b/plugins/alapi/wbtop.py
@@ -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()
diff --git a/plugins/ban/__init__.py b/plugins/ban/__init__.py
index af4d70c7..6a4c7eac 100644
--- a/plugins/ban/__init__.py
+++ b/plugins/ban/__init__.py
@@ -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的对象..')
diff --git a/plugins/bilibili_sub/__init__.py b/plugins/bilibili_sub/__init__.py
new file mode 100644
index 00000000..f6491c0a
--- /dev/null
+++ b/plugins/bilibili_sub/__init__.py
@@ -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}")
diff --git a/plugins/bilibili_sub/data_source.py b/plugins/bilibili_sub/data_source.py
new file mode 100644
index 00000000..d4032287
--- /dev/null
+++ b/plugins/bilibili_sub/data_source.py
@@ -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('', "")
+ .replace("", ""),
+ }
+ 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
+
diff --git a/plugins/bilibili_sub/utils.py b/plugins/bilibili_sub/utils.py
new file mode 100644
index 00000000..89325453
--- /dev/null
+++ b/plugins/bilibili_sub/utils.py
@@ -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')
+
+
+
+
+
+
+
+
diff --git a/plugins/bt/__init__.py b/plugins/bt/__init__.py
index 86431c09..46af7cce 100644
--- a/plugins/bt/__init__.py
+++ b/plugins/bt/__init__.py
@@ -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)
diff --git a/plugins/check_zhenxun_update/__init__.py b/plugins/check_zhenxun_update/__init__.py
index d83ceda5..68564233 100644
--- a/plugins/check_zhenxun_update/__init__.py
+++ b/plugins/check_zhenxun_update/__init__.py
@@ -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')
diff --git a/plugins/check_zhenxun_update/data_source.py b/plugins/check_zhenxun_update/data_source.py
index 9e010abe..284adfc7 100644
--- a/plugins/check_zhenxun_update/data_source.py
+++ b/plugins/check_zhenxun_update/data_source.py
@@ -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}")
diff --git a/plugins/coser/__init__.py b/plugins/coser/__init__.py
index 2197618c..8afa2fb3 100644
--- a/plugins/coser/__init__.py
+++ b/plugins/coser/__init__.py
@@ -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}')
+
diff --git a/plugins/database_scripts.py b/plugins/database_scripts.py
new file mode 100644
index 00000000..160a31af
--- /dev/null
+++ b/plugins/database_scripts.py
@@ -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()
+
+
+
diff --git a/plugins/draw_card/announcement.py b/plugins/draw_card/announcement.py
index f0fc7c98..819fc8d5 100644
--- a/plugins/draw_card/announcement.py
+++ b/plugins/draw_card/announcement.py
@@ -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('/')
diff --git a/plugins/fudu.py b/plugins/fudu.py
index a3ac3d5b..c8406722 100644
--- a/plugins/fudu.py
+++ b/plugins/fudu.py
@@ -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 ""
diff --git a/plugins/genshin/query_resource_points/__init__.py b/plugins/genshin/query_resource_points/__init__.py
index 9211954f..caa2d0e3 100644
--- a/plugins/genshin/query_resource_points/__init__.py
+++ b/plugins/genshin/query_resource_points/__init__.py
@@ -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 = ""
diff --git a/plugins/group_handle/__init__.py b/plugins/group_handle/__init__.py
index 64344ab5..310329e5 100644
--- a/plugins/group_handle/__init__.py
+++ b/plugins/group_handle/__init__.py
@@ -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()
diff --git a/plugins/group_manager/__init__.py b/plugins/group_manager/__init__.py
index 1ef81650..b294187b 100644
--- a/plugins/group_manager/__init__.py
+++ b/plugins/group_manager/__init__.py
@@ -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('没有任何群在群白名单...')
diff --git a/plugins/help/config.py b/plugins/help/config.py
index 6b2c9b9c..08b02c28 100644
--- a/plugins/help/config.py
+++ b/plugins/help/config.py
@@ -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 = [
diff --git a/plugins/help/data_source.py b/plugins/help/data_source.py
index f459fcd5..d13c0cb8 100644
--- a/plugins/help/data_source.py
+++ b/plugins/help/data_source.py
@@ -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"
diff --git a/plugins/hook.py b/plugins/hook.py
index 1d4a17b4..6aef856e 100644
--- a/plugins/hook.py
+++ b/plugins/hook.py
@@ -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("有命令就别说话了")
diff --git a/plugins/luxun/__init__.py b/plugins/luxun/__init__.py
index 51b3b412..d3e989dd 100644
--- a/plugins/luxun/__init__.py
+++ b/plugins/luxun/__init__.py
@@ -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:
diff --git a/plugins/mute.py b/plugins/mute.py
index 3f124ef0..2ed9f922 100644
--- a/plugins/mute.py
+++ b/plugins/mute.py
@@ -29,6 +29,7 @@ mute_setting = on_command(
aliases={"设置检测时间", "设置检测次数", "设置禁言时长", "刷屏检测设置"},
permission=GROUP,
block=True,
+ priority=5
)
diff --git a/plugins/nonebot_plugin_withdraw/__init__.py b/plugins/nonebot_plugin_withdraw/__init__.py
deleted file mode 100644
index f0d4f4a3..00000000
--- a/plugins/nonebot_plugin_withdraw/__init__.py
+++ /dev/null
@@ -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("撤回失败,可能已超时")
diff --git a/plugins/nonebot_plugin_withdraw/config.py b/plugins/nonebot_plugin_withdraw/config.py
deleted file mode 100644
index 5e26d25b..00000000
--- a/plugins/nonebot_plugin_withdraw/config.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from pydantic import BaseSettings
-
-
-class Config(BaseSettings):
- withdraw_max_size: int = 50
-
- class Config:
- extra = 'ignore'
diff --git a/plugins/one_friend/__init__.py b/plugins/one_friend/__init__.py
index 60a9217d..8f798f55 100644
--- a/plugins/one_friend/__init__.py
+++ b/plugins/one_friend/__init__.py
@@ -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()))
diff --git a/plugins/open_cases/__init__.py b/plugins/open_cases/__init__.py
index 4a8a1ee7..f3c1d083 100644
--- a/plugins/open_cases/__init__.py
+++ b/plugins/open_cases/__init__.py
@@ -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:
diff --git a/plugins/open_cases/open_cases_c.py b/plugins/open_cases/open_cases_c.py
index e665540e..20de162f 100644
--- a/plugins/open_cases/open_cases_c.py
+++ b/plugins/open_cases/open_cases_c.py
@@ -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}')
diff --git a/plugins/parse_bilibili_json.py b/plugins/parse_bilibili_json.py
index ff02bfe5..f59ea9c7 100644
--- a/plugins/parse_bilibili_json.py
+++ b/plugins/parse_bilibili_json.py
@@ -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):
diff --git a/plugins/pix_gallery/__init__.py b/plugins/pix_gallery/__init__.py
index 5cf5d3dc..f38ef7ec 100644
--- a/plugins/pix_gallery/__init__.py
+++ b/plugins/pix_gallery/__init__.py
@@ -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}")
diff --git a/plugins/pix_gallery/data_source.py b/plugins/pix_gallery/data_source.py
index 76796c0c..17941f45 100644
--- a/plugins/pix_gallery/data_source.py
+++ b/plugins/pix_gallery/data_source.py
@@ -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:
diff --git a/plugins/pix_gallery/pix.py b/plugins/pix_gallery/pix.py
index 46860f10..6d995c9f 100644
--- a/plugins/pix_gallery/pix.py
+++ b/plugins/pix_gallery/pix.py
@@ -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}"
- )
diff --git a/plugins/pix_gallery/pix_show_info.py b/plugins/pix_gallery/pix_show_info.py
index e779f08d..9d9c537d 100644
--- a/plugins/pix_gallery/pix_show_info.py
+++ b/plugins/pix_gallery/pix_show_info.py
@@ -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_}"
)
diff --git a/plugins/pixiv/__init__.py b/plugins/pixiv/__init__.py
index 7b55d199..35916d80 100644
--- a/plugins/pixiv/__init__.py
+++ b/plugins/pixiv/__init__.py
@@ -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)
diff --git a/plugins/pixiv/data_source.py b/plugins/pixiv/data_source.py
index b3e7ca3c..ab295199 100644
--- a/plugins/pixiv/data_source.py
+++ b/plugins/pixiv/data_source.py
@@ -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
+
diff --git a/plugins/reimu/__init__.py b/plugins/reimu/__init__.py
index 26b7b46b..dad7b5e9 100644
--- a/plugins/reimu/__init__.py
+++ b/plugins/reimu/__init__.py
@@ -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(
diff --git a/plugins/russian/__init__.py b/plugins/russian/__init__.py
index c9b68326..d4ba9bed 100644
--- a/plugins/russian/__init__.py
+++ b/plugins/russian/__init__.py
@@ -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"))
# 随机子弹排列
diff --git a/plugins/russian/data_source.py b/plugins/russian/data_source.py
index 21041596..9c793e6d 100644
--- a/plugins/russian/data_source.py
+++ b/plugins/russian/data_source.py
@@ -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)
diff --git a/plugins/search_anime/__init__.py b/plugins/search_anime/__init__.py
index 6d62f3a8..04aa0f4e 100644
--- a/plugins/search_anime/__init__.py
+++ b/plugins/search_anime/__init__.py
@@ -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)
diff --git a/plugins/search_buff_skin_price/__init__.py b/plugins/search_buff_skin_price/__init__.py
index b5d0890c..aaa2291e 100644
--- a/plugins/search_buff_skin_price/__init__.py
+++ b/plugins/search_buff_skin_price/__init__.py
@@ -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("没有查询到哦,请检查格式吧")
diff --git a/plugins/send_img/__init__.py b/plugins/send_img/__init__.py
index 39b0757d..089aff9e 100644
--- a/plugins/send_img/__init__.py
+++ b/plugins/send_img/__init__.py
@@ -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())
diff --git a/plugins/send_setu/__init__.py b/plugins/send_setu/__init__.py
index 0879efea..3d1b2c09 100644
--- a/plugins/send_setu/__init__.py
+++ b/plugins/send_setu/__init__.py
@@ -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]))
diff --git a/plugins/send_setu/data_source.py b/plugins/send_setu/data_source.py
index c44c5fb0..1184eee3 100644
--- a/plugins/send_setu/data_source.py
+++ b/plugins/send_setu/data_source.py
@@ -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
diff --git a/plugins/shop/gold_redbag/__init__.py b/plugins/shop/gold_redbag/__init__.py
index 2b78f3a3..7f9de5c1 100644
--- a/plugins/shop/gold_redbag/__init__.py
+++ b/plugins/shop/gold_redbag/__init__.py
@@ -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
diff --git a/plugins/shop/use/data_source.py b/plugins/shop/use/data_source.py
index 72095b4b..4d628799 100644
--- a/plugins/shop/use/data_source.py
+++ b/plugins/shop/use/data_source.py
@@ -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
diff --git a/plugins/sign_in/__init__.py b/plugins/sign_in/__init__.py
index f4ae9b92..6ff29d26 100644
--- a/plugins/sign_in/__init__.py
+++ b/plugins/sign_in/__init__.py
@@ -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}')
diff --git a/plugins/sign_in/config.py b/plugins/sign_in/config.py
new file mode 100644
index 00000000..5c062d1e
--- /dev/null
+++ b/plugins/sign_in/config.py
@@ -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'
+}
+
+
+
+
+
+
diff --git a/plugins/sign_in/group_user_checkin.py b/plugins/sign_in/group_user_checkin.py
index 4fa4f75b..874c0be2 100644
--- a/plugins/sign_in/group_user_checkin.py
+++ b/plugins/sign_in/group_user_checkin.py
@@ -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)
diff --git a/plugins/sign_in/random_event.py b/plugins/sign_in/random_event.py
new file mode 100644
index 00000000..f1dda044
--- /dev/null
+++ b/plugins/sign_in/random_event.py
@@ -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'
+
+
+
+
+
diff --git a/plugins/sign_in/utils.py b/plugins/sign_in/utils.py
new file mode 100644
index 00000000..5ee15e95
--- /dev/null
+++ b/plugins/sign_in/utils.py
@@ -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)
+
diff --git a/plugins/statistics_hook.py b/plugins/statistics_hook.py
index fa274eb7..1371ee85 100644
--- a/plugins/statistics_hook.py
+++ b/plugins/statistics_hook.py
@@ -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)
diff --git a/plugins/super_cmd/__init__.py b/plugins/super_cmd/__init__.py
index 46c7a951..0081e936 100644
--- a/plugins/super_cmd/__init__.py
+++ b/plugins/super_cmd/__init__.py
@@ -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)
diff --git a/plugins/super_help/__init__.py b/plugins/super_help/__init__.py
index 6fe13153..f8d7d644 100644
--- a/plugins/super_help/__init__.py
+++ b/plugins/super_help/__init__.py
@@ -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)
diff --git a/plugins/update_gocqhttp/__init__.py b/plugins/update_gocqhttp/__init__.py
index 4b9df65d..5a21a83f 100644
--- a/plugins/update_gocqhttp/__init__.py
+++ b/plugins/update_gocqhttp/__init__.py
@@ -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
diff --git a/plugins/what_anime/__init__.py b/plugins/what_anime/__init__.py
index 2fbec594..2758699f 100644
--- a/plugins/what_anime/__init__.py
+++ b/plugins/what_anime/__init__.py
@@ -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)
diff --git a/plugins/withdraw.py b/plugins/withdraw.py
new file mode 100644
index 00000000..b1abc1fd
--- /dev/null
+++ b/plugins/withdraw.py
@@ -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))
+
diff --git a/resources/img/sign/sign_res/background/background_01.jpg b/resources/img/sign/sign_res/background/background_01.jpg
new file mode 100644
index 00000000..fe48e2e0
Binary files /dev/null and b/resources/img/sign/sign_res/background/background_01.jpg differ
diff --git a/resources/img/sign/sign_res/bar.png b/resources/img/sign/sign_res/bar.png
new file mode 100644
index 00000000..105955c4
Binary files /dev/null and b/resources/img/sign/sign_res/bar.png differ
diff --git a/resources/img/sign/sign_res/bar_white.png b/resources/img/sign/sign_res/bar_white.png
new file mode 100644
index 00000000..e04bca98
Binary files /dev/null and b/resources/img/sign/sign_res/bar_white.png differ
diff --git a/resources/img/sign/sign_res/border/ava_border_01.png b/resources/img/sign/sign_res/border/ava_border_01.png
new file mode 100644
index 00000000..b9af9cc2
Binary files /dev/null and b/resources/img/sign/sign_res/border/ava_border_01.png differ
diff --git a/resources/img/sign/sign_res/border/gift_border_02.png b/resources/img/sign/sign_res/border/gift_border_02.png
new file mode 100644
index 00000000..9d89b376
Binary files /dev/null and b/resources/img/sign/sign_res/border/gift_border_02.png differ
diff --git a/resources/img/sign/sign_res/white.png b/resources/img/sign/sign_res/white.png
new file mode 100644
index 00000000..366c89e4
Binary files /dev/null and b/resources/img/sign/sign_res/white.png differ
diff --git a/services/log.py b/services/log.py
index 30c76278..fa2443ad 100644
--- a/services/log.py
+++ b/services/log.py
@@ -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)
diff --git a/update_info.json b/update_info.json
index 65a59212..a7f49d21 100644
--- a/update_info.json
+++ b/update_info.json
@@ -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": []
}
diff --git a/utils/browser.py b/utils/browser.py
index e4eee6c4..b08f728b 100644
--- a/utils/browser.py
+++ b/utils/browser.py
@@ -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:
diff --git a/utils/image_utils.py b/utils/image_utils.py
index 7b8fa547..00bd3730 100644
--- a/utils/image_utils.py
+++ b/utils/image_utils.py
@@ -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:
diff --git a/utils/message_builder.py b/utils/message_builder.py
index 452e5356..f6135741 100644
--- a/utils/message_builder.py
+++ b/utils/message_builder.py
@@ -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:
diff --git a/utils/static_data/__init__.py b/utils/static_data/__init__.py
index 7563e9c0..c400aadf 100644
--- a/utils/static_data/__init__.py
+++ b/utils/static_data/__init__.py
@@ -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)
diff --git a/utils/static_data/data_class.py b/utils/static_data/data_class.py
index cca80a3b..0915b788 100644
--- a/utils/static_data/data_class.py
+++ b/utils/static_data/data_class.py
@@ -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
diff --git a/utils/static_data/group_manager.py b/utils/static_data/group_manager.py
index d34bfc74..6f16744e 100644
--- a/utils/static_data/group_manager.py
+++ b/utils/static_data/group_manager.py
@@ -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": []}
+
+
diff --git a/utils/utils.py b/utils/utils.py
index 668cd7e6..51d082fb 100644
--- a/utils/utils.py
+++ b/utils/utils.py
@@ -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
+
+