Compare commits

..
114 Commits
Author SHA1 Message Date
HibiKier 79185bd90f Update README.md 2022-07-26 18:31:30 +08:00
HibiKier d695c30988 Update __version__ 2022-07-26 18:30:09 +08:00
HibiKier 6ff6009a70 b站订阅up动态提供直链 2022-07-24 02:54:51 +08:00
HibiKier dadeb4006e Update __init__.py 2022-07-24 01:19:47 +08:00
HibiKier 1f01ba1d10 优化开箱次数判断 2022-07-23 14:09:17 +08:00
HibiKier 62965fe1df Merge pull request #928 from Sakuracio/main
update: README.md
2022-07-19 08:36:37 +08:00
MangataAkihi e29eb4cce5 Update README.md 2022-07-18 19:05:44 +08:00
MangataAkihi 699791e318 Update README.md 2022-07-18 19:03:32 +08:00
HibiKier d2aae0103d fix b23.tv bug 2022-07-16 05:48:00 +08:00
HibiKier ab06e38b7c update coser 2022-07-16 05:31:56 +08:00
HibiKier 8a0ca3c2e5 update README.md 2022-07-13 22:55:54 +08:00
HibiKier 97317ed2c6 update bilibili_sub 2022-07-13 22:54:13 +08:00
HibiKier 1bb9b2cb3f fix setu 2022-07-04 20:21:35 +08:00
HibiKier 7ba129b3bf update README.md 2022-07-04 20:03:38 +08:00
HibiKier 1e2c9ca28a Merge pull request #886 from yajiwa/main
修复B站订阅UP动态
2022-07-04 19:34:33 +08:00
yajiwa c6f37fd05f update bilibili_sub 2022-07-04 15:45:15 +08:00
HibiKier b6b569fff9 Update goods_info.py 2022-07-04 13:13:06 +08:00
HibiKier ac57c016a6 Update goods_info.py 2022-07-04 13:09:16 +08:00
HibiKier 28fdd9de95 Update __version__ 2022-07-04 12:29:33 +08:00
HibiKier 1ec946aaa9 Update README.md 2022-07-04 08:40:44 +08:00
HibiKier d6110e3c6f update bilibili_sub 2022-07-03 22:00:49 +08:00
HibiKier 4c5302bd4c fix shop update goods 2022-07-03 16:47:19 +08:00
HibiKier 21ee3d5c3e update send_setu 2022-07-03 16:33:14 +08:00
HibiKier e5c036cee8 update shop image 2022-07-03 13:55:26 +08:00
HibiKier 6f82488af7 Merge pull request #879 from VirtualTowel/main
修复图库内图片无法被连续删除的问题
2022-07-03 13:53:49 +08:00
VirtualTowel 57a7903c63 修复图库内图片无法被连续删除的问题 2022-07-01 20:12:39 +08:00
HibiKier 27b89b333a Merge pull request #866 from Excalibur5100/main
修复色图插件api修改无法搜索图片
2022-06-28 20:48:33 +08:00
Excalibur5100 ce2c4e7492 修复色图插件最近加tag参数后搜不到图的问题
插件所用API更新,最大数量num改为20
https://api.lolicon.app/#/setu
2022-06-28 19:48:59 +08:00
HibiKier cad98a2a33 Update goods_info.py 2022-06-26 22:23:19 +08:00
HibiKier 40da48e685 update models 2022-06-26 19:29:51 +08:00
HibiKier 1c393e5c3e update shop daily_limit 2022-06-26 03:08:23 +08:00
HibiKier 667c143c74 update pix 2022-06-26 01:37:47 +08:00
HibiKier bc089c18ce update bt 2022-06-26 01:26:14 +08:00
HibiKier 24b730c0e2 Merge pull request #847 from po-lan/main
对WSL虚拟机 代理 添加写法
2022-06-24 20:59:28 +08:00
po-lan 9ed9e9b973 对WSL虚拟机 代理 添加写法 2022-06-23 17:57:47 +08:00
HibiKier 5b0027aa3d Update README.md 2022-06-22 22:49:26 +08:00
HibiKier 810c5e4e8b Update README.md 2022-06-21 21:59:41 +08:00
HibiKier 907534958f Merge pull request #840 from yajiwa/main
update parse_bilibili
2022-06-21 21:59:23 +08:00
HibiKier f08a18ab07 Update data_class.py 2022-06-21 21:01:14 +08:00
github-actions[bot] 40549d5ca7 Auto generate poetry.lock 2022-06-21 00:56:57 +00:00
yajiwa 3e67edc506 update pyproject.toml 2022-06-21 08:53:49 +08:00
yajiwa 9c56a81f65 update parse_bilibili 2022-06-21 08:50:05 +08:00
HibiKier a9a636c9ae Update plugins2settings_manager.py 2022-06-20 22:31:57 +08:00
HibiKier 98374dcd74 Update README.md 2022-06-20 22:07:48 +08:00
HibiKier 10ca6eec91 update webui 2022-06-20 21:54:10 +08:00
HibiKier 216d32cf21 Update README.md 2022-06-19 23:16:11 +08:00
HibiKier 248fae4fe6 Update __version__ 2022-06-19 23:15:40 +08:00
HibiKier b479b6839d Update README.md 2022-06-19 22:29:44 +08:00
HibiKier 1a4e1e9515 Merge pull request #835 from yajiwa/main
词条优化问题展示,修改含机器人昵称和@逻辑
2022-06-19 22:29:20 +08:00
yajiwa e5160a4ee8 Merge branch 'HibiKier:main' into main 2022-06-19 17:26:13 +08:00
yajiwa 56ea3964a7 update word_bank 2022-06-19 17:24:50 +08:00
HibiKier ad73778286 update README.md 2022-06-19 16:55:02 +08:00
HibiKier 3e548f48c8 Merge pull request #828 from McElaga/main
修复原神树脂重复提醒的bug
2022-06-19 16:54:25 +08:00
HibiKier ae466931fa fix webui 2022-06-19 16:44:37 +08:00
HibiKier 68052b526f update image_utils 2022-06-18 15:23:36 +08:00
HibiKier 903b5b88a7 update image_utils 2022-06-18 15:09:55 +08:00
HibiKier 007823d6b2 update README.md 2022-06-18 15:03:05 +08:00
HibiKier db5c4fb349 Merge pull request #830 from po-lan/main
我不太会提交单个文件,我就把俄罗斯轮盘的文件 改回去了,再提交的
2022-06-18 15:00:46 +08:00
HibiKier c37901290a fix nickname 2022-06-18 14:57:54 +08:00
HibiKier da67f1f6f8 update webui 2022-06-18 14:48:46 +08:00
HibiKier 5172fa69e5 fix web ui 2022-06-18 14:31:44 +08:00
po-lan dd7280cd0d 恢复 原先的文件 2022-06-18 14:08:59 +08:00
McElaga 0d0f522c88 Merge branch 'HibiKier:main' into main 2022-06-18 09:27:12 +08:00
McElaga 5429e6ed5c Merge branch 'main' of https://github.com/McElaga/zhenxun_bot 2022-06-18 09:15:24 +08:00
McElaga 9db69fa05b 修复一点逻辑小问题 2022-06-18 09:15:19 +08:00
HibiKier 3b8d52bcb5 Update README.md 2022-06-17 18:50:37 +08:00
HibiKier 807f39a336 Update README.md 2022-06-17 18:50:15 +08:00
HibiKier fea2f30461 Merge pull request #820 from LambdaYH/patch-2
修复wordbank的一些小问题
2022-06-17 18:49:42 +08:00
po-lan 5d97e3f95f Update __init__.py 2022-06-16 16:15:39 +08:00
po-lan 63e6ca3e99 Update __init__.py 2022-06-16 15:40:46 +08:00
po-lan b11590ec3c ban掉被击毙的人一段时间 2022-06-16 15:38:20 +08:00
po-lan 3a43ed6919 如果需要 保存到 config 可以少调用一次 2022-06-16 14:38:41 +08:00
po-lan 15ce9c91fb Update __init__.py 2022-06-16 14:25:22 +08:00
LambdaYH 0e8d7537d4 fix wordbank 2022-06-16 00:43:32 +08:00
Cinte 1fca0787be fix: 修复之前更改正则引入的问题 2022-06-15 23:16:39 +08:00
HibiKier af30285c00 Update browser.py 2022-06-15 10:08:43 +08:00
HibiKier a84cab7afd replace bt url 2022-06-14 20:40:11 +08:00
HibiKier 593573ddfb fix pix 2022-06-14 19:48:32 +08:00
HibiKier e9e9f81bdb Merge pull request #806 from LambdaYH/patch-2
fix: 修复添加词条时对answer中图片的处理
2022-06-14 19:31:53 +08:00
HibiKier 61f624841b Merge pull request #810 from LambdaYH/patch-3
fix: 自动更新群组
2022-06-14 19:31:18 +08:00
HibiKier 4bb38a2730 Merge pull request #812 from po-lan/main
可关闭 ssl 验证
2022-06-14 19:22:25 +08:00
HibiKier d4ec0df00c Update http_utils.py 2022-06-14 19:22:12 +08:00
po-lan c8a7d855f8 Update http_utils.py 2022-06-14 18:47:43 +08:00
Cinte 73a126dcd5 fix: 自动更新群组 2022-06-14 09:18:03 +08:00
HibiKier 0736533389 fix search_image 2022-06-13 22:16:45 +08:00
Cinte 2695d658ab fix: 修复添加词条时对answer中图片的处理 2022-06-13 22:11:18 +08:00
HibiKier 947166e793 Merge pull request #804 from po-lan/main
Windows 重启适配
2022-06-13 20:20:30 +08:00
po-lan 80c49a7cf5 Update __init__.py 2022-06-13 15:34:28 +08:00
po-lan 55bfa8f669 Update __init__.py
Windows 重启适配
2022-06-13 15:24:28 +08:00
HibiKier 74ade14f5e Update README.md 2022-06-13 11:07:34 +08:00
HibiKier c9b5218ebc Merge pull request #798 from CopilotLaLaLa/main
webui中token.json文件写入补充
2022-06-13 11:07:11 +08:00
HibiKier b324b2bd65 Merge pull request #800 from yajiwa/main
update setu_img
2022-06-13 11:06:20 +08:00
HibiKier 35c038efa2 Update utils.py 2022-06-13 11:05:16 +08:00
HibiKier caa404d58d Update utils.py 2022-06-13 11:03:21 +08:00
yajiwa 830103b9d5 update change_img_md5 2022-06-13 10:59:29 +08:00
yajiwa 6e18379597 update setu_img 2022-06-13 10:08:51 +08:00
yajiwa 6effbacb28 add change_img_md5 2022-06-13 10:08:09 +08:00
CopilotLaLaLa a20a1a0234 同步原仓库 2022-06-12 15:23:10 +00:00
CopilotLaLaLa 3667724061 token_json文件写入 2022-06-12 15:16:07 +00:00
HibiKier 785179e4a7 update pix 2022-06-11 17:57:19 +08:00
HibiKier 715338f821 Merge pull request #791 from mmmjie/main
两处BUG的修复
2022-06-10 21:31:51 +08:00
mmmjie 7d5a82ab6d Update update_picture.py
对于temp/temp的错误路径,减少了一个temp
TEMP_PATH 已经指向了一个temp了
2022-06-10 00:37:18 +08:00
mmmjie e764cfcc1c Update white2black_image.py
随着7b836ac 对utils/image_utils.py 的改动
调整此插件对于 utils/image_utils.py改动的引用部分
2022-06-10 00:35:57 +08:00
HibiKier 363acf37bc fix bug and update 2022-06-09 20:39:48 +08:00
HibiKier 5fd687c1e4 Merge pull request #778 from SinKy-Yan/main
fix auto update bug
2022-06-09 19:37:26 +08:00
HibiKier dbedcbb93d Update pyproject.toml 2022-06-08 11:51:32 +08:00
HibiKier 9e9611f11f Update README.md 2022-06-08 11:43:10 +08:00
HibiKier 44002838da Merge pull request #779 from MingxuanGame/main
chore(deps): update `nonebot-adapter-onebot`
2022-06-08 11:42:43 +08:00
MingxuanGame 4daab8459f chore(deps): update nonebot-adapter-onebot 2022-06-07 11:57:34 +00:00
HibiKier 5a002f75cc Merge pull request #777 from LambdaYH/patch-1
fix image_utils.py
2022-06-07 19:27:31 +08:00
源源球球✨ a2180a1365 fix auto update bug 2022-06-07 10:19:23 +00:00
Cinte 7b836acf36 fix image_utils.py
https://github.com/HibiKier/zhenxun_bot/commit/ae8a214a3a5c08a51cacd1dc37583c0b32e6332f
之前这个commit里面看到函数参数有写着int类型就把`font_size`类型转换给去了,结果导致了部分地方输入float类型后报错。现在改回来
2022-06-07 17:06:16 +08:00
HibiKier a112a561cc Update README.md 2022-06-05 20:30:49 +08:00
HibiKier 6dcc2a69f4 Update README.md 2022-06-05 19:56:42 +08:00
89 changed files with 1786 additions and 1116 deletions
+1
View File
@@ -140,6 +140,7 @@ cython_debug/
test.py
server_ip.py
game_utils.py
member_activity_handle.py
Yu-Gi-Oh/
csgo/
+114 -9
View File
@@ -235,14 +235,118 @@ python bot.py
## 使用Docker
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
#### GitHub:[Sakuracio/zhenxun_bot_docker](https://github.com/Sakuracio/zhenxun_bot_docker)
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
__Docker 单机版(仅真寻Bot)__
**点击下方的 GitHub 徽标查看教程**
[![Github](https://shields.io/badge/GITHUB-Sakuracio-4476AF?logo=github&style=for-the-badge)](https://github.com/Sakuracio/zhenxun_bot_docker)
[![DOCKER](https://shields.io/badge/docker-hibikier/zhenxun_bot-4476AF?logo=docker&style=for-the-badge)](https://hub.docker.com/r/hibikier/zhenxun_bot)
__Docker 全量版(包含 真寻Bot PostgreSQL数据库 go-cqhttp webui等)__
[![Github](https://shields.io/badge/GITHUB-SinKy--Yan-4476AF?logo=github&style=for-the-badge)](https://github.com/SinKy-Yan/zhenxunbot-docker)
[![DOCKER](https://shields.io/badge/docker-jyishit/zhenxun_bot-4476AF?logo=docker&style=for-the-badge)](https://hub.docker.com/r/jyishit/zhenxun_bot)
**点击上方的 GitHub 徽标查看教程**
PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能无法正常启动全量版容器**
## 更新
### 2022/7/24 \[v0.1.6.2]
* 订阅up动态提供直链
### 2022/7/23
* 优化开箱次数判断
### 2022/7/16
* cos提供连发命令
* 修复B站视频解析中b23解析错误
### 2022/7/13
* B站订阅提供配置项`LIVE_MSG_AT_ALL`,`UP_MSG_AT_ALL`:控制UP动态投稿和直播是否AT全体
* 修改了Omega图库检测的数据库文件名
* game_utils提供了Game类
### 2022/7/7
* 微博热搜选择单条热搜时也会检测时效性 [@pull/891](https://github.com/HibiKier/zhenxun_bot/pull/891)
### 2022/7/4
* 修复商品未设置限购时无法购买
* 修复B站订阅UP动态 [@pull/886](https://github.com/HibiKier/zhenxun_bot/pull/886)
* 修复色图命令带tag时配置项`MAX_ONCE_NUM2FORWARD`无法生效
### 2022/7/3 \[v0.1.6.1]
* BagUser提供方法`check_props`方法,用于判断用户是否含有该道具并是否使用
* 优化商品显示图片,提供限制,限购,折扣提示
* 修复图库内图片无法被连续删除的问题 [@pull/879](https://github.com/HibiKier/zhenxun_bot/pull/879)
* 色图提供配置项`MAX_ONCE_NUM2FORWARD`:群聊中单次发送图片数量达到指定时使用合并转发
* 优化修复了商品修改命令
* B站订阅UP动态改为详情页截图
### 2022/6/28
* 修复色图插件api修改无法搜索图片 [@pull/866](https://github.com/HibiKier/zhenxun_bot/pull/866)
### 2022/6/26
* 替换了bt URL
* PIX当使用pid查询图片时,会发送该pid下所有图片
* 商店提供了每日购买次数限制
### 2022/6/24
* 对WSL虚拟机 代理 添加写法 [@pull/847](https://github.com/HibiKier/zhenxun_bot/pull/847)
### 2022/6/21
* update parse_bilibili [@pull/840](https://github.com/HibiKier/zhenxun_bot/pull/840)
### 2022/6/19 \[v0.1.6.0]
* 暂时使用hook修复webui中plugins2setting修改时会改变plugins2setting.cmd为字符串
* 修复原神树脂重复提醒的bug [@pull/828](https://github.com/HibiKier/zhenxun_bot/pull/828)
* 词条优化问题展示,修改含机器人昵称和@逻辑 [@pull/835](https://github.com/HibiKier/zhenxun_bot/pull/835)
### 2022/6/18
* 修复昵称系统`BLACK_WORD`为空时造成报错
* 修复特殊头像时背景透明化出错
* 修复text2image纯文本时换行时颜色不统一
* 优化webUI,当有插件出错时不会影响其他插件显示
* 优化Config类型注释 [@pull/830](https://github.com/HibiKier/zhenxun_bot/pull/830)
* 优化browser
### 2022/6/17
* 修复wordbank的一些小问题 @pull/820
### 2022/6/14
* AsyncHttpx提供可关闭 ssl 验证参数 [@pull/812](https://github.com/HibiKier/zhenxun_bot/pull/812)
* fix: 自动更新群组 [@pull/810](https://github.com/HibiKier/zhenxun_bot/pull/810)
* fix: 修复添加词条时对answer中图片的处理 [@pull/806](https://github.com/HibiKier/zhenxun_bot/pull/806)
* 修复pix中指定num无法生效
* 替换了bt URL
### 2022/6/13
* Windows 重启适配 [@pull/804](https://github.com/HibiKier/zhenxun_bot/pull/804)
* 色图等提供修改md5方法 [@pull/800](https://github.com/HibiKier/zhenxun_bot/pull/800)
* webui中token.json文件写入补充 [@pull/798](https://github.com/HibiKier/zhenxun_bot/pull/798)
* 修复识图某些图片可能会出错
### 2022/6/11
* pix当只有一个tag时且为数字时可以通过添加'#'防止判定为数量
### 2022/6/9
* 修复b站订阅同群二人以上相同订阅时发送多次信息
* 修复超级用户帮助中缺少了 ‘插件商店’ 相关帮助
* 昵称系统提供了详细帮助
### 2022/6/5 \[v0.1.5.9]
* webui修复plugin2setting中cmd从list转变为str
@@ -252,7 +356,6 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
### 2022/6/3
* 修复了webUI插件相关API问题
* 插件仓库在已安装插件边上会提示\[已安装]
* 修复ShopRegister kwargs某些字段无效
* 调整了一下查看所有请求中的年龄绘制 [@pull/745](https://github.com/HibiKier/zhenxun_bot/pull/745)
@@ -284,7 +387,6 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
* 新增自动更新插件```UPDATE_REMIND```:新版本提醒,原配置项```AUTO_UPDATE_ZHENXUN```改为自动更新升级
* black_word新增当群权限为-1时不再检测该群
* 修复非超级用户绑定原神cookie会被black_word阻拦
* 修复webui中plugins2setting修改时会改变plugins2setting.cmd为字符串
* 修复微博热搜报错,发红包小bug [@pull/688](https://github.com/HibiKier/zhenxun_bot/pull/688)
* 更多的中文提示
@@ -475,7 +577,7 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
* 修复点歌无法正确发送
* 修复我有一个朋友有时文本会包含CQ码
* 修复群欢消息被动控制文本未删除 [@pull/124](https://github.com/HibiKier/zhenxun_bot/pull/124)
* message_builder.image不再提供参数:abspath
* message_builder.image不再提供参数:abspath
### 2022/2/23
@@ -612,10 +714,13 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
__..... 更多更新信息请查看文档__
## Todo
- [ ] web管理
## 爱发电
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
## 感谢
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
[Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台.
+1 -1
View File
@@ -1 +1 @@
__version__: v0.1.5.9
__version__: v0.1.6.2
+3 -3
View File
@@ -4,9 +4,8 @@ from nonebot import on_message
from services.log import logger
from models.group_info import GroupInfo
from models.friend_user import FriendUser
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import NICKNAME, Config
from utils.manager import group_manager
from pathlib import Path
import shutil
@@ -42,7 +41,7 @@ Config.add_plugin_config(
)
cx = on_message(priority=9, block=False)
cx = on_message(priority=9999, block=False, rule=lambda: False)
# 早上好
@@ -107,6 +106,7 @@ async def _():
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
)
logger.info(f"自动更新群组 {g} 信息成功")
except Exception as e:
+1 -1
View File
@@ -7,10 +7,10 @@ from datetime import datetime
from services.log import logger
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
GroupIncreaseNoticeEvent,
GroupDecreaseNoticeEvent,
)
from nonebot.adapters.onebot.v11.exception import ActionFailed
from utils.manager import group_manager, plugins2settings_manager, requests_manager
from configs.config import NICKNAME
from models.group_info import GroupInfo
+1 -1
View File
@@ -1,6 +1,5 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
from nonebot.adapters.onebot.v11.exception import ActionFailed
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from models.bag_user import BagUser
@@ -23,6 +22,7 @@ from nonebot.typing import T_State
from typing import Optional
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
MessageEvent,
GroupMessageEvent,
PokeNotifyEvent,
+1 -1
View File
@@ -1,11 +1,11 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
Bot,
Event,
MessageEvent,
ActionFailed,
PokeNotifyEvent,
GroupMessageEvent,
)
+1 -1
View File
@@ -1,9 +1,9 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
MessageEvent,
GroupMessageEvent,
)
+2 -2
View File
@@ -1,6 +1,7 @@
from nonebot import on_request, on_message
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
FriendRequestEvent,
GroupRequestEvent,
MessageEvent,
@@ -8,7 +9,6 @@ from nonebot.adapters.onebot.v11 import (
from models.friend_user import FriendUser
from datetime import datetime
from configs.config import NICKNAME, Config
from nonebot.adapters.onebot.v11.exception import ActionFailed
from utils.manager import requests_manager
from models.group_info import GroupInfo
from utils.utils import scheduler
@@ -25,7 +25,7 @@ __plugin_configs__ = {
friend_req = on_request(priority=5, block=True)
group_req = on_request(priority=5, block=True)
x = on_message(priority=999, block=False)
x = on_message(priority=999, block=False, rule=lambda: False)
exists_data = {"private": {}, "group": {}}
+9 -2
View File
@@ -22,6 +22,12 @@ __plugin_des__ = "区区昵称,才不想叫呢!"
__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["昵称", "昵称系统"],
}
__plugin_configs__ = {
"BLACK_WORD": {
"value": ["爸", "爹", "爷", "父亲"],
@@ -57,8 +63,9 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True)
_tmp = ""
black_word = Config.get_config("nickname", "BLACK_WORD")
for x in msg:
_tmp += "*" if x in black_word else x
if black_word:
for x in msg:
_tmp += "*" if x in black_word else x
msg = _tmp
if isinstance(event, GroupMessageEvent):
if await GroupInfoUser.set_group_member_nickname(
+1 -1
View File
@@ -20,7 +20,7 @@ usage:
卸载插件 [name/id]
""".strip()
__plugin_des__ = "从真寻适配仓库中下载插件"
__plugin_cmd__ = [""]
__plugin_cmd__ = ["查看插件仓库", "更新插件仓库", "安装插件 [name/id]", "卸载插件 [name/id]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
+8 -3
View File
@@ -81,7 +81,7 @@ async def install_plugin(name: str) -> str:
json.dump(data[name], f, ensure_ascii=False, indent=4)
logger.debug("移动插件文件夹完成...")
logger.info(f"成功安装插件 {name} 成功!\n{tmp}")
return f"成功安装插件 {name},请重启bot!"
return f"成功安装插件 {name},请重启真寻!"
except Exception as e:
logger.error(f"安装插件 {name} 失败 {type(e)}:{e}")
return f"安装插件 {name} 失败 {type(e)}:{e}"
@@ -130,12 +130,17 @@ async def show_plugin_repo() -> Union[int, str]:
"download_url": plugin_info[key]["download_url"],
"github_url": plugin_info[key]["github_url"],
}
status = ""
version = ""
if key in load_plugin_list:
status = "<f font_color=#1a7e30>[已安装]</f>"
version = f"<f font_color=#1a7e30>[{plugins_manager.get_data()[key]['version']}]</f>"
s = (
f'id:{i+1}\n名称:{plugin_info[key]["plugin_name"]}'
f' \t\t{"<f font_color=#1a7e30>[已安装]</f>" if key in load_plugin_list else ""}\n'
f' \t\t{status}\n'
f"模块:{key}\n"
f'作者:{plugin_info[key]["author"]}\n'
f'版本:{plugin_info[key]["version"]}\n'
f'版本:{plugin_info[key]["version"]} \t\t{version}\n'
f'简介:{plugin_info[key]["introduction"]}\n'
f"-------------------"
)
+8
View File
@@ -112,6 +112,14 @@ async def _():
"ALTER TABLE chat_history ADD plain_text Text;",
"chat_history"
), # 新增纯文本
(
"ALTER TABLE goods_info ADD daily_limit Integer DEFAULT 0;",
"goods_info"
), # 新增纯文本
(
"ALTER TABLE goods_info ADD daily_purchase_limit Json DEFAULT '{}';",
"goods_info"
), # 新增纯文本
]
for sql in sql_str:
try:
+4
View File
@@ -77,7 +77,11 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
await BagUser.get_gold(event.user_id, event.group_id)
) < goods.goods_price * num * goods.goods_discount:
await buy.finish("您的金币好像不太够哦", at_sender=True)
flag, n = await GoodsInfo.check_user_daily_purchase(goods, event.user_id, event.group_id, num)
if flag:
await buy.finish(f"该次购买将超过每日次数限制,目前该道具还可以购买{n}次哦", at_sender=True)
if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
await GoodsInfo.add_user_daily_purchase(goods, event.user_id, event.group_id, num)
await buy.send(
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
at_sender=True,
+15 -3
View File
@@ -1,10 +1,10 @@
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info, GoodsInfo
from nonebot.adapters.onebot.v11 import MessageEvent, Message
from nonebot import on_command
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from nonebot.permission import SUPERUSER
from utils.utils import is_number
from utils.utils import is_number, scheduler
from nonebot.params import CommandArg
from nonebot.plugin import export
from services.log import logger
@@ -128,6 +128,18 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功")
else:
await shop_update_goods.send(f"修改商品 {name} 失败了...", at_sender=True)
await shop_update_goods.send(name, at_sender=True)
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败")
@scheduler.scheduled_job(
"cron",
hour=0,
minute=0,
)
async def _():
try:
await GoodsInfo.reset_daily_purchase()
logger.info("商品每日限购次数重置成功...")
except Exception as e:
logger.error(f"商品每日限购次数重置发生错误 {type(e)}:{e}")
+102 -38
View File
@@ -1,9 +1,11 @@
from PIL import Image
from models.goods_info import GoodsInfo
from utils.image_utils import BuildImage
from models.sign_group_user import SignGroupUser
from utils.utils import is_number
from configs.path_config import IMAGE_PATH
from typing import Optional, Union
from typing import Optional, Union, Tuple
from configs.config import Config
from nonebot import Driver
from nonebot.plugin import require
@@ -32,6 +34,7 @@ async def init_default_shop_goods():
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
),
load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
daily_limit=(10, 20, 30),
** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
)
async def sign_card(user_id: int, group_id: int, prob: float):
@@ -62,8 +65,9 @@ async def create_shop_help() -> str:
_list.append(goods)
A = BuildImage(1000, h, color="#f9f6f2")
current_h = 0
total_n = 0
for goods in _list:
bk = BuildImage(700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
bk = BuildImage(1180, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
goods_image = BuildImage(
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
)
@@ -75,16 +79,27 @@ async def create_shop_help() -> str:
)
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
await name_image.atext((390, 0), "售价:", center_type="by_height")
await name_image.atext(
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
)
if goods.goods_discount != 1:
discount_price = int(goods.goods_discount * goods.goods_price)
old_price_image = BuildImage(0, 0, plain_text=str(goods.goods_price), font_color=(194, 194, 194), font="CJGaoDeGuo.otf", font_size=15)
await old_price_image.aline((0, int(old_price_image.h / 2), old_price_image.w + 1, int(old_price_image.h / 2)), (0, 0, 0))
await name_image.apaste(
old_price_image, (440, 0), True
)
await name_image.atext(
(440, 15), str(discount_price), (255, 255, 255)
)
else:
await name_image.atext(
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
)
await name_image.atext(
(
440
+ BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w,
0,
),
" 金币",
f" 金币",
center_type="by_height",
)
await name_image.acircle_corner(5)
@@ -92,15 +107,18 @@ async def create_shop_help() -> str:
await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
await goods_image.acircle_corner(20)
await bk.apaste(goods_image, alpha=True)
n = 0
_w = 550
# 添加限时图标和时间
if goods.goods_limit_time > 0:
n += 140
_limit_time_logo = BuildImage(
40, 40, background=f"{IMAGE_PATH}/other/time.png"
)
await bk.apaste(_limit_time_logo, (600, 0), True)
await bk.apaste(_limit_time_logo, (_w + 50, 0), True)
await bk.apaste(
BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"),
(640, 10),
(_w + 90, 10),
True,
)
limit_time = time.strftime(
@@ -109,28 +127,66 @@ async def create_shop_help() -> str:
y_m_d = limit_time[0]
_h_m = limit_time[1].split(":")
h_m = _h_m[0] + "时 " + _h_m[1] + "分"
await bk.atext((605, 38), str(y_m_d))
await bk.atext((615, 57), str(h_m))
await bk.aline((550, -1, 710, -1), "#a29ad6", 5)
await bk.aline((550, 80, 710, 80), "#a29ad6", 5)
await bk.atext((_w + 55, 38), str(y_m_d))
await bk.atext((_w + 65, 57), str(h_m))
_w += 140
if goods.goods_discount != 1:
n += 140
_discount_logo = BuildImage(30, 30, background=f"{IMAGE_PATH}/other/discount.png")
await bk.apaste(_discount_logo, (_w + 50, 10), True)
await bk.apaste(
BuildImage(0, 0, plain_text="折扣!", font_size=23, font="CJGaoDeGuo.otf"),
(_w + 90, 15),
True,
)
await bk.apaste(
BuildImage(0, 0, plain_text=f"{10 * goods.goods_discount:.1f} 折", font_size=30, font="CJGaoDeGuo.otf", font_color=(85, 156, 75)),
(_w + 50, 44),
True,
)
_w += 140
if goods.daily_limit != 0:
n += 140
_daily_limit_logo = BuildImage(35, 35, background=f"{IMAGE_PATH}/other/daily_limit.png")
await bk.apaste(_daily_limit_logo, (_w + 50, 10), True)
await bk.apaste(
BuildImage(0, 0, plain_text="限购!", font_size=23, font="CJGaoDeGuo.otf"),
(_w + 90, 20),
True,
)
await bk.apaste(
BuildImage(0, 0, plain_text=f"{goods.daily_limit}", font_size=30, font="CJGaoDeGuo.otf"),
(_w + 72, 45),
True,
)
if total_n < n:
total_n = n
if n:
await bk.aline((550, -1, 550 + n, -1), "#a29ad6", 5)
await bk.aline((550, 80, 550 + n, 80), "#a29ad6", 5)
# 添加限时图标和时间
idx += 1
await A.apaste(bk, (0, current_h), True)
current_h += 90
w = 1000
w = 850
if total_n:
w += total_n
h = A.h + 230 + 100
h = 1000 if h < 1000 else h
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
shop.paste(A, (20, 230))
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan.png")
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan_3.png")
zx_img.transpose(Image.FLIP_LEFT_RIGHT)
zx_img.replace_color_tran(((240, 240, 240), (255, 255, 255)), (249, 246, 242))
await shop.apaste(zx_img, (780, 100))
await shop.apaste(zx_img, (0, 100))
shop.paste(A, (20 + zx_img.w, 230))
await shop.apaste(shop_logo, (450, 30), True)
shop.text(
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
"注【通过 序号 或者 商品名称 购买】",
)
shop.text((20, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
shop.text((20 + zx_img.w, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
return shop.pic2bs4()
@@ -140,6 +196,7 @@ async def register_goods(
des: str,
discount: Optional[float] = 1,
limit_time: Optional[int] = 0,
daily_limit: Optional[int] = 0,
) -> bool:
"""
添加商品
@@ -151,6 +208,7 @@ async def register_goods(
:param des: 商品简介
:param discount: 商品折扣
:param limit_time: 商品限时销售时间,单位为小时
:param daily_limit: 每日购买次数限制
:return: 是否添加成功
"""
if not await GoodsInfo.get_goods_info(name):
@@ -162,7 +220,7 @@ async def register_goods(
else 0
)
return await GoodsInfo.add_goods(
name, int(price), des, float(discount), limit_time
name, int(price), des, float(discount), limit_time, daily_limit
)
return False
@@ -192,7 +250,7 @@ async def delete_goods(name: str, id_: int) -> "str, str, int":
# 更新商品信息
async def update_goods(**kwargs) -> "str, str, int":
async def update_goods(**kwargs) -> Tuple[bool, str, str]:
"""
更新商品信息
:param kwargs: kwargs
@@ -202,17 +260,18 @@ async def update_goods(**kwargs) -> "str, str, int":
goods_lst = await GoodsInfo.get_all_goods()
if is_number(kwargs["name"]):
if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst):
return "序号错误,没有该序号的商品...", "", 999
return False, "序号错误,没有该序号的商品...", ""
goods = goods_lst[int(kwargs["name"]) - 1]
else:
goods = await GoodsInfo.get_goods_info(kwargs["name"])
if not goods:
return "名称错误,没有该名称的商品...", "", 999
name = goods.goods_name
return False, "名称错误,没有该名称的商品...", ""
name: str = goods.goods_name
price = goods.goods_price
des = goods.goods_description
discount = goods.goods_discount
limit_time = goods.goods_limit_time
daily_limit = goods.daily_limit
new_time = 0
tmp = ""
if kwargs.get("price"):
@@ -229,24 +288,25 @@ async def update_goods(**kwargs) -> "str, str, int":
new_time = time.strftime(
"%Y-%m-%d %H:%M:%S",
time.localtime(time.time() + kwargs["limit_time"] * 60 * 60),
)
tmp += f"限时至: {new_time}\n"
) if kwargs["limit_time"] != 0 else 0
tmp += f"限时至: {new_time}\n" if new_time else "取消了限时\n"
limit_time = kwargs["limit_time"]
return (
await GoodsInfo.update_goods(
name,
int(price),
des,
float(discount),
int(
time.time() + limit_time * 60 * 60
if limit_time != 0 and new_time
else 0
),
),
if kwargs.get("daily_limit"):
tmp += f'每日购买限制:{daily_limit} --> {kwargs["daily_limit"]}\n' if daily_limit else "取消了购买限制\n"
daily_limit = int(kwargs["daily_limit"])
await GoodsInfo.update_goods(
name,
tmp[:-1],
int(price),
des,
float(discount),
int(
time.time() + limit_time * 60 * 60
if limit_time != 0 and new_time
else 0
),
daily_limit
)
return True, name, tmp[:-1],
def parse_goods_info(msg: str) -> Union[dict, str]:
@@ -276,6 +336,10 @@ def parse_goods_info(msg: str) -> Union[dict, str]:
data["discount"] = sp[1]
elif sp[0] == "limit_time":
if not is_number(sp[1]) or float(sp[1]) < 0:
return "limit_time参数不合法,必须大于0!"
return "limit_time参数不合法,必须为数字且大于0!"
data["limit_time"] = sp[1]
elif sp[0] == "daily_limit":
if not is_number(sp[1]) or float(sp[1]) < 0:
return "daily_limit参数不合法,必须为数字且大于0!"
data["daily_limit"] = sp[1]
return data
+11 -11
View File
@@ -1,4 +1,11 @@
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GROUP, GroupMessageEvent, Message
from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent,
GROUP,
GroupMessageEvent,
Message,
ActionFailed,
)
from nonebot import on_command, on_regex
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
@@ -8,7 +15,6 @@ from utils.manager import group_manager, plugins2settings_manager
from models.group_info import GroupInfo
from services.log import logger
from configs.config import NICKNAME
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.params import Command, CommandArg
from typing import Tuple
@@ -137,9 +143,7 @@ async def _():
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
msg = arg.extract_plain_text().strip().split()
all_group = [
g["group_id"] for g in await bot.get_group_list()
]
all_group = [g["group_id"] for g in await bot.get_group_list()]
group_list = []
for group in msg:
if is_number(group) and int(group) in all_group:
@@ -151,9 +155,7 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
else:
group_manager.delete_group_white_list(group)
group_list = [str(x) for x in group_list]
await manager_group_whitelist.send(
"已成功将 " + "\n".join(group_list) + " " + cmd
)
await manager_group_whitelist.send("已成功将 " + "\n".join(group_list) + " " + cmd)
else:
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
@@ -199,6 +201,4 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
else:
if await GroupInfo.get_group_info(group_id):
await GroupInfo.set_group_flag(group_id, 0)
await group_auth.send(
f'已为 {group_id} {cmd[:2]}群认证..'
)
await group_auth.send(f"已为 {group_id} {cmd[:2]}群认证..")
+5
View File
@@ -2,6 +2,10 @@ from typing import Optional
from pathlib import Path
from .utils import ConfigsManager
import platform
if platform.system() == "Linux":
import os
hostip = os.popen("cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }'").read().replace("\n","")
# 回复消息名称
NICKNAME: str = "小真寻"
@@ -18,6 +22,7 @@ port: str = "" # 数据库端口
database: str = "" # 数据库名称
# 代理,例如 "http://127.0.0.1:7890"
# 如果是WLS 可以 f"http://{hostip}:7890" 使用寄主机的代理
SYSTEM_PROXY: Optional[str] = None # 全局代理
+4 -3
View File
@@ -94,12 +94,13 @@ class ConfigsManager:
del self._data[module]
self.save()
def set_config(self, module: str, key: str, value: str):
def set_config(self, module: str, key: str, value: Any , save_simple_data: bool = False):
"""
设置配置值
:param module: 模块名
:param key: 配置名称
:param value: 值
:param save_simple_data: 同时保存至config.yaml
"""
if module in self._data.keys():
if (
@@ -108,7 +109,7 @@ class ConfigsManager:
):
self._data[module][key]["value"] = value
self._simple_data[module][key] = value
self.save()
self.save(save_simple_data = save_simple_data)
def set_help(self, module: str, key: str, help_: str):
"""
@@ -122,7 +123,7 @@ class ConfigsManager:
self._data[module][key]["help"] = help_
self.save()
def set_default_value(self, module: str, key: str, value: str):
def set_default_value(self, module: str, key: str, value: Any):
"""
设置配置默认值
:param module: 模块名
+19 -19
View File
@@ -22,9 +22,9 @@ class BagUser(db.Model):
@classmethod
async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
"""
说明:
说明:
获取金币概况
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
"""
@@ -44,9 +44,9 @@ class BagUser(db.Model):
@classmethod
async def get_gold(cls, user_qq: int, group_id: int) -> int:
"""
说明:
说明:
获取当前金币
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
"""
@@ -64,9 +64,9 @@ class BagUser(db.Model):
@classmethod
async def get_property(cls, user_qq: int, group_id: int) -> Dict[str, int]:
"""
说明:
说明:
获取当前道具
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
"""
@@ -84,9 +84,9 @@ class BagUser(db.Model):
@classmethod
async def add_gold(cls, user_qq: int, group_id: int, num: int):
"""
说明:
说明:
增加金币
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param num: 金币数量
@@ -112,9 +112,9 @@ class BagUser(db.Model):
@classmethod
async def spend_gold(cls, user_qq: int, group_id: int, num: int):
"""
说明:
说明:
花费金币
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param num: 金币数量
@@ -140,9 +140,9 @@ class BagUser(db.Model):
@classmethod
async def add_property(cls, user_qq: int, group_id: int, name: str):
"""
说明:
说明:
增加道具
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param name: 道具名称
@@ -165,9 +165,9 @@ class BagUser(db.Model):
cls, user_qq: int, group_id: int, name: str, num: int = 1
) -> bool:
"""
说明:
说明:
使用/删除 道具
参数:
参数:
:param user_qq: qq号
:param group_id: 所在群号
:param name: 道具名称
@@ -192,9 +192,9 @@ class BagUser(db.Model):
cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int
) -> bool:
"""
说明:
说明:
购买道具
参数:
参数:
:param user_qq: 用户qq
:param group_id: 所在群聊
:param goods: 商品
@@ -209,14 +209,14 @@ class BagUser(db.Model):
return True
except Exception as e:
logger.error(f"buy_property 发生错误 {type(e)}:{e}")
return False
return False
@classmethod
async def get_all_users(cls, group_id: Optional[int] = None) -> List["BagUser"]:
"""
说明:
说明:
获取所有用户数据
参数:
参数:
:param group_id: 群号
"""
if not group_id:
+12 -12
View File
@@ -15,9 +15,9 @@ class BanUser(db.Model):
@classmethod
async def check_ban_level(cls, user_qq: int, level: int) -> bool:
"""
说明:
说明:
检测ban掉目标的用户与unban用户的权限等级大小
参数:
参数:
:param user_qq: unban用户的qq号
:param level: ban掉目标用户的权限等级
"""
@@ -31,9 +31,9 @@ class BanUser(db.Model):
@classmethod
async def check_ban_time(cls, user_qq: int) -> str:
"""
说明:
说明:
检测用户被ban时长
参数:
参数:
:param user_qq: qq号
"""
query = cls.query.where((cls.user_qq == user_qq))
@@ -49,9 +49,9 @@ class BanUser(db.Model):
@classmethod
async def is_ban(cls, user_qq: int) -> bool:
"""
说明:
说明:
判断用户是否被ban
参数:
参数:
:param user_qq: qq号
"""
if await cls.check_ban_time(user_qq):
@@ -63,9 +63,9 @@ class BanUser(db.Model):
@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()
@@ -77,9 +77,9 @@ class BanUser(db.Model):
@classmethod
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
"""
说明:
说明:
ban掉目标用户
参数:
参数:
:param user_qq: 目标用户qq号
:param ban_level: 使用ban命令用户的权限
:param duration: ban时长,秒
@@ -104,9 +104,9 @@ class BanUser(db.Model):
@classmethod
async def unban(cls, user_qq: int) -> bool:
"""
说明:
说明:
unban用户
参数:
参数:
:param user_qq: qq号
"""
query = cls.query.where((cls.user_qq == user_qq))
+18 -18
View File
@@ -28,9 +28,9 @@ class ChatHistory(db.Model):
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
说明:
获取用户消息
参数:
参数:
:param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊
:param days: 限制日期
@@ -46,9 +46,9 @@ class ChatHistory(db.Model):
date_scope: Tuple[datetime, datetime] = None,
) -> List["ChatHistory"]:
"""
说明:
说明:
获取群聊指定用户聊天记录
参数:
参数:
:param uid: qq
:param gid: 群号
:param limit: 获取数量
@@ -63,9 +63,9 @@ class ChatHistory(db.Model):
@classmethod
async def get_group_user_msg_count(cls, uid: int, gid: int) -> Optional[int]:
"""
说明:
说明:
查询群聊指定用户的聊天记录数量
参数:
参数:
:param uid: qq
:param gid: 群号
"""
@@ -86,9 +86,9 @@ class ChatHistory(db.Model):
date_scope: Optional[Tuple[datetime, datetime]] = None,
) -> Optional[Tuple[int, int]]:
"""
说明:
说明:
获取排行数据
参数:
参数:
:param gid: 群号
:param limit: 获取数量
:param order: 排序类型,desc,des
@@ -103,9 +103,9 @@ class ChatHistory(db.Model):
@classmethod
async def get_group_first_msg_datetime(cls, gid: int) -> Optional[datetime]:
"""
说明:
说明:
获取群第一条记录消息时间
参数:
参数:
:param gid:
"""
if (
@@ -124,9 +124,9 @@ class ChatHistory(db.Model):
days: Optional[int] = None,
) -> int:
"""
说明:
说明:
获取用户消息数量
参数:
参数:
:param uid: 用户qq
:param msg_type: 消息类型,私聊或群聊
:param days: 限制日期
@@ -142,9 +142,9 @@ class ChatHistory(db.Model):
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
说明:
获取群聊消息
参数:
参数:
:param gid: 用户qq
:param days: 限制日期
"""
@@ -157,9 +157,9 @@ class ChatHistory(db.Model):
days: Optional[int] = None,
) -> List["ChatHistory"]:
"""
说明:
说明:
获取群聊消息数量
参数:
参数:
:param gid: 用户qq
:param days: 限制日期
"""
@@ -178,9 +178,9 @@ class ChatHistory(db.Model):
is_select_count: bool = False,
):
"""
说明:
说明:
获取消息查询query
参数:
参数:
:param uid: 用户qq
:param gid: 群号
:param type_: 类型,私聊或群聊
+10 -10
View File
@@ -15,9 +15,9 @@ class FriendUser(db.Model):
@classmethod
async def get_user_name(cls, user_id: int) -> str:
"""
说明:
说明:
获取好友用户名称
参数:
参数:
:param user_id: qq号
"""
query = cls.query.where(cls.user_id == user_id)
@@ -30,9 +30,9 @@ class FriendUser(db.Model):
@classmethod
async def add_friend_info(cls, user_id: int, user_name: str) -> bool:
"""
说明:
说明:
添加好友信息
参数:
参数:
:param user_id: qq号
:param user_name: 用户名称
"""
@@ -55,9 +55,9 @@ class FriendUser(db.Model):
@classmethod
async def delete_friend_info(cls, user_id: int) -> bool:
"""
说明:
说明:
删除好友信息
参数:
参数:
:param user_id: qq号
"""
try:
@@ -72,9 +72,9 @@ class FriendUser(db.Model):
@classmethod
async def get_friend_nickname(cls, user_id: int) -> str:
"""
说明:
说明:
获取用户昵称
参数:
参数:
:param user_id: qq号
"""
query = cls.query.where(cls.user_id == user_id)
@@ -92,9 +92,9 @@ class FriendUser(db.Model):
@classmethod
async def set_friend_nickname(cls, user_id: int, nickname: str) -> bool:
"""
说明:
说明:
设置用户昵称
参数:
参数:
:param user_id: qq号
:param nickname: 昵称
"""
+102 -35
View File
@@ -1,5 +1,5 @@
from services.db_context import db
from typing import Optional, List
from typing import Optional, List, Tuple
from services.log import logger
@@ -12,27 +12,33 @@ class GoodsInfo(db.Model):
goods_description = db.Column(db.TEXT(), nullable=False) # 商品描述
goods_discount = db.Column(db.Numeric(scale=3, asdecimal=False), default=1) # 打折
goods_limit_time = db.Column(db.BigInteger(), default=0) # 限时
daily_limit = db.Column(db.Integer(), nullable=False, default=0) # 每日购买限制
daily_purchase_limit = db.Column(
db.JSON(), nullable=False, default={}
) # 每日购买限制数据存储
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
@classmethod
async def add_goods(
cls,
goods_name: str,
goods_price: int,
goods_description: str,
goods_discount: float = 1,
goods_limit_time: int = 0,
cls,
goods_name: str,
goods_price: int,
goods_description: str,
goods_discount: float = 1,
goods_limit_time: int = 0,
daily_limit: int = 0,
) -> bool:
"""
说明:
说明:
添加商品
参数:
参数:
:param goods_name: 商品名称
:param goods_price: 商品价格
:param goods_description: 商品简介
:param goods_discount: 商品折扣
:param goods_limit_time: 商品限时
:param daily_limit: 每日购买限制
"""
try:
if not await cls.get_goods_info(goods_name):
@@ -42,6 +48,7 @@ class GoodsInfo(db.Model):
goods_description=goods_description,
goods_discount=goods_discount,
goods_limit_time=goods_limit_time,
daily_limit=daily_limit,
)
return True
except Exception as e:
@@ -51,15 +58,15 @@ class GoodsInfo(db.Model):
@classmethod
async def delete_goods(cls, goods_name: str) -> bool:
"""
说明:
说明:
删除商品
参数:
参数:
:param goods_name: 商品名称
"""
query = (
await cls.query.where(cls.goods_name == goods_name)
.with_for_update()
.gino.first()
.with_for_update()
.gino.first()
)
if not query:
return False
@@ -68,50 +75,51 @@ class GoodsInfo(db.Model):
@classmethod
async def update_goods(
cls,
goods_name: str,
goods_price: Optional[int] = None,
goods_description: Optional[str] = None,
goods_discount: Optional[float] = None,
goods_limit_time: Optional[int] = None,
cls,
goods_name: str,
goods_price: Optional[int] = None,
goods_description: Optional[str] = None,
goods_discount: Optional[float] = None,
goods_limit_time: Optional[int] = None,
daily_limit: Optional[int] = None
) -> bool:
"""
说明:
说明:
更新商品信息
参数:
参数:
:param goods_name: 商品名称
:param goods_price: 商品价格
:param goods_description: 商品简介
:param goods_discount: 商品折扣
:param goods_limit_time: 商品限时时间
:param daily_limit: 每日次数限制
"""
try:
query = (
await cls.query.where(cls.goods_name == goods_name)
.with_for_update()
.gino.first()
.with_for_update()
.gino.first()
)
if not query:
return False
if goods_price:
await query.update(goods_price=goods_price).apply()
if goods_description:
await query.update(goods_description=goods_description).apply()
if goods_discount:
await query.update(goods_discount=goods_discount).apply()
if goods_limit_time:
await query.update(goods_limit_time=goods_limit_time).apply()
await query.update(
goods_price=goods_price or query.goods_price,
goods_description=goods_description or query.goods_description,
goods_discount=goods_discount or query.goods_discount,
goods_limit_time=goods_limit_time if goods_limit_time is not None else query.goods_limit_time,
daily_limit=daily_limit if daily_limit is not None else query.daily_limit,
).apply()
return True
except Exception as e:
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
return False
return False
@classmethod
async def get_goods_info(cls, goods_name: str) -> "GoodsInfo":
"""
说明:
说明:
获取商品对象
参数:
参数:
:param goods_name: 商品名称
"""
return await cls.query.where(cls.goods_name == goods_name).gino.first()
@@ -119,7 +127,7 @@ class GoodsInfo(db.Model):
@classmethod
async def get_all_goods(cls) -> List["GoodsInfo"]:
"""
说明:
说明:
获得全部有序商品对象
"""
query = await cls.query.gino.all()
@@ -130,3 +138,62 @@ class GoodsInfo(db.Model):
goods_lst.append([x for x in query if x.id == min_id][0])
id_lst.remove(min_id)
return goods_lst
@classmethod
async def add_user_daily_purchase(
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
):
"""
说明:
添加用户明日购买限制
参数:
:param goods: 商品
:param user_id: 用户id
:param group_id: 群号
:param num: 数量
"""
user_id = str(user_id)
group_id = str(group_id)
if goods and goods.daily_limit and goods.daily_limit > 0:
if not goods.daily_purchase_limit.get(group_id):
goods.daily_purchase_limit[group_id] = {}
if not goods.daily_purchase_limit[group_id].get(user_id):
goods.daily_purchase_limit[group_id][user_id] = 0
goods.daily_purchase_limit[group_id][user_id] += num
await goods.update(daily_purchase_limit=goods.daily_purchase_limit).apply()
@classmethod
async def check_user_daily_purchase(
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
) -> Tuple[bool, int]:
"""
说明:
检测用户每日购买上限
参数:
:param goods: 商品
:param user_id: 用户id
:param group_id: 群号
:param num: 数量
"""
user_id = str(user_id)
group_id = str(group_id)
if goods and goods.daily_limit > 0:
if (
not goods.daily_limit
or not goods.daily_purchase_limit.get(group_id)
or not goods.daily_purchase_limit[group_id].get(user_id)
):
return goods.daily_limit - num < 0, goods.daily_limit
if goods.daily_purchase_limit[group_id][user_id] + num > goods.daily_limit:
return (
True,
goods.daily_limit - goods.daily_purchase_limit[group_id][user_id],
)
return False, 0
@classmethod
async def reset_daily_purchase(cls):
"""
重置每次次数限制
"""
await cls.update.values(daily_purchase_limit={}).gino.status()
+7 -7
View File
@@ -17,9 +17,9 @@ class GroupInfo(db.Model):
@classmethod
async def get_group_info(cls, group_id: int) -> "GroupInfo":
"""
说明:
说明:
获取群信息
参数:
参数:
:param group_id: 群号
"""
query = cls.query.where(cls.group_id == group_id)
@@ -35,9 +35,9 @@ class GroupInfo(db.Model):
group_flag: Optional[int] = None,
) -> bool:
"""
说明:
说明:
添加群信息
参数:
参数:
:param group_id: 群号
:param group_name: 群名称
:param max_member_count: 群员最大数量
@@ -74,9 +74,9 @@ class GroupInfo(db.Model):
@classmethod
async def delete_group_info(cls, group_id: int):
"""
说明:
说明:
删除群信息
参数:
参数:
:param group_id: 群号
"""
await cls.delete.where(cls.group_id == group_id).gino.status()
@@ -84,7 +84,7 @@ class GroupInfo(db.Model):
@classmethod
async def get_all_group(cls) -> List["GroupInfo"]:
"""
说明:
说明:
获取所有群对象
"""
query = await cls.query.gino.all()
+14 -14
View File
@@ -27,9 +27,9 @@ class GroupInfoUser(db.Model):
uid: Optional[int] = None,
) -> bool:
"""
说明:
说明:
添加群内用户信息
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param user_name: 用户名称
@@ -57,9 +57,9 @@ class GroupInfoUser(db.Model):
cls, user_qq: int, group_id: int
) -> "GroupInfoUser":
"""
说明:
说明:
查询群员信息
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
@@ -71,9 +71,9 @@ class GroupInfoUser(db.Model):
@classmethod
async def delete_member_info(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
说明:
删除群员信息
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
@@ -96,9 +96,9 @@ class GroupInfoUser(db.Model):
@classmethod
async def get_group_member_id_list(cls, group_id: int) -> List[int]:
"""
说明:
说明:
获取该群所有用户qq
参数:
参数:
:param group_id: 群号
"""
member_list = []
@@ -112,9 +112,9 @@ class GroupInfoUser(db.Model):
cls, user_qq: int, group_id: int, nickname: str
) -> bool:
"""
说明:
说明:
设置群员在该群内的昵称
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param nickname: 昵称
@@ -131,9 +131,9 @@ class GroupInfoUser(db.Model):
@classmethod
async def get_user_all_group(cls, user_qq: int) -> List[int]:
"""
说明:
说明:
获取该用户所在的所有群聊
参数:
参数:
:param user_qq: 用户qq
"""
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
@@ -144,9 +144,9 @@ class GroupInfoUser(db.Model):
@classmethod
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
"""
说明:
说明:
获取用户在该群的昵称
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
+10 -10
View File
@@ -17,9 +17,9 @@ class LevelUser(db.Model):
@classmethod
async def get_user_level(cls, user_qq: int, group_id: int) -> int:
"""
说明:
说明:
获取用户在群内的等级
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
@@ -35,9 +35,9 @@ class LevelUser(db.Model):
cls, user_qq: int, group_id: int, level: int, group_flag: int = 0
) -> bool:
"""
说明:
说明:
设置用户在群内的权限
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param level: 权限等级
@@ -64,9 +64,9 @@ class LevelUser(db.Model):
@classmethod
async def delete_level(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
说明:
删除用户权限
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
@@ -82,9 +82,9 @@ class LevelUser(db.Model):
@classmethod
async def check_level(cls, user_qq: int, group_id: int, level: int) -> bool:
"""
说明:
说明:
检查用户权限等级是否大于 level
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param level: 权限等级
@@ -112,9 +112,9 @@ class LevelUser(db.Model):
@classmethod
async def is_group_flag(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
说明:
检测是否会被自动更新刷新权限
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
+2 -2
View File
@@ -80,9 +80,9 @@ class SignGroupUser(db.Model):
@classmethod
async def get_all_impression(cls, group_id: int) -> "list, list, list":
"""
说明:
说明:
获取该群所有用户 id 及对应 好感度
参数:
参数:
:param group_id: 群号
"""
impression_list = []
+31 -5
View File
@@ -1,6 +1,8 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from utils.message_builder import at
from .data_source import (
add_live_sub,
delete_sub,
@@ -50,7 +52,17 @@ __plugin_configs__ = {
"value": 5,
"help": "群内bilibili订阅需要管理的权限",
"default_value": 5,
}
},
"LIVE_MSG_AT_ALL": {
"value": False,
"help": "直播提醒是否AT全体(仅在真寻是管理员时生效)",
"default_value": False,
},
"UP_MSG_AT_ALL": {
"value": False,
"help": "UP动态投稿提醒是否AT全体(仅在真寻是管理员时生效)",
"default_value": False,
},
}
add_sub = on_command("添加订阅", priority=5, block=True)
@@ -228,13 +240,27 @@ async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
:param sub: BilibiliSub
:param bot: Bot
"""
temp_group = []
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)
)
if ":" in x and x.split(":")[1] not in temp_group:
group_id = int(x.split(":")[1])
temp_group.append(group_id)
if (
await bot.get_group_member_info(
group_id=group_id, user_id=int(bot.self_id), no_cache=True
)
)["role"] in ["owner", "admin"]:
if (
sub.sub_type == "live"
and Config.get_config("bilibili_sub", "LIVE_MSG_AT_ALL")
) or (
sub.sub_type == "up"
and Config.get_config("bilibili_sub", "UP_MSG_AT_ALL")
):
rst = "[CQ:at,qq=all]\n" + rst
await bot.send_group_msg(group_id=group_id, message=Message(rst))
else:
await bot.send_private_msg(user_id=int(x), message=Message(rst))
except Exception as e:
+37 -14
View File
@@ -1,6 +1,10 @@
from bilireq.exceptions import ResponseCodeError
from nonebot.adapters.onebot.v11 import MessageSegment
from utils.manager import resources_manager
from asyncio.exceptions import TimeoutError
from utils.utils import get_bot
from .model import BilibiliSub
from bilireq.live import get_room_info_by_id
from .utils import get_meta
@@ -8,7 +12,7 @@ from utils.message_builder import image
from bilireq.user import get_user_info
from bilireq import dynamic
from .utils import get_videos
from typing import Optional
from typing import Optional, Tuple
from configs.path_config import IMAGE_PATH
from datetime import datetime
from utils.browser import get_browser
@@ -227,6 +231,7 @@ async def _get_live_status(id_: int) -> Optional[str]:
await BilibiliSub.update_sub_info(id_, live_status=live_status)
if sub.live_status == 0 and live_status == 1:
return (
f""
f"{image(cover)}\n"
f"{sub.uname} 开播啦!\n"
f"标题:{title}\n"
@@ -251,14 +256,14 @@ async def _get_up_status(id_: int) -> Optional[str]:
video = None
if _user.uname != uname:
await BilibiliSub.update_sub_info(id_, uname=uname)
dynamic_img, dynamic_upload_time = await get_user_dynamic(id_, _user)
dynamic_img, dynamic_upload_time, link = await get_user_dynamic(id_, _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"
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n{link}"
if (
latest_video_created
and _user.latest_video_created
@@ -304,7 +309,7 @@ async def _get_season_status(id_) -> Optional[str]:
async def get_user_dynamic(
uid: int, local_user: BilibiliSub
) -> "Optional[MessageSegment], int":
) -> Tuple[Optional[MessageSegment], int, str]:
"""
获取用户动态
:param uid: 用户uid
@@ -316,33 +321,50 @@ async def get_user_dynamic(
browser = await get_browser()
if dynamic_info.get("cards") and browser:
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
dynamic_id = dynamic_info["cards"][0]["desc"]["dynamic_id"]
if local_user.dynamic_upload_time < dynamic_upload_time:
page = await browser.new_page()
context = await browser.new_context()
page = await context.new_page()
try:
await page.goto(
f"https://space.bilibili.com/{local_user.uid}/dynamic",
f"https://t.bilibili.com/{dynamic_id}",
wait_until="networkidle",
timeout=10000,
)
await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s
# await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s
# 删除置顶
# await page.evaluate(
# """
# xs = document.getElementsByClassName('bili-dyn-item__tag');
# for (x of xs) {
# x.parentNode.parentNode.remove();
# }
# """
# )
# async with page.expect_popup() as popup_info:
# await page.locator(".bili-rich-text__content").click()
# details_page = await popup_info.value
await page.set_viewport_size(
{"width": 2560, "height": 1080, "timeout": 10000 * 20}
)
await page.wait_for_selector(".panel-area")
await page.evaluate(
"""
xs = document.getElementsByClassName('bili-dyn-item__tag');
for (x of xs) {
x.parentNode.parentNode.remove();
}
xs = document.getElementById('internationalHeader');
xs.remove();
xs = document.getElementsByClassName('panel-area')
xs[0].remove();
"""
)
card = page.locator(".bili-dyn-list__item").first
card = page.locator(".detail-card")
await card.wait_for()
# 截图并保存
await card.screenshot(
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
)
except Exception as e:
logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
finally:
await context.close()
await page.close()
return (
image(
@@ -350,8 +372,9 @@ async def get_user_dynamic(
"bilibili_sub/dynamic",
),
dynamic_upload_time,
f"https://t.bilibili.com/{dynamic_id}"
)
return None, None
return None, 0, ''
class SubManager:
+9 -9
View File
@@ -47,9 +47,9 @@ class BilibiliSub(db.Model):
season_update_time: Optional[datetime] = None,
) -> bool:
"""
说明:
说明:
添加订阅
参数:
参数:
:param sub_id: 订阅名称,房间号,番剧号等
:param sub_type: 订阅类型
:param sub_user: 订阅此条目的用户
@@ -110,9 +110,9 @@ class BilibiliSub(db.Model):
@classmethod
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str) -> bool:
"""
说明:
说明:
删除订阅
参数:
参数:
:param sub_id: 订阅名称
:param sub_user: 删除此条目的用户
"""
@@ -140,9 +140,9 @@ class BilibiliSub(db.Model):
@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()
@@ -173,9 +173,9 @@ class BilibiliSub(db.Model):
season_update_time: Optional[datetime] = None,
) -> bool:
"""
说明:
说明:
更新订阅信息
参数:
参数:
:param sub_id: 订阅名称,房间号,番剧号等
:param live_short_id: 直接短 id
:param live_status: 主播开播状态
@@ -232,7 +232,7 @@ class BilibiliSub(db.Model):
cls,
) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]":
"""
说明:
说明:
分类获取所有数据
"""
live_data = []
+10 -10
View File
@@ -25,9 +25,9 @@ class BlackWord(db.Model):
punish_level: int,
):
"""
说明:
说明:
添加用户发送的敏感词
参数:
参数:
:param user_qq: 用户id
:param group_id: 群号
:param black_word: 黑名单词汇
@@ -52,9 +52,9 @@ class BlackWord(db.Model):
id_: Optional[int] = None,
) -> bool:
"""
说明:
说明:
设置处罚
参数:
参数:
:param user_qq: 用户id
:param punish: 处罚
:param black_word: 黑名单词汇
@@ -81,9 +81,9 @@ class BlackWord(db.Model):
cls, user_qq: int, days: int = 7, punish_level: Optional[int] = None
) -> int:
"""
说明:
说明:
获取用户规定周期内的犯事次数
参数:
参数:
:param user_qq: 用户qq
:param days: 周期天数
:param punish_level: 惩罚等级
@@ -101,9 +101,9 @@ class BlackWord(db.Model):
@classmethod
async def get_user_punish_level(cls, user_qq: int, days: int = 7) -> Optional[int]:
"""
说明:
说明:
获取用户最近一次的惩罚记录等级
参数:
参数:
:param user_qq: 用户qq
:param days: 周期天数
"""
@@ -125,9 +125,9 @@ class BlackWord(db.Model):
date_type: str = "=",
) -> List["BlackWord"]:
"""
说明:
说明:
通过指定条件查询数据
参数:
参数:
:param user_qq: 用户qq
:param group_id: 群号
:param date: 日期
+1 -1
View File
@@ -6,7 +6,7 @@ from configs.config import Config
from pathlib import Path
from services.log import logger
from models.ban_user import BanUser
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.adapters.onebot.v11 import ActionFailed
from models.group_member_info import GroupInfoUser
from utils.http_utils import AsyncHttpx
import random
+1 -1
View File
@@ -9,7 +9,7 @@ import platform
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
url = "http://www.eclzz.win"
url = "http://www.eclzz.zone/"
async def get_bt_info(keyword: str, page: int):
+10 -11
View File
@@ -5,7 +5,7 @@ from .data_source import check_update, get_latest_version_data
from services.log import logger
from utils.utils import scheduler, get_bot
from pathlib import Path
from configs.config import Config
from configs.config import NICKNAME, Config
from nonebot.rule import to_me
from nonebot.params import ArgStr
import platform
@@ -71,18 +71,17 @@ async def _(bot: Bot):
)
@restart.handle()
async def _():
if str(platform.system()).lower() == "windows":
await restart.finish("暂无windows重启脚本...")
@restart.got("flag", prompt="确定是否重启真寻?确定请回复[是|好|确定](重启失败咱们将失去联系,请谨慎!)")
@restart.got("flag", prompt=f"确定是否重启{NICKNAME}?确定请回复[是|好|确定](重启失败咱们将失去联系,请谨慎!)")
async def _(flag: str = ArgStr("flag")):
if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
await restart.send("开始重启真寻..请稍等...")
await restart.send(f"开始重启{NICKNAME}..请稍等...")
open("is_restart", "w")
os.system("./restart.sh")
if str(platform.system()).lower() == "windows":
import sys
python = sys.executable
os.execl(python, python, *sys.argv)
else:
os.system("./restart.sh")
else:
await restart.send("已取消操作...")
@@ -126,5 +125,5 @@ async def _():
if code == 200:
await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]),
message=f"更新完毕,请重启真寻....",
message=f"更新完毕,请重启{NICKNAME}....",
)
+2 -2
View File
@@ -162,7 +162,7 @@ def _file_handle(latest_version: str) -> str:
if backup_file.exists():
backup_file.unlink()
if file not in [config_file, config_path_file]:
os.rename(file.absolute(), backup_file.absolute())
shutil.move(file.absolute(), backup_file.absolute())
else:
with open(file, "r", encoding="utf8") as rf:
data = rf.read()
@@ -174,7 +174,7 @@ def _file_handle(latest_version: str) -> str:
old_file = Path() / file
if old_file not in [config_file, config_path_file] and file != "configs":
if not old_file.exists() and new_file.exists():
os.rename(new_file.absolute(), old_file.absolute())
shutil.move(new_file.absolute(), old_file.absolute())
logger.info(f"已更新文件:{file}")
# except Exception as e:
# error = f'{type(e)}:{e}'
+20 -13
View File
@@ -1,4 +1,7 @@
from typing import Tuple, Any
from nonebot import on_regex
from nonebot.params import RegexGroup
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
from utils.message_builder import image
@@ -11,7 +14,9 @@ __plugin_usage__ = """
usage:
三次元也不戳,嘿嘿嘿
指令:
cos/coser
?N连cos/coser
示例:cos
示例:5连cos (单次请求张数小于9)
""".strip()
__plugin_des__ = "三次元也不戳,嘿嘿嘿"
__plugin_cmd__ = ["cos/coser"]
@@ -31,21 +36,23 @@ __plugin_configs__ = {
},
}
coser = on_regex("^(cos|COS|coser|括丝)$", priority=5, block=True)
coser = on_regex(r"^(\d)连?(cos|COS|coser|括丝)$", priority=5, block=True)
url = "https://api.iyk0.com/cos"
@coser.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
try:
msg_id = await coser.send(image(url))
withdraw_message_manager.withdraw_message(
event,
msg_id["message_id"],
Config.get_config("coser", "WITHDRAW_COS_MESSAGE"),
)
except Exception as e:
await coser.send("你cos给我看!")
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
async def _(bot: Bot, event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
num = reg_group[0] or 1
for _ in range(int(num)):
try:
msg_id = await coser.send(image(url))
withdraw_message_manager.withdraw_message(
event,
msg_id["message_id"],
Config.get_config("coser", "WITHDRAW_COS_MESSAGE"),
)
except Exception as e:
await coser.send("你cos给我看!")
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
+1 -1
View File
@@ -30,7 +30,7 @@ class Map:
ratio: float = 1,
):
"""
参数:
参数:
:param resource_name: 资源名称
:param center_point: 中心点
:param deviation: 坐标误差
+46 -46
View File
@@ -25,9 +25,9 @@ class Genshin(db.Model):
@classmethod
async def add_uid(cls, user_qq: int, uid: int):
"""
说明:
说明:
添加一个uid
参数:
参数:
:param user_qq: 用户qq
:param uid: 原神uid
"""
@@ -44,9 +44,9 @@ class Genshin(db.Model):
@classmethod
async def set_mys_id(cls, uid: int, mys_id: int) -> bool:
"""
说明:
说明:
设置米游社id
参数:
参数:
:param uid: 原神uid
:param mys_id: 米游社id
"""
@@ -60,9 +60,9 @@ class Genshin(db.Model):
@classmethod
async def set_bind_group(cls, uid: int, bind_group) -> bool:
"""
说明:
说明:
绑定group_id,除私聊外的提醒将在此群发送
参数:
参数:
:param uid: uid
:param bind_group: 群号
"""
@@ -76,9 +76,9 @@ class Genshin(db.Model):
@classmethod
async def get_bind_group(cls, uid: int) -> Optional[int]:
"""
说明:
说明:
获取用户绑定的群聊
参数:
参数:
:param uid: uid
"""
user = await cls.query.where(cls.uid == uid).gino.first()
@@ -89,9 +89,9 @@ class Genshin(db.Model):
@classmethod
async def set_cookie(cls, uid: int, cookie: str) -> bool:
"""
说明:
说明:
设置cookie
参数:
参数:
:param uid: 原神uid
:param cookie: 米游社id
"""
@@ -105,9 +105,9 @@ class Genshin(db.Model):
@classmethod
async def set_resin_remind(cls, uid: int, flag: bool) -> bool:
"""
说明:
说明:
设置体力提醒
参数:
参数:
:param uid: 原神uid
:param flag: 开关状态
"""
@@ -121,9 +121,9 @@ class Genshin(db.Model):
@classmethod
async def set_user_resin_recovery_time(cls, uid: int, date: datetime):
"""
说明:
说明:
设置体力完成时间
参数:
参数:
:param uid: uid
:param date: 提醒日期
"""
@@ -134,9 +134,9 @@ class Genshin(db.Model):
@classmethod
async def get_user_resin_recovery_time(cls, uid: int) -> Optional[datetime]:
"""
说明:
说明:
获取体力完成时间
参数:
参数:
:param uid: uid
"""
u = await cls.query.where(cls.uid == uid).gino.first()
@@ -147,7 +147,7 @@ class Genshin(db.Model):
@classmethod
async def get_all_resin_remind_user(cls) -> List["Genshin"]:
"""
说明:
说明:
获取所有开启体力提醒的用户
"""
return await cls.query.where(cls.resin_remind == True).gino.all()
@@ -155,9 +155,9 @@ class Genshin(db.Model):
@classmethod
async def clear_resin_remind_time(cls, uid: int) -> bool:
"""
说明:
说明:
清空提醒日期
参数:
参数:
:param uid: uid
"""
user = await cls.query.where(cls.uid == uid).gino.first()
@@ -169,9 +169,9 @@ class Genshin(db.Model):
@classmethod
async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
"""
说明:
说明:
设置米游社/原神自动签到
参数:
参数:
:param uid: 原神uid
:param flag: 开关状态
"""
@@ -185,7 +185,7 @@ class Genshin(db.Model):
@classmethod
async def get_all_auto_sign_user(cls) -> List["Genshin"]:
"""
说明:
说明:
获取所有开启自动签到的用户
"""
return await cls.query.where(cls.auto_sign == True).gino.all()
@@ -193,7 +193,7 @@ class Genshin(db.Model):
@classmethod
async def get_all_sign_user(cls) -> List["Genshin"]:
"""
说明:
说明:
获取 原神 所有今日签到用户
"""
return await cls.query.where(cls.auto_sign_time != None).gino.all()
@@ -201,9 +201,9 @@ class Genshin(db.Model):
@classmethod
async def clear_sign_time(cls, uid: int) -> bool:
"""
说明:
说明:
清空签到日期
参数:
参数:
:param uid: uid
"""
user = await cls.query.where(cls.uid == uid).gino.first()
@@ -215,9 +215,9 @@ class Genshin(db.Model):
@classmethod
async def random_sign_time(cls, uid: int) -> Optional[datetime]:
"""
说明:
说明:
随机签到时间
说明:
说明:
:param uid: uid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
@@ -245,9 +245,9 @@ class Genshin(db.Model):
@classmethod
async def get_query_cookie(cls, uid: int) -> Optional[str]:
"""
说明:
说明:
获取查询角色信息cookie
参数:
参数:
:param uid: 原神uid
"""
# 查找用户今日是否已经查找过,防止重复
@@ -265,9 +265,9 @@ class Genshin(db.Model):
@classmethod
async def get_user_cookie(cls, uid: int, flag: bool = False) -> Optional[str]:
"""
说明:
说明:
获取用户cookie
参数:
参数:
:param uid:原神uid
:param flag:必须使用自己的cookie
"""
@@ -279,9 +279,9 @@ class Genshin(db.Model):
@classmethod
async def get_user_by_qq(cls, user_qq: int) -> Optional["Genshin"]:
"""
说明:
说明:
通过qq获取用户对象
参数:
参数:
:param user_qq: qq
"""
return await cls.query.where(cls.user_qq == user_qq).gino.first()
@@ -289,9 +289,9 @@ class Genshin(db.Model):
@classmethod
async def get_user_by_uid(cls, uid: int) -> Optional["Genshin"]:
"""
说明:
说明:
通过uid获取用户对象
参数:
参数:
:param uid: qq
"""
return await cls.query.where(cls.uid == uid).gino.first()
@@ -299,9 +299,9 @@ class Genshin(db.Model):
@classmethod
async def get_user_uid(cls, user_qq: int) -> Optional[int]:
"""
说明:
说明:
获取用户uid
参数:
参数:
:param user_qq:用户qq
"""
return await cls._get_user_data(user_qq, None, "uid")
@@ -311,7 +311,7 @@ class Genshin(db.Model):
"""
说嘛:
获取用户米游社id
参数:
参数:
:param uid:原神id
"""
return await cls._get_user_data(None, uid, "mys_id")
@@ -319,9 +319,9 @@ class Genshin(db.Model):
@classmethod
async def delete_user_cookie(cls, uid: int):
"""
说明:
说明:
删除用户cookie
参数:
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
@@ -332,9 +332,9 @@ class Genshin(db.Model):
@classmethod
async def delete_user(cls, user_qq: int):
"""
说明:
说明:
删除用户数据
参数:
参数:
:param user_qq: 用户qq
"""
query = cls.query.where(cls.user_qq == user_qq).with_for_update()
@@ -347,9 +347,9 @@ class Genshin(db.Model):
@classmethod
async def _add_query_uid(cls, uid: int, cookie_uid: int):
"""
说明:
说明:
添加每日查询重复uid的cookie
参数:
参数:
:param uid: 原神uid
:param cookie_uid: cookie的uid
"""
@@ -362,9 +362,9 @@ class Genshin(db.Model):
cls, user_qq: Optional[int], uid: Optional[int], type_: str
) -> Optional[Union[int, str]]:
"""
说明:
说明:
获取用户数据
参数:
参数:
:param user_qq: 用户qq
:param uid: uid
:param type_: 数据类型
@@ -149,12 +149,12 @@ async def _remind(user_id: int, uid: str):
if current_resin < max_resin:
user_manager.remove(uid)
user_manager.remove_overflow(uid)
if current_resin <= max_resin - 40:
next_time = now + timedelta(minutes=(max_resin - 40 - current_resin + 1) * 8, seconds=10)
elif max_resin - 40 < current_resin <= max_resin - 20:
next_time = now + timedelta(minutes=(max_resin - 20 - current_resin + 1) * 8, seconds=10)
elif max_resin - 20 < current_resin < max_resin:
next_time = now + timedelta(minutes=(max_resin - current_resin) * 8, seconds=10)
if current_resin < max_resin - 40:
next_time = now + timedelta(minutes=(max_resin - 40 - current_resin) * 8)
elif max_resin - 40 <= current_resin < max_resin - 20:
next_time = now + timedelta(minutes=(max_resin - 20 - current_resin) * 8)
elif max_resin - 20 <= current_resin < max_resin:
next_time = now + timedelta(minutes=(max_resin - current_resin) * 8)
elif current_resin == max_resin:
custom_overflow_resin = Config.get_config("resin_remind", "CUSTOM_RESIN_OVERFLOW_REMIND")
if user_manager.is_overflow(uid) and custom_overflow_resin:
+1 -1
View File
@@ -1,6 +1,7 @@
from nonebot import on_command, on_notice
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
GroupMessageEvent,
PokeNotifyEvent,
Message
@@ -24,7 +25,6 @@ from nonebot.rule import to_me
from datetime import datetime, timedelta
from configs.config import NICKNAME
from apscheduler.jobstores.base import JobLookupError
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.params import CommandArg
import random
import time
+6 -6
View File
@@ -18,9 +18,9 @@ class RedbagUser(db.Model):
@classmethod
async def add_redbag_data(cls, user_qq: int, group_id: int, itype: str, money: int):
"""
说明:
说明:
添加收发红包数据
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param itype: 收或发
@@ -45,9 +45,9 @@ class RedbagUser(db.Model):
@classmethod
async def ensure(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
说明:
获取用户对象
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
@@ -61,9 +61,9 @@ class RedbagUser(db.Model):
@classmethod
async def get_user_all(cls, group_id: int = None) -> List["RedbagUser"]:
"""
说明:
说明:
获取所有用户对象
参数:
参数:
:param group_id: 群号
"""
if not group_id:
@@ -65,8 +65,8 @@ async def arg_handle(
if int(img_id) > max_id or int(img_id) < 0:
await delete_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True)
try:
if (TEMP_PATH / "delete.jpg").exists():
(TEMP_PATH / "delete.jpg").unlink()
if (TEMP_PATH / f"{event.user_id}_delete.jpg").exists():
(TEMP_PATH / f"{event.user_id}_delete.jpg").unlink()
logger.info(f"删除{cn2py(state['path'])}图片 {img_id}.jpg 成功")
except Exception as e:
logger.warning(f"删除图片 delete.jpg 失败 e{e}")
+14 -11
View File
@@ -1,8 +1,7 @@
from nonebot import on_message, on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, ActionFailed
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.utils import is_number, get_message_img, get_message_text
from nonebot.adapters.onebot.v11.exception import ActionFailed
from configs.path_config import DATA_PATH, TEMP_PATH
from utils.image_utils import get_img_hash
from services.log import logger
@@ -72,9 +71,7 @@ def save_data():
async def download_img_and_hash(url, group_id) -> str:
if await AsyncHttpx.download_file(
url, TEMP_PATH / f"mute_{group_id}_img.jpg"
):
if await AsyncHttpx.download_file(url, TEMP_PATH / f"mute_{group_id}_img.jpg"):
return str(get_img_hash(TEMP_PATH / f"mute_{group_id}_img.jpg"))
return ""
@@ -133,11 +130,19 @@ async def _(bot: Bot, event: GroupMessageEvent):
@mute_setting.handle()
async def _(event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
async def _(
event: GroupMessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
):
global mute_data
group_id = str(event.group_id)
if not mute_data.get(group_id):
mute_data[group_id] = {"count": Config.get_config("mute", "MUTE_DEFAULT_COUNT"), "time": Config.get_config("mute", "MUTE_DEFAULT_TIME"), "duration": Config.get_config("mute", "MUTE_DEFAULT_DURATION")}
mute_data[group_id] = {
"count": Config.get_config("mute", "MUTE_DEFAULT_COUNT"),
"time": Config.get_config("mute", "MUTE_DEFAULT_TIME"),
"duration": Config.get_config("mute", "MUTE_DEFAULT_DURATION"),
}
msg = arg.extract_plain_text().strip()
if cmd[0] == "刷屏检测设置":
await mute_setting.finish(
@@ -157,8 +162,6 @@ async def _(event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Mes
if cmd[0] == "设置刷屏禁言时长":
mute_data[group_id]["duration"] = int(msg)
msg += " 分钟"
await mute_setting.send(f'刷屏检测:{cmd[0]}为 {msg}')
logger.info(
f'USER {event.user_id} GROUP {group_id} {cmd[0]}:{msg}'
)
await mute_setting.send(f"刷屏检测:{cmd[0]}为 {msg}")
logger.info(f"USER {event.user_id} GROUP {group_id} {cmd[0]}:{msg}")
save_data()
+1 -1
View File
@@ -31,7 +31,7 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
async with db.transaction():
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
# 一天次数上限
if user.today_open_total == int(
if user.today_open_total > int(
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ int(impression)
/ Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
+1 -1
View File
@@ -7,7 +7,7 @@ from .models.open_cases_user import OpenCasesUser
from services.log import logger
from utils.utils import get_bot, cn2py
from asyncio.exceptions import TimeoutError
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import Config
from utils.manager import group_manager
from .config import *
+163 -166
View File
@@ -1,166 +1,163 @@
# from nonebot import on_message
# from services.log import logger
# from nonebot.adapters.onebot.v11 import GroupMessageEvent
# from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
# from nonebot.adapters.onebot.v11.permission import GROUP
# from utils.message_builder import image
# from nonebot.adapters.onebot.v11.exception import ActionFailed
# from utils.image_utils import BuildImage
# from utils.browser import get_browser
# from configs.path_config import IMAGE_PATH
# from utils.http_utils import AsyncHttpx
# from configs.config import Config
# from utils.user_agent import get_user_agent
# import aiohttp
# import asyncio
# import time
# import ujson as json
#
#
# __zx_plugin_name__ = "B站转发解析"
# __plugin_usage__ = """
# usage:
# B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
# """.strip()
# __plugin_des__ = "B站转发解析"
# __plugin_type__ = ("其他",)
# __plugin_version__ = 0.1
# __plugin_author__ = "HibiKier"
# __plugin_task__ = {"bilibili_parse": "b站转发解析"}
# Config.add_plugin_config(
# "_task",
# "DEFAULT_BILIBILI_PARSE",
# True,
# help_="被动 B站转发解析 进群默认开关状态",
# default_value=True,
# )
#
#
# parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
#
# _tmp = {}
#
#
# @parse_bilibili_json.handle()
# async def _(event: GroupMessageEvent):
# vd_info = None
# url = None
# if get_message_json(event.json()):
# try:
# data = json.loads(get_message_json(event.json())[0]["data"])
# except (IndexError, KeyError):
# data = None
# if data:
# # 转发视频
# if data.get("desc") == "哔哩哔哩":
# async with aiohttp.ClientSession(
# headers=get_user_agent()
# ) as session:
# async with session.get(
# data["meta"]["detail_1"]["qqdocurl"],
# proxy=get_local_proxy(),
# timeout=7,
# ) as response:
# url = str(response.url).split("?")[0]
# bvid = url.split("/")[-1]
# vd_info = await video.Video(bvid=bvid).get_info()
# # response = await AsyncHttpx.get(
# # data["meta"]["detail_1"]["qqdocurl"], timeout=7
# # )
# # url = str(response.url).split("?")[0]
# # bvid = url.split("/")[-1]
# # vd_info = await video.Video(bvid=bvid).get_info()
# # 转发专栏
# if (
# data.get("meta")
# and data["meta"].get("news")
# and data["meta"]["news"].get("desc") == "哔哩哔哩专栏"
# ):
# url = data["meta"]["news"]["jumpUrl"]
# page = None
# try:
# browser = await get_browser()
# if not browser:
# return
# page = await browser.new_page(
# user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
# " (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36"
# )
# await page.goto(url, wait_until="networkidle", timeout=10000)
# await page.set_viewport_size({"width": 2560, "height": 1080})
# await page.click("#app > div")
# div = await page.query_selector("#app > div")
# await div.screenshot(
# path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
# timeout=100000,
# )
# await asyncio.get_event_loop().run_in_executor(
# None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
# )
# await parse_bilibili_json.send(
# "[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
# )
# await page.close()
# logger.info(
# f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
# )
# except Exception as e:
# logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}")
# if page:
# await page.close()
# return
# # BV
# if msg := get_message_text(event.json()):
# 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]
# res = await AsyncHttpx.get(url, timeout=7)
# url = str(res.url).split("?")[0]
# bvid = url.split("/")[-1]
# vd_info = await video.Video(bvid=bvid).get_info()
# if vd_info:
# 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(
# "[[_task|bilibili_parse]]" +
# image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
# f"UP:{author}\n"
# f"上传日期:{date}\n"
# f"回复:{reply},收藏:{favorite},投币:{coin}\n"
# 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):
# A = BuildImage(0, 0, background=path, ratio=0.5)
# A.save(path)
from nonebot import on_message
from services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent, ActionFailed
from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.message_builder import image
from utils.image_utils import BuildImage
from utils.browser import get_browser
from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx
from configs.config import Config
from utils.user_agent import get_user_agent
import aiohttp
import asyncio
import time
import ujson as json
from bilireq import video
__zx_plugin_name__ = "B站转发解析"
__plugin_usage__ = """
usage:
B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
""".strip()
__plugin_des__ = "B站转发解析"
__plugin_type__ = ("其他",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"bilibili_parse": "b站转发解析"}
Config.add_plugin_config(
"_task",
"DEFAULT_BILIBILI_PARSE",
True,
help_="被动 B站转发解析 进群默认开关状态",
default_value=True,
)
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
_tmp = {}
@parse_bilibili_json.handle()
async def _(event: GroupMessageEvent):
vd_info = None
url = None
if get_message_json(event.json()):
try:
data = json.loads(get_message_json(event.json())[0]["data"])
except (IndexError, KeyError):
data = None
if data:
# 转发视频
if data.get("desc") == "哔哩哔哩":
async with aiohttp.ClientSession(
headers=get_user_agent()
) as session:
async with session.get(
data["meta"]["detail_1"]["qqdocurl"],
timeout=7,
) as response:
url = str(response.url).split("?")[0]
bvid = url.split("/")[-1]
vd_info = await video.get_video_base_info(bvid)
# 转发专栏
if (
data.get("meta")
and data["meta"].get("news")
and data["meta"]["news"].get("desc") == "哔哩哔哩专栏"
):
url = data["meta"]["news"]["jumpUrl"]
page = None
try:
browser = await get_browser()
if not browser:
return
page = await browser.new_page(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
" (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36"
)
await page.goto(url, wait_until="networkidle", timeout=10000)
await page.set_viewport_size({"width": 2560, "height": 1080})
await page.click("#app > div")
div = await page.query_selector("#app > div")
await div.screenshot(
path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
timeout=100000,
)
await asyncio.get_event_loop().run_in_executor(
None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
)
await parse_bilibili_json.send(
"[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
)
await page.close()
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
)
except Exception as e:
logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}")
if page:
await page.close()
return
# BV
if msg := get_message_text(event.json()):
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.get_video_base_info(msg)
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.get_video_base_info(msg)
elif "https://b23.tv" in msg:
url = "https://" + msg[msg.find("b23.tv"): msg.find("b23.tv") + 14]
async with aiohttp.ClientSession(
headers=get_user_agent()
) as session:
async with session.get(
url,
timeout=7,
) as response:
url = str(response.url).split("?")[0]
bvid = url.split("/")[-1]
vd_info = await video.get_video_base_info(bvid)
if vd_info:
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(
"[[_task|bilibili_parse]]" +
image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
f"UP:{author}\n"
f"上传日期:{date}\n"
f"回复:{reply},收藏:{favorite},投币:{coin}\n"
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):
A = BuildImage(0, 0, background=path, ratio=0.5)
A.save(path)
+2 -1
View File
@@ -4,7 +4,7 @@ from asyncio.locks import Semaphore
from asyncio.exceptions import TimeoutError
from ._model.pixiv import Pixiv
from typing import List, Optional
from utils.utils import change_pixiv_image_links
from utils.utils import change_pixiv_image_links, change_img_md5
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
from services.log import logger
@@ -238,6 +238,7 @@ async def get_image(img_url: str, user_id: int) -> Optional[str]:
TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg", "wb"
) as f:
await f.write(response.content)
change_img_md5(TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg")
return TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg"
except TimeoutError:
logger.warning(f"PIX:{img_url} 图片下载超时...")
@@ -38,9 +38,9 @@ class OmegaPixivIllusts(db.Model):
updated_at: datetime,
):
"""
说明:
说明:
添加图片信息
参数:
参数:
:param pid: pid
:param title: 标题
:param width: 宽度
@@ -78,9 +78,9 @@ class OmegaPixivIllusts(db.Model):
num: int = 100
) -> List[Optional["OmegaPixivIllusts"]]:
"""
说明:
说明:
查找符合条件的图片
参数:
参数:
:param keywords: 关键词
:param uid: 画师uid
:param pid: 图片pid
@@ -104,9 +104,9 @@ class OmegaPixivIllusts(db.Model):
@classmethod
async def check_exists(cls, pid: int) -> bool:
"""
说明:
说明:
检测pid是否已存在
参数:
参数:
:param pid: 图片PID
"""
query = await cls.query.where(cls.pid == pid).gino.all()
@@ -115,9 +115,9 @@ class OmegaPixivIllusts(db.Model):
@classmethod
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int, int":
"""
说明:
说明:
获取相关关键词(keyword, tag)在图库中的数量
参数:
参数:
:param tags: 关键词/Tag
"""
setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count'))
@@ -133,7 +133,7 @@ class OmegaPixivIllusts(db.Model):
@classmethod
async def get_all_pid(cls) -> List[int]:
"""
说明:
说明:
获取所有图片PID
"""
data = await cls.select('pid').gino.all()
+11 -11
View File
@@ -38,9 +38,9 @@ class Pixiv(db.Model):
tags: str,
):
"""
说明:
说明:
添加图片信息
参数:
参数:
:param pid: pid
:param title: 标题
:param width: 宽度
@@ -74,9 +74,9 @@ class Pixiv(db.Model):
@classmethod
async def remove_image_data(cls, pid: int, img_p: str) -> bool:
"""
说明:
说明:
删除图片数据
参数:
参数:
:param pid: 图片pid
:param img_p: 图片pid的张数,如:p0,p1
"""
@@ -94,7 +94,7 @@ class Pixiv(db.Model):
@classmethod
async def get_all_pid(cls) -> List[int]:
"""
说明:
说明:
获取所有PID
"""
query = await cls.query.select("pid").gino.first()
@@ -112,9 +112,9 @@ class Pixiv(db.Model):
num: int = 100
) -> List[Optional["Pixiv"]]:
"""
说明:
说明:
查找符合条件的图片
参数:
参数:
:param keywords: 关键词
:param uid: 画师uid
:param pid: 图片pid
@@ -140,9 +140,9 @@ class Pixiv(db.Model):
@classmethod
async def check_exists(cls, pid: int, img_p: str) -> bool:
"""
说明:
说明:
检测pid是否已存在
参数:
参数:
:param pid: 图片PID
:param img_p: 张数
"""
@@ -154,9 +154,9 @@ class Pixiv(db.Model):
@classmethod
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int":
"""
说明:
说明:
获取相关关键词(keyword, tag)在图库中的数量
参数:
参数:
:param tags: 关键词/Tag
"""
setattr(Pixiv, 'count', db.func.count(cls.pid).label('count'))
@@ -19,9 +19,9 @@ class PixivKeywordUser(db.Model):
cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str]
) -> bool:
"""
说明:
说明:
添加搜图的关键词
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param keyword: 关键词
@@ -38,9 +38,9 @@ class PixivKeywordUser(db.Model):
@classmethod
async def delete_keyword(cls, keyword: str) -> bool:
"""
说明:
说明:
删除关键词
参数:
参数:
:param keyword: 关键词
"""
if await cls._check_keyword_exists(keyword):
@@ -53,9 +53,9 @@ class PixivKeywordUser(db.Model):
@classmethod
async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int":
"""
说明:
说明:
通过或禁用关键词
参数:
参数:
:param keyword: 关键词
:param is_pass: 通过状态
"""
@@ -71,7 +71,7 @@ class PixivKeywordUser(db.Model):
@classmethod
async def get_all_user_dict(cls) -> dict:
"""
说明:
说明:
获取关键词数据库各个用户贡献的关键词字典
"""
tmp = {}
@@ -85,7 +85,7 @@ class PixivKeywordUser(db.Model):
@classmethod
async def get_current_keyword(cls) -> "List[str], List[str]":
"""
说明:
说明:
获取当前通过与未通过的关键词
"""
pass_keyword = []
@@ -101,7 +101,7 @@ class PixivKeywordUser(db.Model):
@classmethod
async def get_black_pid(cls) -> List[str]:
"""
说明:
说明:
获取黑名单PID
"""
black_pid = []
@@ -113,9 +113,9 @@ class PixivKeywordUser(db.Model):
@classmethod
async def _check_keyword_exists(cls, keyword: str) -> bool:
"""
说明:
说明:
检测关键词是否已存在
参数:
参数:
:param keyword: 关键词
"""
current_keyword = []
+12 -3
View File
@@ -20,6 +20,11 @@ usage:
pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取
pid [uid]: 通过uid获取图片
pix pid[pid]: 查看图库中指定pid图片
示例:pix 萝莉 白丝
示例:pix 萝莉 白丝 10 (10为数量)
示例:pix #02 (当tag只有1个tag且为数字时,使用#标记,否则将被判定为数量)
示例:pix 34582394 (查询指定uid图片)
示例:pix pid:12323423 (查询指定pid图片)
""".strip()
__plugin_superuser_usage__ = """
usage:
@@ -88,9 +93,12 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
nsfw_tag == 2 and not Config.get_config("pix", "ALLOW_GROUP_R18")
):
await pix.finish("你不能看这些噢,这些都是是留给管理员看的...")
if n := len(x) == 1 and is_number(x[0]) and int(x[0]) < 100:
num = int(x[0])
keyword = ""
if (n := len(x)) == 1:
if is_number(x[0]) and int(x[0]) < 100:
num = int(x[0])
keyword = ""
elif x[0].startswith("#"):
keyword = x[0][1:]
elif n > 1:
if is_number(x[-1]):
num = int(x[-1])
@@ -124,6 +132,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
all_image = await OmegaPixivIllusts.query_images(
pid=int(pid), nsfw_tag=nsfw_tag
)
num = len(all_image)
else:
tmp = await Pixiv.query_images(
x, r18=1 if nsfw_tag == 2 else 0, num=pix_num
+1 -1
View File
@@ -184,7 +184,7 @@ async def _():
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
omega_pixiv_illusts = None
for file in os.listdir("."):
if "omega_pixiv_illusts" in file and ".sql" in file:
if "omega_pixiv_artwork" 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:
+2 -3
View File
@@ -1,11 +1,10 @@
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message, NetworkError
from nonebot.matcher import Matcher
from nonebot.params import CommandArg
from nonebot import on_command
from utils.utils import is_number
from .data_source import get_pixiv_urls, download_pixiv_imgs, search_pixiv_urls
from services.log import logger
from nonebot.adapters.onebot.v11.exception import NetworkError
from asyncio.exceptions import TimeoutError
from utils.message_builder import custom_forward_msg
from configs.config import Config
@@ -18,7 +17,7 @@ __zx_plugin_name__ = "P站排行/搜图"
__plugin_usage__ = """
usage:
P站排行:
可选参数:
可选参数:
类型:
1. 日排行
2. 周排行
+2
View File
@@ -1,5 +1,6 @@
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from utils.utils import change_img_md5
from asyncio.exceptions import TimeoutError
from configs.config import Config
from utils.http_utils import AsyncHttpx
@@ -143,6 +144,7 @@ async def download_pixiv_imgs(
file,
timeout=Config.get_config("pixiv_rank_search", "TIMEOUT"),
):
change_img_md5(file)
if forward_msg_index is not None:
result += image(
f"{user_id}_{forward_msg_index}_{index}_pixiv.jpg",
+8 -8
View File
@@ -23,9 +23,9 @@ class RussianUser(db.Model):
@classmethod
async def ensure(cls, user_qq: int, group_id: int) -> "RussianUser":
"""
说明:
说明:
获取用户对象
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
"""
@@ -39,9 +39,9 @@ class RussianUser(db.Model):
@classmethod
async def add_count(cls, user_qq: int, group_id: int, itype: str) -> bool:
"""
说明:
说明:
添加用户输赢次数
说明:
说明:
:param user_qq: qq号
:param group_id: 群号
:param itype: 输或赢 'win' or 'lose'
@@ -87,9 +87,9 @@ class RussianUser(db.Model):
@classmethod
async def money(cls, user_qq: int, group_id: int, itype: str, count: int) -> bool:
"""
说明:
说明:
添加用户输赢金钱
参数:
参数:
:param user_qq: qq号
:param group_id: 群号
:param itype: 输或赢 'win' or 'lose'
@@ -120,9 +120,9 @@ class RussianUser(db.Model):
@classmethod
async def get_all_user(cls, group_id: int) -> List["RussianUser"]:
"""
说明:
说明:
获取该群所有用户对象
参数:
参数:
:param group_id: 群号
"""
users = await cls.query.where((cls.group_id == group_id)).gino.all()
+15 -8
View File
@@ -1,3 +1,4 @@
from services import logger
from utils.http_utils import AsyncHttpx
from configs.config import Config
from configs.path_config import TEMP_PATH
@@ -39,12 +40,18 @@ async def get_saucenao_image(url: str) -> Union[str, List[str]]:
):
msg_list.append(image(TEMP_PATH / f"saucenao_search_{index}.jpg"))
for info in data:
similarity = info["header"]["similarity"]
tmp = f"相似度:{similarity}%\n"
for x in info["data"].keys():
if x != "ext_urls":
tmp += f"{x}:{info['data'][x]}\n"
if "source" not in info["data"].keys():
tmp += f'source:{info["data"]["ext_urls"][0]}\n'
msg_list.append(tmp[:-1])
try:
similarity = info["header"]["similarity"]
tmp = f"相似度:{similarity}%\n"
for x in info["data"].keys():
if x != "ext_urls":
tmp += f"{x}:{info['data'][x]}\n"
try:
if "source" not in info["data"].keys():
tmp += f'source:{info["data"]["ext_urls"][0]}\n'
except KeyError:
tmp += f'source:{info["header"]["thumbnail"]}\n'
msg_list.append(tmp[:-1])
except Exception as e:
logger.warning(f"识图获取图片信息发生错误 {type(e)}:{e}")
return msg_list
+14 -14
View File
@@ -30,9 +30,9 @@ class Setu(db.Model):
tags: str,
):
"""
说明:
说明:
添加一份色图数据
参数:
参数:
:param local_id: 本地存储id
:param title: 标题
:param author: 作者
@@ -62,9 +62,9 @@ class Setu(db.Model):
limit: int = 50,
):
"""
说明:
说明:
通过tag查找色图
参数:
参数:
:param local_id: 本地色图 id
:param tags: tags
:param r18: 是否 r18,0:非r18 1:r18 2:混合
@@ -90,7 +90,7 @@ class Setu(db.Model):
@classmethod
async def get_image_count(cls, r18: int = 0) -> int:
"""
说明:
说明:
查询图片数量
"""
flag = False if r18 == 0 else True
@@ -101,9 +101,9 @@ class Setu(db.Model):
@classmethod
async def get_image_in_hash(cls, img_hash: str) -> "Setu":
"""
说明:
说明:
通过图像hash获取图像信息
参数:
参数:
:param img_hash: = 图像hash值
"""
query = await cls.query.where(cls.img_hash == img_hash).gino.first()
@@ -112,9 +112,9 @@ class Setu(db.Model):
@classmethod
async def _check_exists(cls, pid: int, img_url: str) -> bool:
"""
说明:
说明:
检测图片是否存在
参数:
参数:
:param pid: 图片pid
:param img_url: 图片链接
"""
@@ -127,9 +127,9 @@ class Setu(db.Model):
@classmethod
async def delete_image(cls, pid: int) -> int:
"""
说明:
说明:
删除图片并替换
参数:
参数:
:param pid: 图片pid
"""
query = await cls.query.where(cls.pid == pid).gino.first()
@@ -157,9 +157,9 @@ class Setu(db.Model):
tags: Optional[str] = None,
) -> bool:
"""
说明:
说明:
根据PID修改图片数据
参数:
参数:
:param local_id: 本地id
:param pid: 图片pid
:param title: 标题
@@ -190,7 +190,7 @@ class Setu(db.Model):
@classmethod
async def get_all_setu(cls) -> List["Setu"]:
"""
说明:
说明:
获取所有图片对象
"""
return await cls.query.gino.all()
+103 -34
View File
@@ -6,13 +6,15 @@ from nonebot.message import run_postprocessor
from nonebot.matcher import Matcher
from typing import Optional, Type, Any
from gino.exceptions import UninitializedError
from utils.message_builder import custom_forward_msg
from utils.utils import (
is_number,
get_message_img,
)
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
MessageEvent,
GroupMessageEvent,
PrivateMessageEvent,
@@ -30,7 +32,6 @@ from .data_source import (
add_data_to_database,
get_setu_count,
)
from nonebot.adapters.onebot.v11.exception import ActionFailed
from configs.config import Config, NICKNAME
from utils.manager import withdraw_message_manager
from nonebot.params import CommandArg, Command, RegexGroup
@@ -98,6 +99,11 @@ __plugin_configs__ = {
"TIMEOUT": {"value": 10, "help": "色图下载超时限制(秒)", "default_value": 10},
"SHOW_INFO": {"value": True, "help": "是否显示色图的基本信息,如PID等", "default_value": True},
"ALLOW_GROUP_R18": {"value": False, "help": "在群聊中启用R18权限", "default_value": False},
"MAX_ONCE_NUM2FORWARD": {
"value": None,
"help": "单次发送的图片数量达到指定值时转发为合并消息",
"default_value": None,
},
}
Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pixiv.re", help_="Pixiv反向代理")
@@ -133,7 +139,10 @@ setu_reg = on_regex("(.*)[份|发|张|个|次|点](.*)[瑟|色|涩]图$", priori
@setu.handle()
async def _(
event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()
bot: Bot,
event: MessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
):
msg = arg.extract_plain_text().strip()
if isinstance(event, GroupMessageEvent):
@@ -149,10 +158,7 @@ async def _(
if cmd[0] == "色图r" and isinstance(event, PrivateMessageEvent):
r18 = 1
num = 10
elif (
cmd[0] == "色图r"
and isinstance(event, GroupMessageEvent)
):
elif cmd[0] == "色图r" and isinstance(event, GroupMessageEvent):
if not Config.get_config("send_setu", "ALLOW_GROUP_R18"):
await setu.finish(
random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
@@ -178,7 +184,7 @@ async def _(
Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
)
return
await send_setu_handle(setu, event, cmd[0], msg, num, r18)
await send_setu_handle(bot, setu, event, cmd[0], msg, num, r18)
num_key = {
@@ -197,7 +203,7 @@ num_key = {
@setu_reg.handle()
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
async def _(bot: Bot, event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
if isinstance(event, GroupMessageEvent):
impression = (
await SignGroupUser.ensure(event.user_id, event.group_id)
@@ -214,10 +220,11 @@ async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
num = int(num)
except ValueError:
num = 1
await send_setu_handle(setu_reg, event, "色图", tags, num, 0)
await send_setu_handle(bot, setu_reg, event, "色图", tags, num, 0)
async def send_setu_handle(
bot: Bot,
matcher: Type[Matcher],
event: MessageEvent,
command: str,
@@ -247,8 +254,10 @@ async def send_setu_handle(
if code == 401:
await setu.finish(urls[0], at_sender=True)
if code == 200:
forward_list = []
for i in range(len(urls)):
try:
msg_id = None
setu_img, index = await search_online_setu(urls[i])
# 下载成功的话
if index != -1:
@@ -257,9 +266,17 @@ async def send_setu_handle(
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送色图 {index}.png"
)
msg_id = await matcher.send(
Message(f"{text_list[i]}\n{setu_img}")
)
if (
Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
and num
>= Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
and isinstance(event, GroupMessageEvent)
):
forward_list.append(Message(f"{text_list[i]}\n{setu_img}"))
else:
msg_id = await matcher.send(
Message(f"{text_list[i]}\n{setu_img}")
)
else:
if setu_list is None:
setu_list, code = await get_setu_list(tags=tags, r18=r18)
@@ -268,14 +285,35 @@ async def send_setu_handle(
if setu_list:
setu_image = random.choice(setu_list)
setu_list.remove(setu_image)
msg_id = await matcher.send(
Message(
gen_message(setu_image)
+ (
await check_local_exists_or_download(setu_image)
)[0]
if (
Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
and num
>= Config.get_config(
"send_setu", "MAX_ONCE_NUM2FORWARD"
)
and isinstance(event, GroupMessageEvent)
):
forward_list.append(
Message(
gen_message(setu_image)
+ (
await check_local_exists_or_download(
setu_image
)
)[0]
)
)
else:
msg_id = await matcher.send(
Message(
gen_message(setu_image)
+ (
await check_local_exists_or_download(
setu_image
)
)[0]
)
)
)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
@@ -291,6 +329,16 @@ async def send_setu_handle(
)
except ActionFailed:
await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
if forward_list:
msg_id = await bot.send_group_forward_msg(
group_id=event.group_id,
messages=custom_forward_msg(forward_list, bot.self_id),
)
withdraw_message_manager.withdraw_message(
event,
msg_id,
Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
)
return
if code != 200:
await matcher.finish("网络连接失败...", at_sender=True)
@@ -300,27 +348,48 @@ async def send_setu_handle(
if code != 200:
await matcher.finish(setu_list[0], at_sender=True)
# 开始发图
forward_list = []
for _ in range(num):
if not setu_list:
await setu.finish("坏了,已经没图了,被榨干了!")
setu_image = random.choice(setu_list)
setu_list.remove(setu_image)
try:
msg_id = await matcher.send(
if (
Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
and num >= Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
and isinstance(event, GroupMessageEvent)
):
forward_list.append(
Message(
gen_message(setu_image)
+ (await check_local_exists_or_download(setu_image))[0]
)
)
withdraw_message_manager.withdraw_message(
event,
msg_id["message_id"],
Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送本地色图 {setu_image.local_id}.png"
)
except ActionFailed:
await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
else:
try:
msg_id = await matcher.send(
Message(
gen_message(setu_image)
+ (await check_local_exists_or_download(setu_image))[0]
)
)
withdraw_message_manager.withdraw_message(
event,
msg_id["message_id"],
Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送本地色图 {setu_image.local_id}.png"
)
except ActionFailed:
await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
if forward_list:
msg_id = await bot.send_group_forward_msg(
group_id=event.group_id,
messages=custom_forward_msg(forward_list, bot.self_id),
)
withdraw_message_manager.withdraw_message(
event, msg_id, Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE")
)
+4 -1
View File
@@ -2,6 +2,7 @@ from configs.path_config import IMAGE_PATH, TEMP_PATH
from utils.message_builder import image
from services.log import logger
from utils.image_utils import get_img_hash, compressed_image
from utils.utils import change_img_md5
from asyncpg.exceptions import UniqueViolationError
from asyncio.exceptions import TimeoutError
from typing import List, Optional
@@ -31,7 +32,7 @@ async def get_setu_urls(
params = {
"r18": r18, # 添加r18参数 0为否,1为是,2为混合
"tag": tags, # 若指定tag
"num": 100, # 一次返回的结果数量
"num": 20, # 一次返回的结果数量
"size": ["original"],
}
for count in range(3):
@@ -111,6 +112,7 @@ async def search_online_setu(
path_ / f"{index}.jpg",
)
logger.info(f"下载 lolicon 图片 {url_} 成功, id:{index}")
change_img_md5(path_ / file_name)
return image(path_ / file_name), index
except TimeoutError:
pass
@@ -128,6 +130,7 @@ async def check_local_exists_or_download(setu_image: Setu) -> "MessageSegment, i
path_ = r18_path if setu_image.is_r18 else path
file = IMAGE_PATH / path_ / f"{setu_image.local_id}.jpg"
if file.exists():
change_img_md5(file)
return image(f"{setu_image.local_id}.jpg", path_), 200
return await search_online_setu(setu_image.img_url, id_, path_)
+1 -1
View File
@@ -232,7 +232,7 @@ async def _(
result += image(b64=pic2b64(img))
if method in ["模糊效果", "6"]:
for i in range(index):
img = Image.open(TEMP_PATH / f"temp/{event.user_id}_{i}_update.png").filter(
img = Image.open(TEMP_PATH / f"{event.user_id}_{i}_update.png").filter(
ImageFilter.BLUR
)
result += image(b64=pic2b64(img))
+31 -15
View File
@@ -1,20 +1,36 @@
from configs.config import Config as gConfig
from .api import *
from .auth import *
gConfig.add_plugin_config(
"web-ui",
"username",
"admin",
name="web-ui",
help_="前端管理用户名"
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, IgnoredException
from utils.manager import plugins2settings_manager
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
Bot,
MessageEvent
)
gConfig.add_plugin_config(
"web-ui",
"password",
None,
name="web-ui",
help_="前端管理密码"
)
gConfig.add_plugin_config("web-ui", "username", "admin", name="web-ui", help_="前端管理用户名")
gConfig.add_plugin_config("web-ui", "password", None, name="web-ui", help_="前端管理密码")
# 使用webui访问api后plugins2settings中的cmd字段将从list变为str
# 暂时找不到原因
# 先使用hook修复
@run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
flag = False
for module in plugins2settings_manager.keys():
if isinstance(plugins2settings_manager.get_plugin_data(module).get("cmd"), str):
plugins2settings_manager.set_module_data(
module,
"cmd",
plugins2settings_manager.get_plugin_data(module).get("cmd").split(","),
False
)
flag = True
if flag:
plugins2settings_manager.save()
+8
View File
@@ -1,3 +1,5 @@
from pydantic import ValidationError
from configs.config import Config
from services.log import logger
from utils.manager import (plugins2block_manager, plugins2cd_manager,
@@ -85,6 +87,10 @@ def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
id_ += 1
data["plugin_config"] = tmp
plugin_list.append(Plugin(**data))
except (AttributeError, ValidationError) as e:
logger.error(
f"WEB_UI GET /webui/plugins model:{model} 发生错误 {type(e)}:{e}"
)
except Exception as e:
logger.error(
f"WEB_UI GET /webui/plugins model:{model} 发生错误 {type(e)}:{e}"
@@ -137,6 +143,8 @@ def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result:
else:
if plugin.plugin_settings:
for key, value in plugin.plugin_settings:
if key == "cmd":
value = value.split(",")
plugins2settings_manager.set_module_data(plugin.model, key, value)
if plugin.plugin_manager:
for key, value in plugin.plugin_manager:
+7 -7
View File
@@ -76,7 +76,7 @@ async def _(user: User = Depends(token_to_user)) -> Result:
async def get_system_data(user: User = Depends(token_to_user)):
"""
说明:
说明:
获取系统信息,资源文件大小,网络状态等
"""
baidu = 200
@@ -107,7 +107,7 @@ async def get_system_data(user: User = Depends(token_to_user)):
def _get_system_status(user: User = Depends(token_to_user)) -> SystemStatus:
"""
说明:
说明:
获取系统信息等
"""
cpu = psutil.cpu_percent()
@@ -126,7 +126,7 @@ def _get_system_disk(
type_: Optional[str], user: User = Depends(token_to_user)
) -> Union[SystemFolderSize, Dict[str, Union[float, datetime]]]:
"""
说明:
说明:
获取资源文件大小等
"""
if not type_:
@@ -171,9 +171,9 @@ def _get_system_disk(
def _get_dir_size(dir_path: Path) -> float:
"""
说明:
说明:
获取文件夹大小
参数:
参数:
:param dir_path: 文件夹路径
"""
size = 0
@@ -184,9 +184,9 @@ def _get_dir_size(dir_path: Path) -> float:
def save_system_data(cpu: float, memory: float, disk: float):
"""
说明:
说明:
保存一些系统信息
参数:
参数:
:param cpu: cpu
:param memory: memory
:param disk: disk
+2
View File
@@ -76,6 +76,8 @@ async def login_get_token(form_data: OAuth2PasswordRequestForm = Depends()):
token_data["token"].append(access_token)
if len(token_data["token"]) > 3:
token_data["token"] = token_data["token"][1:]
with open(token_file, 'w', encoding="utf8") as f:
json.dump(token_data, f, ensure_ascii=False, indent=4)
return {"access_token": access_token, "token_type": "bearer"}
+1 -1
View File
@@ -61,7 +61,7 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
msg_sp = msg.split("<|>")
w, h = w2b.size
add_h, font_size = init_h_font_size(h)
bg = BuildImage(w, h + add_h, color="black", font_size=font_size)
bg = BuildImage(w, h + add_h, color="black", font_size=int(font_size))
bg.paste(w2b)
chinese_msg = formalization_msg(msg)
if not bg.check_font_size(chinese_msg):
+6 -8
View File
@@ -1,20 +1,18 @@
import re
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Event
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Event
from utils.utils import get_message_img_file
from nonebot.typing import T_State
from .model import WordBank
async def check(bot: Bot, event: Event, state: T_State) -> bool:
async def check(event: Event) -> bool:
if isinstance(event, GroupMessageEvent):
msg = event.raw_message
list_img = get_message_img_file(event.json())
if list_img:
for img_file in list_img:
strinfo = re.compile(f"{img_file},subType=\d*]")
strinfo = re.compile(f"{img_file},.*?]")
msg = strinfo.sub(f'{img_file}]', msg)
return bool(
await WordBank.check(event.group_id, msg, event.is_tome())
)
strinfo_face = re.compile(f",type=sticker]")
msg = strinfo_face.sub(f']', msg)
return bool(await WordBank.check(event.group_id, msg,))
return False
+29 -11
View File
@@ -1,9 +1,10 @@
from utils.message_builder import image, at
from utils.message_builder import image, at, face
from typing import Tuple
from ._rule import check
from .model import WordBank
from configs.path_config import DATA_PATH
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from utils.utils import get_message_at, get_message_img
from utils.utils import get_message_at, get_message_img, change_img_md5
from nonebot import on_message
from models.group_member_info import GroupInfoUser
from utils.utils import get_message_img_file, is_number
@@ -23,16 +24,16 @@ async def _(event: GroupMessageEvent):
list_img = get_message_img_file(event.json())
if list_img:
for img_file in list_img:
strinfo = re.compile(f"{img_file},subType=\d*]")
strinfo = re.compile(f"{img_file},.*?]")
msg = strinfo.sub(f'{img_file}]', msg)
q = await WordBank.check(
event.group_id, msg, event.is_tome()
)
strinfo_face = re.compile(f",type=sticker]")
msg = strinfo_face.sub(f']', msg)
q = await WordBank.check(event.group_id, msg, )
await message_handle.send(await get_one_answer(event, q.format, q.answer))
# 处理单条回答
async def get_one_answer(event, format, _answer, all=1):
async def get_one_answer(event, format: str, _answer: str, all: bool = True) -> str:
path = data_dir / f"{event.group_id}"
placeholder_list = (
[
@@ -50,12 +51,13 @@ async def get_one_answer(event, format, _answer, all=1):
else:
for idx, placeholder in placeholder_list:
if placeholder.endswith("jpg"):
change_img_md5(path / placeholder)
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + image(
path / placeholder
)
else:
if all == 1:
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + at(placeholder)
if all:
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + at(int(placeholder))
else:
q = await GroupInfoUser.get_member_info(
int(placeholder), event.group_id)
@@ -65,7 +67,7 @@ async def get_one_answer(event, format, _answer, all=1):
# 处理单条问题
async def get_one_problem(event, problem):
async def get_one_problem(event, problem: str, ) -> Tuple[str, str]:
strinfo = re.compile(f",subType=\d")
problem = strinfo.sub('', problem)
_problem = problem
@@ -93,7 +95,7 @@ async def get_one_problem(event, problem):
# 显示单条数据库问题
async def get_one_image_problem(event, problem):
async def get_one_image_problem(event, problem: str) -> str:
path = data_dir / f"{event.group_id}" / "problem"
placeholder_list = []
idx = 0
@@ -127,3 +129,19 @@ async def get_one_image_problem(event, problem):
_p = _p[_p.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):]
return problem + _p
# 替换cq码
async def replace_cq(group_id, msg: str, is_face: bool = True) -> str:
strinfo_img = re.compile(f"\[CQ:image.*?]")
msg = strinfo_img.sub('[图片]', msg)
at_list = re.findall(rf"\[CQ:at,qq=(.*?)]", msg)
if at_list:
for ats in at_list:
q = await GroupInfoUser.get_member_info(
int(ats), group_id)
msg = msg.replace(f'[CQ:at,qq={ats}]', "@" + q.user_name)
if is_face:
strinfo_face = re.compile(f"\[CQ:face,id=.*?]")
msg = strinfo_face.sub('[表情]', msg)
return msg
+22 -42
View File
@@ -1,9 +1,7 @@
from services.db_context import db
from typing import Optional, List, Union, Tuple
from datetime import datetime
from pathlib import Path
from configs.path_config import DATA_PATH
import re
import random
from configs.config import Config
@@ -125,58 +123,40 @@ class WordBank(db.Model):
q.sort()
_tmp = []
for problem in q:
if "[_to_me" in problem:
r = re.search(r"\[_to_me\|(.*?)](.*)", problem)
if r:
bot_name = r.group(1)
problem = problem.replace(f"[_to_me|{bot_name}]", bot_name)
_tmp.append(problem)
return list(set(_tmp))
@classmethod
async def check(cls, group_id: int, problem: str, is_tome: bool = False) -> Optional["WordBank"]:
async def check(cls, group_id: int, problem: str) -> Optional["WordBank"]:
"""
检测词条并随机返回
:param group_id: 群号
:param problem: 问题
:param is_tome:是否at真寻
"""
if is_tome:
if problem:
FUZZY = Config.get_config("word_bank", "WORD_BANK_FUZZY")
KEY = Config.get_config("word_bank", "WORD_BANK_KEY")
q = await cls.query.where(
(cls.group_id == group_id)
(cls.group_id == group_id) & (cls.problem == problem)
).gino.all()
q = [x for x in q if "[_to_me" in x.problem]
if q:
for x in q:
r = re.search(r"\[_to_me\|(.*?)](.*)", x.problem)
if r and r.group(2) == problem:
return x
return None
if KEY and FUZZY:
q_fuzzy = await cls.query.where(
(cls.group_id == group_id) & (cls.search_type == 2) & (
cls.problem.contains(f'{problem}'))).gino.all()
q_key = await cls.query.where((cls.group_id == group_id) & (cls.search_type == 1)).gino.all()
q_key = [x for x in q_key if str(x.problem) in (problem)]
q += q_fuzzy + q_key
elif FUZZY:
q_fuzzy = await cls.query.where(
(cls.group_id == group_id) & (cls.search_type == 2) & (
cls.problem.contains(f'{problem}'))).gino.all()
q += q_fuzzy
elif KEY:
q_key = await cls.query.where((cls.group_id == group_id) & (cls.search_type == 1)).gino.all()
q_key = [x for x in q_key if str(x.problem) in (problem)]
q += q_key
else:
if problem:
FUZZY = Config.get_config("word_bank", "WORD_BANK_FUZZY")
KEY = Config.get_config("word_bank", "WORD_BANK_KEY")
q = await cls.query.where(
(cls.group_id == group_id) & (cls.problem == problem)
).gino.all()
if KEY and FUZZY:
q_fuzzy = await cls.query.where(
(cls.group_id == group_id) & (cls.search_type == 2) & (
cls.problem.contains(f'{problem}'))).gino.all()
q_key = await cls.query.where((cls.group_id == group_id) & (cls.search_type == 1)).gino.all()
q_key = [x for x in q_key if str(x.problem) in (problem)]
q += q_fuzzy + q_key
elif FUZZY:
q_fuzzy = await cls.query.where(
(cls.group_id == group_id) & (cls.search_type == 2) & (
cls.problem.contains(f'{problem}'))).gino.all()
q += q_fuzzy
elif KEY:
q_key = await cls.query.where((cls.group_id == group_id) & (cls.search_type == 1)).gino.all()
q_key = [x for x in q_key if str(x.problem) in (problem)]
q += q_key
else:
return None
return None
return random.choice(q) if q else None
+20 -27
View File
@@ -6,14 +6,13 @@ from utils.http_utils import AsyncHttpx
from ._data_source import WordBankBuilder
from utils.message_builder import image
from utils.image_utils import text2image
from .message_handle import get_one_answer, get_one_problem, get_one_image_problem
from .message_handle import get_one_answer, get_one_problem, get_one_image_problem, replace_cq
from .model import WordBank
from nonebot.adapters.onebot.v11 import (
Bot,
GroupMessageEvent,
Message
)
from nonebot.typing import T_State
from nonebot import on_command
import random
import os
@@ -69,7 +68,7 @@ show_word = on_command("显示词条", aliases={"查看词条"}, priority=5, blo
@add_word.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = CommandArg()):
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = str(arg)
r = re.search(r"问(.+)\s?答([\s\S]*)", msg)
if not r:
@@ -81,12 +80,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = C
if not answer:
await add_word.finish("未检测到词条回答...")
idx = 0
for n in bot.config.nickname:
if n and problem.startswith(n):
_problem = f"[_to_me|{n}]" + problem[len(n):]
break
else:
_problem = problem
_problem = problem
search_type = 0
if re.search("^关键字|词(.*)", msg):
search_type = 1
@@ -94,7 +88,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = C
search_type = 2
_builder = await get__builder(event, _problem, answer, idx)
if await _builder.save(search_type):
logger.info(f"已保存词条 问:{_builder.problem} 答:{msg}")
logger.info(f"已保存词条 问:{_builder.problem} 答:{answer}")
await add_word.send("已保存词条:" + _builder.problem)
else:
await delete_word.send("保存失败,可能是回答重复")
@@ -102,7 +96,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = C
@delete_word.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = str(arg).strip()
msg = str(arg)
if not msg:
await delete_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
index = None
@@ -124,7 +118,10 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
if answer := await WordBank.delete_problem_answer(
event.user_id, event.group_id, _problem, index
):
await delete_word.send("删除词条成功:" + problem + f"\n回答:\n{answer}")
await delete_word.send(Message(
"删除词条成功:\n问" + await replace_cq(event.group_id, problem, False) + f"\n回答:\n" + await replace_cq(
event.group_id, answer, False) + "\n"))
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
@@ -137,7 +134,7 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
@update_word.handle()
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = str(arg)
if not msg:
await update_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
@@ -157,12 +154,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
else:
await update_word.finish("此命令之后需要跟随修改内容")
idx = 0
for n in bot.config.nickname:
if n and problem.startswith(n):
_problem = f"[_to_me|{n}]" + problem[len(n):]
break
else:
_problem = problem
_problem = problem
_builder = await get__builder(event, _problem, new_answer, idx)
try:
@@ -185,8 +177,8 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
if not msg:
_problem_list = await WordBank.get_group_all_problem(event.group_id)
if not _problem_list:
await show_word.finish("该群未收录任何词条..")
_problem_list = [f"\t{i}. {x}" for i, x in enumerate(_problem_list)]
await show_word.finish("该群未收录任replace_cq何词条..")
_problem_list = [f"\t{i}. {await replace_cq(event.group_id, x)}" for i, x in enumerate(_problem_list)]
long_problem_list = len(_problem_list)
max_line = Config.get_config("word_bank", "WORD_BANK_MIX")
if long_problem_list > max_line:
@@ -245,10 +237,11 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
else:
# 解析图片和@
_answer_img_nu_list = [await get_one_answer(event, format, answer, 0) for answer, format in _answer_list]
_answer_img_nu_list = [await get_one_answer(event, format, answer, False) for answer, format in
_answer_list]
word_nu = len(_answer_img_nu_list)
img_nu = 0
answer = "词条" + msg + "回答:"
answer = "词条" + msg + "\n回答:"
for i, x, in enumerate(_answer_img_nu_list):
r = re.findall(rf"\[CQ:image,file=", str(x))
if r:
@@ -265,7 +258,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
# await show_word.send(f"词条 {msg} 回答:\n" + "\n".join(_answer_list))
async def get__builder(event, _problem, answer, idx):
async def get__builder(event, _problem: str, answer: str, idx: int):
(data_dir / f"{event.group_id}").mkdir(exist_ok=True, parents=True)
(data_dir / f"{event.group_id}" / "problem").mkdir(exist_ok=True, parents=True)
_builder = WordBankBuilder(event.user_id, event.group_id, _problem)
@@ -293,16 +286,16 @@ async def get__builder(event, _problem, answer, idx):
if f"__placeholder_{rand}_{idx}.jpg" not in os.listdir(data_dir / f"{event.group_id}"):
break
rand = random.randint(1, 10000) + random.randint(1, 114514)
strinfo = re.compile(f"\[CQ:image,file={r.group(1)},url={_x_list[0]}\?{_x_list[1]},subType=\d*?]")
strinfo = re.compile(f"\[CQ:image,file={r.group(1)},.*url={_x_list[0]}\?{_x_list[1]}.*?]")
answer = strinfo.sub(f"[__placeholder_{idx}]", answer)
await AsyncHttpx.download_file(
img, data_dir / f"{event.group_id}" / f"__placeholder_{rand}_{idx}.jpg"
)
_builder.set_placeholder(idx, f"__placeholder_{rand}_{idx}.jpg")
idx += 1
r_problem = re.search(rf"\[CQ:image,file=(.*?),url={_x}.*?]", _p)
r_problem = re.search(rf"\[CQ:image,file=(.*?)(,subType=\d)?,url={_x}.*?]", _p)
if r_problem:
strinfo = re.compile(f",url={_x_list[0]}\?{_x_list[1]},subType=\d*?]")
strinfo = re.compile(f"(,subType=\d)?,url={_x_list[0]}\?{_x_list[1]}.*?]")
_problem = strinfo.sub(f"]", _problem)
_p = strinfo.sub(f"]", _p)
problem += _p[: _p.find(f"[CQ:image,file={r_problem.group(1)}]")] + image(img)
Generated
+257 -104
View File
@@ -142,14 +142,16 @@ lxml = ["lxml"]
[[package]]
name = "bilireq"
version = "0.1.2"
version = "0.2.0.post1"
description = ""
category = "main"
optional = false
python-versions = ">=3.7,<4.0"
[package.dependencies]
httpx = ">=0.22.0,<0.23.0"
grpcio = ">=1.46.3,<2.0.0"
httpx = ">=0.23.0,<0.24.0"
protobuf = "3.20.1"
rsa = ">=4.8,<5.0"
[package.extras]
@@ -179,7 +181,7 @@ uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "certifi"
version = "2022.5.18.1"
version = "2022.6.15"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
@@ -193,17 +195,6 @@ category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "charset-normalizer"
version = "2.0.12"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main"
optional = false
python-versions = ">=3.5.0"
[package.extras]
unicode_backport = ["unicodedata2"]
[[package]]
name = "click"
version = "8.1.3"
@@ -229,7 +220,7 @@ proces = ">=0.1.0"
[[package]]
name = "colorama"
version = "0.4.4"
version = "0.4.5"
description = "Cross-platform colored terminal text."
category = "main"
optional = false
@@ -380,6 +371,20 @@ python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
[package.extras]
docs = ["sphinx"]
[[package]]
name = "grpcio"
version = "1.46.3"
description = "HTTP/2-based RPC framework"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
six = ">=1.5.2"
[package.extras]
protobuf = ["grpcio-tools (>=1.46.3)"]
[[package]]
name = "h11"
version = "0.12.0"
@@ -390,11 +395,11 @@ python-versions = ">=3.6"
[[package]]
name = "httpcore"
version = "0.14.7"
version = "0.15.0"
description = "A minimal low-level HTTP client."
category = "main"
optional = false
python-versions = ">=3.6"
python-versions = ">=3.7"
[package.dependencies]
anyio = ">=3.0.0,<4.0.0"
@@ -419,22 +424,21 @@ test = ["Cython (>=0.29.24,<0.30.0)"]
[[package]]
name = "httpx"
version = "0.22.0"
version = "0.23.0"
description = "The next generation HTTP client."
category = "main"
optional = false
python-versions = ">=3.6"
python-versions = ">=3.7"
[package.dependencies]
certifi = "*"
charset-normalizer = "*"
httpcore = ">=0.14.5,<0.15.0"
httpcore = ">=0.15.0,<0.16.0"
rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]}
sniffio = "*"
[package.extras]
brotli = ["brotlicffi", "brotli"]
cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10.0.0,<11.0.0)", "pygments (>=2.0.0,<3.0.0)"]
cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10,<13)", "pygments (>=2.0.0,<3.0.0)"]
http2 = ["h2 (>=3,<5)"]
socks = ["socksio (>=1.0.0,<2.0.0)"]
@@ -471,7 +475,7 @@ python-versions = "*"
[[package]]
name = "kiwisolver"
version = "1.4.2"
version = "1.4.3"
description = "A fast implementation of the Cassowary constraint solver"
category = "main"
optional = false
@@ -525,6 +529,14 @@ pyparsing = ">=2.2.1"
python-dateutil = ">=2.7"
setuptools_scm = ">=4"
[[package]]
name = "msgpack"
version = "1.0.4"
description = "MessagePack serializer"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "multidict"
version = "6.0.2"
@@ -543,22 +555,23 @@ python-versions = "*"
[[package]]
name = "nonebot-adapter-onebot"
version = "2.0.0b1"
version = "2.1.1"
description = "OneBot(CQHTTP) adapter for nonebot2"
category = "main"
optional = false
python-versions = ">=3.7.3,<4.0.0"
[package.dependencies]
nonebot2 = ">=2.0.0-beta.1,<3.0.0"
msgpack = ">=1.0.3,<2.0.0"
nonebot2 = ">=2.0.0-beta.3,<3.0.0"
[[package]]
name = "nonebot-plugin-apscheduler"
version = "0.1.2"
version = "0.1.3"
description = "APScheduler Support for NoneBot2"
category = "main"
optional = false
python-versions = ">=3.7,<4.0"
python-versions = ">=3.7.3,<4.0.0"
[package.dependencies]
apscheduler = ">=3.7.0,<4.0.0"
@@ -566,7 +579,7 @@ nonebot2 = ">=2.0.0-alpha.8,<3.0.0"
[[package]]
name = "nonebot2"
version = "2.0.0b3"
version = "2.0.0b4"
description = "An asynchronous python bot framework."
category = "main"
optional = false
@@ -577,7 +590,7 @@ fastapi = ">=0.78.0,<0.79.0"
loguru = ">=0.6.0,<0.7.0"
pydantic = {version = ">=1.9.0,<1.10.0", extras = ["dotenv"]}
pygtrie = ">=2.4.1,<3.0.0"
tomlkit = ">=0.10.0,<0.11.0"
tomlkit = ">=0.10.0,<1.0.0"
typing-extensions = ">=3.10.0,<5.0.0"
uvicorn = {version = ">=0.17.0,<0.18.0", extras = ["standard"]}
yarl = ">=1.7.2,<2.0.0"
@@ -599,7 +612,7 @@ python-versions = ">=3.8"
[[package]]
name = "opencv-python"
version = "4.5.5.64"
version = "4.6.0.66"
description = "Wrapper package for OpenCV python bindings."
category = "main"
optional = false
@@ -681,6 +694,14 @@ python-versions = ">=3.6"
[package.dependencies]
zhconv = "1.4.3"
[[package]]
name = "protobuf"
version = "3.20.1"
description = "Protocol Buffers"
category = "main"
optional = false
python-versions = ">=3.7"
[[package]]
name = "psutil"
version = "5.9.1"
@@ -1036,7 +1057,7 @@ python-versions = ">=3.7"
[[package]]
name = "tomlkit"
version = "0.10.2"
version = "0.11.0"
description = "Style preserving TOML library"
category = "main"
optional = false
@@ -1185,7 +1206,7 @@ python-versions = "*"
[metadata]
lock-version = "1.1"
python-versions = "^3.8"
content-hash = "76eab4291b3c2189faf8ee730ad3363111cf377797b803bed0f36394a12d4974"
content-hash = "85256064b3b90b3e9a4ef068edec137c7b4ee8b08c0f2dbbe925390e286f045d"
[metadata.files]
aiofiles = [
@@ -1303,8 +1324,8 @@ beautifulsoup4 = [
{file = "beautifulsoup4-4.9.3.tar.gz", hash = "sha256:84729e322ad1d5b4d25f805bfa05b902dd96450f43842c4e99067d5e1369eb25"},
]
bilireq = [
{file = "bilireq-0.1.2-py3-none-any.whl", hash = "sha256:eef1fee5d7fd84c03a50d40fdda6b4dd4c857efed9a4fd0fccb347554a8e46c4"},
{file = "bilireq-0.1.2.tar.gz", hash = "sha256:cd946f7827a901d83041b628cf2b5cf8d57cd5bb4c7499a0c5e6afbaf479bda3"},
{file = "bilireq-0.2.0.post1-py3-none-any.whl", hash = "sha256:bced02207c09fc29d08f1f37cfeaefdcfdde3dbff180d35d5c3c9d7ea3fa1f90"},
{file = "bilireq-0.2.0.post1.tar.gz", hash = "sha256:f731a5768c7e3159b1e0d5b02b3fdb58939ed24d6cd23a428ab1df20fbbf62cc"},
]
black = [
{file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"},
@@ -1332,17 +1353,13 @@ black = [
{file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"},
]
certifi = [
{file = "certifi-2022.5.18.1-py3-none-any.whl", hash = "sha256:f1d53542ee8cbedbe2118b5686372fb33c297fcd6379b050cca0ef13a597382a"},
{file = "certifi-2022.5.18.1.tar.gz", hash = "sha256:9c5705e395cd70084351dd8ad5c41e65655e08ce46f2ec9cf6c2c08390f71eb7"},
{file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"},
{file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"},
]
chardet = [
{file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"},
{file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
]
charset-normalizer = [
{file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
{file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
]
click = [
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
@@ -1352,8 +1369,8 @@ cn2an = [
{file = "cn2an-0.5.17.tar.gz", hash = "sha256:7b122c878722a3e7d098749fd32fb557e333de178cb451c7164cf52abef30199"},
]
colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
]
commonmark = [
{file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
@@ -1447,13 +1464,69 @@ greenlet = [
{file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"},
{file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"},
]
grpcio = [
{file = "grpcio-1.46.3-cp310-cp310-linux_armv7l.whl", hash = "sha256:4c05dbc164c2d3015109292ffeed68292807a6cb1225f9a36699bf2166634908"},
{file = "grpcio-1.46.3-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:c6a460b6aaf43428d48fececad864cc562458b944df80568e490d985d8576292"},
{file = "grpcio-1.46.3-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:707b85fa0cf606a9ab02246bd3142c76e154f1c30f00f7346b2afa3d0b315d5a"},
{file = "grpcio-1.46.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c63e7c61c0b06f838e8f45ffd3a7c68a520c4c026b2e0e8b1ad29c456d0f859"},
{file = "grpcio-1.46.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6fe85e5873d9784ab82cf261d9fc07ed67a4459ba69fbe1187ef8b8e3d9e30e"},
{file = "grpcio-1.46.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:df980c4901a92ca649e18036ff67c7c8cad239b2759c2472694f7ab0f0b4ffb9"},
{file = "grpcio-1.46.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7b59982e405159385d5796aa1e0817ec83affb3eb4c2a5b7ca39413d17d7e332"},
{file = "grpcio-1.46.3-cp310-cp310-win32.whl", hash = "sha256:6d51fa98bd40d4593f819a3fec8a078a192958d24f84c3daf15b5ad7705d4c48"},
{file = "grpcio-1.46.3-cp310-cp310-win_amd64.whl", hash = "sha256:e9bba429eb743471715e6dadf006a70a77cb6afb065aa4a6eaa9efd76b09e336"},
{file = "grpcio-1.46.3-cp36-cp36m-linux_armv7l.whl", hash = "sha256:a898b0f13bda2dfe786952cc1ea705762fa6c3ae799b4bb0525d7821605ae968"},
{file = "grpcio-1.46.3-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:9014aee70e29911008d2f388011cabf2c7fe4fe29918ce5f71513a660494069a"},
{file = "grpcio-1.46.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9c97106134de70f8323b12738ac0adf0615688b69253002910d0c5d42d202a77"},
{file = "grpcio-1.46.3-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d41ea8efb87b1ae4e576b13d94f2b470297a1495ae6b2c9d1047952731bf168f"},
{file = "grpcio-1.46.3-cp36-cp36m-manylinux_2_17_aarch64.whl", hash = "sha256:ab18e85082003d7883a4d069065436e61cb27c2c2150e7965ce93658f17bc8da"},
{file = "grpcio-1.46.3-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:307ff1d6237d5c383196660a12db021c20280227f9f4423d88d6b2ab20c8b1d0"},
{file = "grpcio-1.46.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c9106ef35239767b3aa9dc1a79856ad499655f853fca9f92f9dd3182d646627"},
{file = "grpcio-1.46.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e0ae8e8523308bf7ab0b7d6aa686011de59b19fb06abb253f302d0b5da2a5905"},
{file = "grpcio-1.46.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:4fd0aa30a938893060defd5f222604461db55f9a81a028b154479b91deac7074"},
{file = "grpcio-1.46.3-cp36-cp36m-win32.whl", hash = "sha256:f7637b55662e56a64c07846bc0d2da6232a6e893b22c39790f2e41d03ac1a826"},
{file = "grpcio-1.46.3-cp36-cp36m-win_amd64.whl", hash = "sha256:97801afa96a819f911d030b490dbea95b246de02433bac69c5acf150081686e4"},
{file = "grpcio-1.46.3-cp37-cp37m-linux_armv7l.whl", hash = "sha256:3585a6fa3d97fc8f030bbf0e88185b5eb345a340f6732e165d5c22df54de5bc6"},
{file = "grpcio-1.46.3-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:dc6d15cbcceaebaacf2994280ed1c01d42b5772059b30afd8a76152e9d23daa4"},
{file = "grpcio-1.46.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e0486485d59d5865149010966ef3df99c5df97ab8b01f10e26f8759d6e10fafc"},
{file = "grpcio-1.46.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5210ec7a1638daa61da16487fbfafb3dbb7b8cd44382d9262316bbb58a5b1cf7"},
{file = "grpcio-1.46.3-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:e278fa30d2b5652f7e43970c86ad34c639146443553678b746909aae204924dc"},
{file = "grpcio-1.46.3-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d4148f1f76516b01cccf2273b45bc706847f1560ccb55aa6e29df851e9ca8cc"},
{file = "grpcio-1.46.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01f3f7a6cdb111cf276ffff9c892fa32624e03999bac809d3f3d8321d98b6855"},
{file = "grpcio-1.46.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:91aaccbe1c035ad2bcd1b8a25cebd11839070eb70fb6573e9d0197ddbca5d96b"},
{file = "grpcio-1.46.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:26136c19d96e2138f04412101f3730d66f5f1515dc912ac0d415587c8208d826"},
{file = "grpcio-1.46.3-cp37-cp37m-win32.whl", hash = "sha256:a8f40dafcdc3e0e378387953528eaf4e35758161f3b10d96199f12b11afbe2c2"},
{file = "grpcio-1.46.3-cp37-cp37m-win_amd64.whl", hash = "sha256:a6bb52df85a4bd6d3bad16b4e7cc43efe95469b74a856c87a2c5bef496c9147f"},
{file = "grpcio-1.46.3-cp38-cp38-linux_armv7l.whl", hash = "sha256:2334ceeab4084e80433693451452cba26afc1607a7974133af3b3635fc8aa935"},
{file = "grpcio-1.46.3-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:2c96a6103caec84985bb2cffac2b261f8cac2641e7a70d4b43b7d08754a6cfe7"},
{file = "grpcio-1.46.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7a39d39da8855b03be2d7348387986bab6a322031fcc8b04fa5e72355e7b13a1"},
{file = "grpcio-1.46.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4caf87a06de88e3611a4610c57ef55b78801843d1f5a9e5fd6b75e887dad3340"},
{file = "grpcio-1.46.3-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:ffbbb228e6fc6f85b34aac428eb76b4fc6591d771e487ce46eb16b4b7e18b91d"},
{file = "grpcio-1.46.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c89ae010c57333dd3c692e0892199a59df1ddfd467cdfea31f98331d0e8cf87"},
{file = "grpcio-1.46.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34b206cdf78dd1c14d93e10e7308750c36b4e6754d579895cba74341875e2fb5"},
{file = "grpcio-1.46.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a19b3ecdb8ddf60e4b034def27636065e49ac1ee3c85854a16353cf52c2afd83"},
{file = "grpcio-1.46.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aac6e66acae82be5c99a0a40ab8f5733d7df76a04f242cf42ecc34cfb1e947bd"},
{file = "grpcio-1.46.3-cp38-cp38-win32.whl", hash = "sha256:aff6d961d6bc5e34e12e148383671f8da5d17e47ed606ec15f483def3053b206"},
{file = "grpcio-1.46.3-cp38-cp38-win_amd64.whl", hash = "sha256:71d46c2f3c0512bac3d658af3193e3d645c96123af56bd07a8416474c69df2cf"},
{file = "grpcio-1.46.3-cp39-cp39-linux_armv7l.whl", hash = "sha256:5969f63f3cf92538f83f26949d393d9fc59de670f47cf7c2a0e1e0d30b770294"},
{file = "grpcio-1.46.3-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:5f8134d4a7e76c8c6644bd3ce728b9894933575155d02c09922986d5d8d6e48c"},
{file = "grpcio-1.46.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:53fff69fd4d315adddda226e7b71804d1f12adf3a4162126dc520725624a483a"},
{file = "grpcio-1.46.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3af2cc4e41f87d3b57f624b1b14321c1d0f030b191da60f9eeeda5448d83240c"},
{file = "grpcio-1.46.3-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5fb7779ae01c20c4fad5831e98003b3f036acfe6b77697d6a9baa0f9a7f14daf"},
{file = "grpcio-1.46.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56636ebf8db63ba50d272dfd73c92538950525120311676246f8f6a81b0aa144"},
{file = "grpcio-1.46.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a5012ba00cf8b7ce9e6ac2312ace0b0e16fe9502c18340c8c3ecb734a759831"},
{file = "grpcio-1.46.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:be1679d814a292a701f45df324e25b060435dd13159e9b08a16e2a2396c4391c"},
{file = "grpcio-1.46.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4faaba7db078a0001a8c1a4370d56dc454c03b4613b6acec01f14b90c8dd03cf"},
{file = "grpcio-1.46.3-cp39-cp39-win32.whl", hash = "sha256:f5c6393fa645183ae858ebfbf72ab94e7ebafb5cd849dcf4ae8c53a83cce4e24"},
{file = "grpcio-1.46.3-cp39-cp39-win_amd64.whl", hash = "sha256:158b90d4f1354f40e435f4c866057acc29a4364b214c31049c8b8c903646fbab"},
{file = "grpcio-1.46.3.tar.gz", hash = "sha256:4b8fd8b1cd553635274b83cd984f0755e6779886eca53c1c71d48215962eb689"},
]
h11 = [
{file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"},
{file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"},
]
httpcore = [
{file = "httpcore-0.14.7-py3-none-any.whl", hash = "sha256:47d772f754359e56dd9d892d9593b6f9870a37aeb8ba51e9a88b09b3d68cfade"},
{file = "httpcore-0.14.7.tar.gz", hash = "sha256:7503ec1c0f559066e7e39bc4003fd2ce023d01cf51793e3c173b864eb456ead1"},
{file = "httpcore-0.15.0-py3-none-any.whl", hash = "sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6"},
{file = "httpcore-0.15.0.tar.gz", hash = "sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b"},
]
httptools = [
{file = "httptools-0.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcddfe70553be717d9745990dfdb194e22ee0f60eb8f48c0794e7bfeda30d2d5"},
@@ -1492,8 +1565,8 @@ httptools = [
{file = "httptools-0.4.0.tar.gz", hash = "sha256:2c9a930c378b3d15d6b695fb95ebcff81a7395b4f9775c4f10a076beb0b2c1ff"},
]
httpx = [
{file = "httpx-0.22.0-py3-none-any.whl", hash = "sha256:e35e83d1d2b9b2a609ef367cc4c1e66fd80b750348b20cc9e19d1952fc2ca3f6"},
{file = "httpx-0.22.0.tar.gz", hash = "sha256:d8e778f76d9bbd46af49e7f062467e3157a5a3d2ae4876a4bbfd8a51ed9c9cb4"},
{file = "httpx-0.23.0-py3-none-any.whl", hash = "sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b"},
{file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"},
]
idna = [
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
@@ -1506,49 +1579,49 @@ jieba = [
{file = "jieba-0.42.1.tar.gz", hash = "sha256:055ca12f62674fafed09427f176506079bc135638a14e23e25be909131928db2"},
]
kiwisolver = [
{file = "kiwisolver-1.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6e395ece147f0692ca7cdb05a028d31b83b72c369f7b4a2c1798f4b96af1e3d8"},
{file = "kiwisolver-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b7f50a1a25361da3440f07c58cd1d79957c2244209e4f166990e770256b6b0b"},
{file = "kiwisolver-1.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c032c41ae4c3a321b43a3650e6ecc7406b99ff3e5279f24c9b310f41bc98479"},
{file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1dcade8f6fe12a2bb4efe2cbe22116556e3b6899728d3b2a0d3b367db323eacc"},
{file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e45e780a74416ef2f173189ef4387e44b5494f45e290bcb1f03735faa6779bf"},
{file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d2bb56309fb75a811d81ed55fbe2208aa77a3a09ff5f546ca95e7bb5fac6eff"},
{file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b2d6c12f2ad5f55104a36a356192cfb680c049fe5e7c1f6620fc37f119cdc2"},
{file = "kiwisolver-1.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:262c248c60f22c2b547683ad521e8a3db5909c71f679b93876921549107a0c24"},
{file = "kiwisolver-1.4.2-cp310-cp310-win32.whl", hash = "sha256:1008346a7741620ab9cc6c96e8ad9b46f7a74ce839dbb8805ddf6b119d5fc6c2"},
{file = "kiwisolver-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:6ece2e12e4b57bc5646b354f436416cd2a6f090c1dadcd92b0ca4542190d7190"},
{file = "kiwisolver-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b978afdb913ca953cf128d57181da2e8798e8b6153be866ae2a9c446c6162f40"},
{file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f88c4b8e449908eeddb3bbd4242bd4dc2c7a15a7aa44bb33df893203f02dc2d"},
{file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e348f1904a4fab4153407f7ccc27e43b2a139752e8acf12e6640ba683093dd96"},
{file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c839bf28e45d7ddad4ae8f986928dbf5a6d42ff79760d54ec8ada8fb263e097c"},
{file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8ae5a071185f1a93777c79a9a1e67ac46544d4607f18d07131eece08d415083a"},
{file = "kiwisolver-1.4.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c222f91a45da9e01a9bc4f760727ae49050f8e8345c4ff6525495f7a164c8973"},
{file = "kiwisolver-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:a4e8f072db1d6fb7a7cc05a6dbef8442c93001f4bb604f1081d8c2db3ca97159"},
{file = "kiwisolver-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:be9a650890fb60393e60aacb65878c4a38bb334720aa5ecb1c13d0dac54dd73b"},
{file = "kiwisolver-1.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ec2e55bf31b43aabe32089125dca3b46fdfe9f50afbf0756ae11e14c97b80ca"},
{file = "kiwisolver-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d1078ba770d6165abed3d9a1be1f9e79b61515de1dd00d942fa53bba79f01ae"},
{file = "kiwisolver-1.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbb5eb4a2ea1ffec26268d49766cafa8f957fe5c1b41ad00733763fae77f9436"},
{file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e6cda72db409eefad6b021e8a4f964965a629f577812afc7860c69df7bdb84a"},
{file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b1605c7c38cc6a85212dfd6a641f3905a33412e49f7c003f35f9ac6d71f67720"},
{file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81237957b15469ea9151ec8ca08ce05656090ffabc476a752ef5ad7e2644c526"},
{file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:240009fdf4fa87844f805e23f48995537a8cb8f8c361e35fda6b5ac97fcb906f"},
{file = "kiwisolver-1.4.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:240c2d51d098395c012ddbcb9bd7b3ba5de412a1d11840698859f51d0e643c4f"},
{file = "kiwisolver-1.4.2-cp38-cp38-win32.whl", hash = "sha256:8b6086aa6936865962b2cee0e7aaecf01ab6778ce099288354a7229b4d9f1408"},
{file = "kiwisolver-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:0d98dca86f77b851350c250f0149aa5852b36572514d20feeadd3c6b1efe38d0"},
{file = "kiwisolver-1.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:91eb4916271655dfe3a952249cb37a5c00b6ba68b4417ee15af9ba549b5ba61d"},
{file = "kiwisolver-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa4d97d7d2b2c082e67907c0b8d9f31b85aa5d3ba0d33096b7116f03f8061261"},
{file = "kiwisolver-1.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:71469b5845b9876b8d3d252e201bef6f47bf7456804d2fbe9a1d6e19e78a1e65"},
{file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8ff3033e43e7ca1389ee59fb7ecb8303abb8713c008a1da49b00869e92e3dd7c"},
{file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:89b57c2984f4464840e4b768affeff6b6809c6150d1166938ade3e22fbe22db8"},
{file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffbdb9a96c536f0405895b5e21ee39ec579cb0ed97bdbd169ae2b55f41d73219"},
{file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a830a03970c462d1a2311c90e05679da56d3bd8e78a4ba9985cb78ef7836c9f"},
{file = "kiwisolver-1.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f74f2a13af201559e3d32b9ddfc303c94ae63d63d7f4326d06ce6fe67e7a8255"},
{file = "kiwisolver-1.4.2-cp39-cp39-win32.whl", hash = "sha256:e677cc3626287f343de751e11b1e8a5b915a6ac897e8aecdbc996cd34de753a0"},
{file = "kiwisolver-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b3e251e5c38ac623c5d786adb21477f018712f8c6fa54781bd38aa1c60b60fc2"},
{file = "kiwisolver-1.4.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0c380bb5ae20d829c1a5473cfcae64267b73aaa4060adc091f6df1743784aae0"},
{file = "kiwisolver-1.4.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:484f2a5f0307bc944bc79db235f41048bae4106ffa764168a068d88b644b305d"},
{file = "kiwisolver-1.4.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8afdf533b613122e4bbaf3c1e42c2a5e9e2d1dd3a0a017749a7658757cb377"},
{file = "kiwisolver-1.4.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42f6ef9b640deb6f7d438e0a371aedd8bef6ddfde30683491b2e6f568b4e884e"},
{file = "kiwisolver-1.4.2.tar.gz", hash = "sha256:7f606d91b8a8816be476513a77fd30abe66227039bd6f8b406c348cb0247dcc9"},
{file = "kiwisolver-1.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fd2842a0faed9ab9aba0922c951906132d9384be89690570f0ed18cd4f20e658"},
{file = "kiwisolver-1.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:caa59e2cae0e23b1e225447d7a9ddb0f982f42a6a22d497a484dfe62a06f7c0e"},
{file = "kiwisolver-1.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1d2c744aeedce22c122bb42d176b4aa6d063202a05a4abdacb3e413c214b3694"},
{file = "kiwisolver-1.4.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:afe173ac2646c2636305ab820cc0380b22a00a7bca4290452e7166b4f4fa49d0"},
{file = "kiwisolver-1.4.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40240da438c0ebfe2aa76dd04b844effac6679423df61adbe3437d32f23468d9"},
{file = "kiwisolver-1.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21a3a98f0a21fc602663ca9bce2b12a4114891bdeba2dea1e9ad84db59892fca"},
{file = "kiwisolver-1.4.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51078855a16b7a4984ed2067b54e35803d18bca9861cb60c60f6234b50869a56"},
{file = "kiwisolver-1.4.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c16635f8dddbeb1b827977d0b00d07b644b040aeb9ff8607a9fc0997afa3e567"},
{file = "kiwisolver-1.4.3-cp310-cp310-win32.whl", hash = "sha256:2d76780d9c65c7529cedd49fa4802d713e60798d8dc3b0d5b12a0a8f38cca51c"},
{file = "kiwisolver-1.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:3a297d77b3d6979693f5948df02b89431ae3645ec95865e351fb45578031bdae"},
{file = "kiwisolver-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ca3eefb02ef17257fae8b8555c85e7c1efdfd777f671384b0e4ef27409b02720"},
{file = "kiwisolver-1.4.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d248c46c0aa406695bda2abf99632db991f8b3a6d46018721a2892312a99f069"},
{file = "kiwisolver-1.4.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cb55258931448d61e2d50187de4ee66fc9d9f34908b524949b8b2b93d0c57136"},
{file = "kiwisolver-1.4.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86bcf0009f2012847a688f2f4f9b16203ca4c835979a02549aa0595d9f457cc8"},
{file = "kiwisolver-1.4.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e7cf940af5fee00a92e281eb157abe8770227a5255207818ea9a34e54a29f5b2"},
{file = "kiwisolver-1.4.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dd22085446f3eca990d12a0878eeb5199dc9553b2e71716bfe7bed9915a472ab"},
{file = "kiwisolver-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:d2578e5149ff49878934debfacf5c743fab49eca5ecdb983d0b218e1e554c498"},
{file = "kiwisolver-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:5fb73cc8a34baba1dfa546ae83b9c248ef6150c238b06fc53d2773685b67ec67"},
{file = "kiwisolver-1.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f70f3d028794e31cf9d1a822914efc935aadb2438ec4e8d4871d95eb1ce032d6"},
{file = "kiwisolver-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:71af5b43e4fa286a35110fc5bb740fdeae2b36ca79fbcf0a54237485baeee8be"},
{file = "kiwisolver-1.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26b5a70bdab09e6a2f40babc4f8f992e3771751e144bda1938084c70d3001c09"},
{file = "kiwisolver-1.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1858ad3cb686eccc7c6b7c5eac846a1cfd45aacb5811b2cf575e80b208f5622a"},
{file = "kiwisolver-1.4.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dc350cb65fe4e3f737d50f0465fa6ea0dcae0e5722b7edf5d5b0a0e3cd2c3c7"},
{file = "kiwisolver-1.4.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:007799c7fa934646318fc128b033bb6e6baabe7fbad521bfb2279aac26225cd7"},
{file = "kiwisolver-1.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:46fb56fde006b7ef5f8eaa3698299b0ea47444238b869ff3ced1426aa9fedcb5"},
{file = "kiwisolver-1.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b9eb88593159a53a5ee0b0159daee531ff7dd9c87fa78f5d807ca059c7eb1b2b"},
{file = "kiwisolver-1.4.3-cp38-cp38-win32.whl", hash = "sha256:3b1dcbc49923ac3c973184a82832e1f018dec643b1e054867d04a3a22255ec6a"},
{file = "kiwisolver-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:7118ca592d25b2957ff7b662bc0fe4f4c2b5d5b27814b9b1bc9f2fb249a970e7"},
{file = "kiwisolver-1.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:747190fcdadc377263223f8f72b038381b3b549a8a3df5baf4d067da4749b046"},
{file = "kiwisolver-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fd628e63ffdba0112e3ddf1b1e9f3db29dd8262345138e08f4938acbc6d0805a"},
{file = "kiwisolver-1.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:22ccba48abae827a0f952a78a7b1a7ff01866131e5bbe1f826ce9bda406bf051"},
{file = "kiwisolver-1.4.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:af24b21c2283ca69c416a8a42cde9764dc36c63d3389645d28c69b0e93db3cd7"},
{file = "kiwisolver-1.4.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:547111ef7cf13d73546c2de97ce434935626c897bdec96a578ca100b5fcd694b"},
{file = "kiwisolver-1.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84f85adfebd7d3c3db649efdf73659e1677a2cf3fa6e2556a3f373578af14bf7"},
{file = "kiwisolver-1.4.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffd7cf165ff71afb202b3f36daafbf298932bee325aac9f58e1c9cd55838bef0"},
{file = "kiwisolver-1.4.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6b3136eecf7e1b4a4d23e4b19d6c4e7a8e0b42d55f30444e3c529700cdacaa0d"},
{file = "kiwisolver-1.4.3-cp39-cp39-win32.whl", hash = "sha256:46c6e5018ba31d5ee7582f323d8661498a154dea1117486a571db4c244531f24"},
{file = "kiwisolver-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:8395064d63b26947fa2c9faeea9c3eee35e52148c5339c37987e1d96fbf009b3"},
{file = "kiwisolver-1.4.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:325fa1b15098e44fe4590a6c5c09a212ca10c6ebb5d96f7447d675f6c8340e4e"},
{file = "kiwisolver-1.4.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:654280c5f41831ddcc5a331c0e3ce2e480bbc3d7c93c18ecf6236313aae2d61a"},
{file = "kiwisolver-1.4.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ae7aa0784aeadfbd693c27993727792fbe1455b84d49970bad5886b42976b18"},
{file = "kiwisolver-1.4.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:130c6c35eded399d3967cf8a542c20b671f5ba85bd6f210f8b939f868360e9eb"},
{file = "kiwisolver-1.4.3.tar.gz", hash = "sha256:ab8a15c2750ae8d53e31f77a94f846d0a00772240f1c12817411fa2344351f86"},
]
loguru = [
{file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"},
@@ -1653,6 +1726,60 @@ matplotlib = [
{file = "matplotlib-3.5.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:24173c23d1bcbaed5bf47b8785d27933a1ac26a5d772200a0f3e0e38f471b001"},
{file = "matplotlib-3.5.2.tar.gz", hash = "sha256:48cf850ce14fa18067f2d9e0d646763681948487a8080ec0af2686468b4607a2"},
]
msgpack = [
{file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250"},
{file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88"},
{file = "msgpack-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467"},
{file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35bc0faa494b0f1d851fd29129b2575b2e26d41d177caacd4206d81502d4c6a6"},
{file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4733359808c56d5d7756628736061c432ded018e7a1dff2d35a02439043321aa"},
{file = "msgpack-1.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb514ad14edf07a1dbe63761fd30f89ae79b42625731e1ccf5e1f1092950eaa6"},
{file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c23080fdeec4716aede32b4e0ef7e213c7b1093eede9ee010949f2a418ced6ba"},
{file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:49565b0e3d7896d9ea71d9095df15b7f75a035c49be733051c34762ca95bbf7e"},
{file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aca0f1644d6b5a73eb3e74d4d64d5d8c6c3d577e753a04c9e9c87d07692c58db"},
{file = "msgpack-1.0.4-cp310-cp310-win32.whl", hash = "sha256:0dfe3947db5fb9ce52aaea6ca28112a170db9eae75adf9339a1aec434dc954ef"},
{file = "msgpack-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dea20515f660aa6b7e964433b1808d098dcfcabbebeaaad240d11f909298075"},
{file = "msgpack-1.0.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e83f80a7fec1a62cf4e6c9a660e39c7f878f603737a0cdac8c13131d11d97f52"},
{file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c11a48cf5e59026ad7cb0dc29e29a01b5a66a3e333dc11c04f7e991fc5510a9"},
{file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1276e8f34e139aeff1c77a3cefb295598b504ac5314d32c8c3d54d24fadb94c9"},
{file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c9566f2c39ccced0a38d37c26cc3570983b97833c365a6044edef3574a00c08"},
{file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fcb8a47f43acc113e24e910399376f7277cf8508b27e5b88499f053de6b115a8"},
{file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:76ee788122de3a68a02ed6f3a16bbcd97bc7c2e39bd4d94be2f1821e7c4a64e6"},
{file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0a68d3ac0104e2d3510de90a1091720157c319ceeb90d74f7b5295a6bee51bae"},
{file = "msgpack-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:85f279d88d8e833ec015650fd15ae5eddce0791e1e8a59165318f371158efec6"},
{file = "msgpack-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c1683841cd4fa45ac427c18854c3ec3cd9b681694caf5bff04edb9387602d661"},
{file = "msgpack-1.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a75dfb03f8b06f4ab093dafe3ddcc2d633259e6c3f74bb1b01996f5d8aa5868c"},
{file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9667bdfdf523c40d2511f0e98a6c9d3603be6b371ae9a238b7ef2dc4e7a427b0"},
{file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11184bc7e56fd74c00ead4f9cc9a3091d62ecb96e97653add7a879a14b003227"},
{file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac5bd7901487c4a1dd51a8c58f2632b15d838d07ceedaa5e4c080f7190925bff"},
{file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1e91d641d2bfe91ba4c52039adc5bccf27c335356055825c7f88742c8bb900dd"},
{file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2a2df1b55a78eb5f5b7d2a4bb221cd8363913830145fad05374a80bf0877cb1e"},
{file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:545e3cf0cf74f3e48b470f68ed19551ae6f9722814ea969305794645da091236"},
{file = "msgpack-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:2cc5ca2712ac0003bcb625c96368fd08a0f86bbc1a5578802512d87bc592fe44"},
{file = "msgpack-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eba96145051ccec0ec86611fe9cf693ce55f2a3ce89c06ed307de0e085730ec1"},
{file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7760f85956c415578c17edb39eed99f9181a48375b0d4a94076d84148cf67b2d"},
{file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:449e57cc1ff18d3b444eb554e44613cffcccb32805d16726a5494038c3b93dab"},
{file = "msgpack-1.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d603de2b8d2ea3f3bcb2efe286849aa7a81531abc52d8454da12f46235092bcb"},
{file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f5d88c99f64c456413d74a975bd605a9b0526293218a3b77220a2c15458ba9"},
{file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916c78f33602ecf0509cc40379271ba0f9ab572b066bd4bdafd7434dee4bc6e"},
{file = "msgpack-1.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81fc7ba725464651190b196f3cd848e8553d4d510114a954681fd0b9c479d7e1"},
{file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5b5b962221fa2c5d3a7f8133f9abffc114fe218eb4365e40f17732ade576c8e"},
{file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:77ccd2af37f3db0ea59fb280fa2165bf1b096510ba9fe0cc2bf8fa92a22fdb43"},
{file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b17be2478b622939e39b816e0aa8242611cc8d3583d1cd8ec31b249f04623243"},
{file = "msgpack-1.0.4-cp38-cp38-win32.whl", hash = "sha256:2bb8cdf50dd623392fa75525cce44a65a12a00c98e1e37bf0fb08ddce2ff60d2"},
{file = "msgpack-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:26b8feaca40a90cbe031b03d82b2898bf560027160d3eae1423f4a67654ec5d6"},
{file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:462497af5fd4e0edbb1559c352ad84f6c577ffbbb708566a0abaaa84acd9f3ae"},
{file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2999623886c5c02deefe156e8f869c3b0aaeba14bfc50aa2486a0415178fce55"},
{file = "msgpack-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f0029245c51fd9473dc1aede1160b0a29f4a912e6b1dd353fa6d317085b219da"},
{file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed6f7b854a823ea44cf94919ba3f727e230da29feb4a99711433f25800cf747f"},
{file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0df96d6eaf45ceca04b3f3b4b111b86b33785683d682c655063ef8057d61fd92"},
{file = "msgpack-1.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a4192b1ab40f8dca3f2877b70e63799d95c62c068c84dc028b40a6cb03ccd0f"},
{file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e3590f9fb9f7fbc36df366267870e77269c03172d086fa76bb4eba8b2b46624"},
{file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1576bd97527a93c44fa856770197dec00d223b0b9f36ef03f65bac60197cedf8"},
{file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63e29d6e8c9ca22b21846234913c3466b7e4ee6e422f205a2988083de3b08cae"},
{file = "msgpack-1.0.4-cp39-cp39-win32.whl", hash = "sha256:fb62ea4b62bfcb0b380d5680f9a4b3f9a2d166d9394e9bbd9666c0ee09a3645c"},
{file = "msgpack-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce"},
{file = "msgpack-1.0.4.tar.gz", hash = "sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f"},
]
multidict = [
{file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"},
{file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"},
@@ -1719,16 +1846,16 @@ mypy-extensions = [
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
nonebot-adapter-onebot = [
{file = "nonebot-adapter-onebot-2.0.0b1.tar.gz", hash = "sha256:9dad770371e577fead096ceacacc43b3ef304a8e238e8fff1163eefc4e947a75"},
{file = "nonebot_adapter_onebot-2.0.0b1-py3-none-any.whl", hash = "sha256:ca1375de1dd503a5ab20440445026195b587e05a2b18ae8df9b6ab17c9e857b5"},
{file = "nonebot-adapter-onebot-2.1.1.tar.gz", hash = "sha256:d00036883dd8b8685f0eea68b7ada9c3b1ba9de8b39f5c33e81d36a444afe02a"},
{file = "nonebot_adapter_onebot-2.1.1-py3-none-any.whl", hash = "sha256:1a825b21fc7315c11d335276a932811352ac70e7031e86b5595121185c951c77"},
]
nonebot-plugin-apscheduler = [
{file = "nonebot-plugin-apscheduler-0.1.2.tar.gz", hash = "sha256:1765336cd388dde15f723ed12dbca942b04e4c25d5d7786878e447b09e68b909"},
{file = "nonebot_plugin_apscheduler-0.1.2-py3-none-any.whl", hash = "sha256:eed7b9e60d08826ae4919f82dc240fc7ec469185271c2271e14438a3e0ca7692"},
{file = "nonebot-plugin-apscheduler-0.1.3.tar.gz", hash = "sha256:fe11e0fbde56cde12a6f1a50997803a422ea2f085c4e9d496210b03ef9cca585"},
{file = "nonebot_plugin_apscheduler-0.1.3-py3-none-any.whl", hash = "sha256:76456f625089045c9f2f8943e90c009841afd461b9dc51e9de21169bbd1b2677"},
]
nonebot2 = [
{file = "nonebot2-2.0.0b3-py3-none-any.whl", hash = "sha256:00f2ea63d5f2c665428bec4b7a33301f6b1b483d5635d2a3241f0a1ab3b5b2ea"},
{file = "nonebot2-2.0.0b3.tar.gz", hash = "sha256:b7ee6ddf387af268e36f4276c2d94b4f717c1a29078400738ca275c3fb266dd4"},
{file = "nonebot2-2.0.0b4-py3-none-any.whl", hash = "sha256:3029cdb657ec48c6aaa046e1b712e7a0ebe5d0010208dff95b5ccbe461d1ed4e"},
{file = "nonebot2-2.0.0b4.tar.gz", hash = "sha256:fe57242138b3ab7019770566c23f7b39c53e0159b81ec7bd5b34cf6b1ff9eb13"},
]
numpy = [
{file = "numpy-1.22.4-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:ba9ead61dfb5d971d77b6c131a9dbee62294a932bf6a356e48c75ae684e635b3"},
@@ -1755,13 +1882,13 @@ numpy = [
{file = "numpy-1.22.4.zip", hash = "sha256:425b390e4619f58d8526b3dcf656dde069133ae5c240229821f01b5f44ea07af"},
]
opencv-python = [
{file = "opencv-python-4.5.5.64.tar.gz", hash = "sha256:f65de0446a330c3b773cd04ba10345d8ce1b15dcac3f49770204e37602d0b3f7"},
{file = "opencv_python-4.5.5.64-cp36-abi3-macosx_10_15_x86_64.whl", hash = "sha256:a512a0c59b6fec0fac3844b2f47d6ecb1a9d18d235e6c5491ce8dbbe0663eae8"},
{file = "opencv_python-4.5.5.64-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6138b6903910e384067d001763d40f97656875487381aed32993b076f44375"},
{file = "opencv_python-4.5.5.64-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b293ced62f4360d9f11cf72ae7e9df95320ff7bf5b834d87546f844e838c0c35"},
{file = "opencv_python-4.5.5.64-cp36-abi3-win32.whl", hash = "sha256:6247e584813c00c3b9ed69a795da40d2c153dc923d0182e957e1c2f00a554ac2"},
{file = "opencv_python-4.5.5.64-cp36-abi3-win_amd64.whl", hash = "sha256:408d5332550287aa797fd06bef47b2dfed163c6787668cc82ef9123a9484b56a"},
{file = "opencv_python-4.5.5.64-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:7787bb017ae93d5f9bb1b817ac8e13e45dd193743cb648498fcab21d00cf20a3"},
{file = "opencv-python-4.6.0.66.tar.gz", hash = "sha256:c5bfae41ad4031e66bb10ec4a0a2ffd3e514d092652781e8b1ac98d1b59f1158"},
{file = "opencv_python-4.6.0.66-cp36-abi3-macosx_10_15_x86_64.whl", hash = "sha256:e6e448b62afc95c5b58f97e87ef84699e6607fe5c58730a03301c52496005cae"},
{file = "opencv_python-4.6.0.66-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5af8ba35a4fcb8913ffb86e92403e9a656a4bff4a645d196987468f0f8947875"},
{file = "opencv_python-4.6.0.66-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbdc84a9b4ea2cbae33861652d25093944b9959279200b7ae0badd32439f74de"},
{file = "opencv_python-4.6.0.66-cp36-abi3-win32.whl", hash = "sha256:f482e78de6e7b0b060ff994ffd859bddc3f7f382bb2019ef157b0ea8ca8712f5"},
{file = "opencv_python-4.6.0.66-cp36-abi3-win_amd64.whl", hash = "sha256:0dc82a3d8630c099d2f3ac1b1aabee164e8188db54a786abb7a4e27eba309440"},
{file = "opencv_python-4.6.0.66-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:6e32af22e3202748bd233ed8f538741876191863882eba44e332d1a34993165b"},
]
packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
@@ -1828,6 +1955,32 @@ proces = [
{file = "proces-0.1.2-py3-none-any.whl", hash = "sha256:82b765c70ebe790aae03159617710d03bcec3c98d6c7190f126bf307eecd0fd3"},
{file = "proces-0.1.2.tar.gz", hash = "sha256:99fc87148aff66fb0ca83b66562d6c61b2a2ba4bdff7c9eec64c02df7917d51f"},
]
protobuf = [
{file = "protobuf-3.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996"},
{file = "protobuf-3.20.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3"},
{file = "protobuf-3.20.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde"},
{file = "protobuf-3.20.1-cp310-cp310-win32.whl", hash = "sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c"},
{file = "protobuf-3.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7"},
{file = "protobuf-3.20.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153"},
{file = "protobuf-3.20.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f"},
{file = "protobuf-3.20.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20"},
{file = "protobuf-3.20.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531"},
{file = "protobuf-3.20.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e"},
{file = "protobuf-3.20.1-cp37-cp37m-win32.whl", hash = "sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c"},
{file = "protobuf-3.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067"},
{file = "protobuf-3.20.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf"},
{file = "protobuf-3.20.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab"},
{file = "protobuf-3.20.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c"},
{file = "protobuf-3.20.1-cp38-cp38-win32.whl", hash = "sha256:dd5789b2948ca702c17027c84c2accb552fc30f4622a98ab5c51fcfe8c50d3e7"},
{file = "protobuf-3.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739"},
{file = "protobuf-3.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7"},
{file = "protobuf-3.20.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f"},
{file = "protobuf-3.20.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9"},
{file = "protobuf-3.20.1-cp39-cp39-win32.whl", hash = "sha256:db977c4ca738dd9ce508557d4fce0f5aebd105e158c725beec86feb1f6bc20d8"},
{file = "protobuf-3.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91"},
{file = "protobuf-3.20.1-py2.py3-none-any.whl", hash = "sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388"},
{file = "protobuf-3.20.1.tar.gz", hash = "sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9"},
]
psutil = [
{file = "psutil-5.9.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:799759d809c31aab5fe4579e50addf84565e71c1dc9f1c31258f159ff70d3f87"},
{file = "psutil-5.9.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9272167b5f5fbfe16945be3db475b3ce8d792386907e673a209da686176552af"},
@@ -2226,8 +2379,8 @@ tomli = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
tomlkit = [
{file = "tomlkit-0.10.2-py3-none-any.whl", hash = "sha256:905cf92c2111ef80d355708f47ac24ad1b6fc2adc5107455940088c9bbecaedb"},
{file = "tomlkit-0.10.2.tar.gz", hash = "sha256:30d54c0b914e595f3d10a87888599eab5321a2a69abc773bbefff51599b72db6"},
{file = "tomlkit-0.11.0-py3-none-any.whl", hash = "sha256:0f4050db66fd445b885778900ce4dd9aea8c90c4721141fde0d6ade893820ef1"},
{file = "tomlkit-0.11.0.tar.gz", hash = "sha256:71ceb10c0eefd8b8f11fe34e8a51ad07812cb1dc3de23247425fbc9ddc47b9dd"},
]
typing-extensions = [
{file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"},
+2 -2
View File
@@ -19,7 +19,7 @@ aiohttp = "3.7.4.post0"
beautifulsoup4 = "4.9.3"
feedparser = "^6.0.8"
gino = "^1.0.1"
httpx = "^0.22.0"
httpx = "^0.23.0"
ImageHash = "^4.2.1"
jieba = "^0.42.1"
lxml = "4.6.5"
@@ -39,7 +39,7 @@ dateparser = "^1.1.0"
cn2an = "^0.5.16"
python-jose = "^3.3.0"
python-multipart = "^0.0.5"
bilireq = "^0.1.2"
bilireq = "^0.2.0"
emoji = "^1.7.0"
wordcloud = "^1.8.1"
rich = "^12.4.3"
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

+2 -1
View File
@@ -10,7 +10,8 @@
"poetry.lock",
"pyproject.toml",
"resources/font",
"bot.py"
"resources/image/zhenxun",
"resources/image/other"
],
"add_file": [],
"delete_file": []
+5 -13
View File
@@ -1,13 +1,8 @@
import asyncio
from typing import Optional
from nonebot.log import logger
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()
_browser: Optional[Browser] = None
@@ -15,16 +10,14 @@ _browser: Optional[Browser] = None
async def init(**kwargs) -> Optional[Browser]:
global _browser
browser = await async_playwright().start()
try:
browser = await async_playwright().start()
_browser = await browser.chromium.launch(**kwargs)
return _browser
except NotImplementedError:
logger.warning("win环境下 初始化playwright失败,相关功能将被限制....")
except Exception as e:
logger.warning(f"启动chromium发生错误 {type(e)}:{e}")
if _browser:
await _browser.close()
# logger.warning(f"启动chromium发生错误 {type(e)}:{e}")
await asyncio.get_event_loop().run_in_executor(None, install)
_browser = await browser.chromium.launch(**kwargs)
return None
@@ -32,7 +25,6 @@ async def get_browser(**kwargs) -> Browser:
return _browser or await init(**kwargs)
# @driver.on_startup
def install():
"""自动安装、更新 Chromium"""
logger.info("正在检查 Chromium 更新")
+2 -2
View File
@@ -10,9 +10,9 @@ async def init_rank(
title: str, all_user_id: List[int], all_user_data: List[int], group_id: int, total_count: int = 10
) -> BuildMat:
"""
说明:
说明:
初始化通用的数据排行榜
参数:
参数:
:param title: 排行榜标题
:param all_user_id: 所有用户的qq号
:param all_user_data: 所有用户需要排行的对应数据
+30 -4
View File
@@ -20,12 +20,15 @@ class ShopRegister(dict):
discount: Tuple[float, ...],
limit_time: Tuple[int, ...],
load_status: Tuple[bool, ...],
daily_limit: Tuple[int, ...],
**kwargs,
):
def add_register_item(func: Callable):
if name in self._data.keys():
raise ValueError("该商品已注册,请替换其他名称!")
for n, p, d, dd, l, s in zip(name, price, des, discount, limit_time, load_status):
for n, p, d, dd, l, s, dl in zip(
name, price, des, discount, limit_time, load_status, daily_limit
):
if s:
_temp_kwargs = {}
for key, value in kwargs.items():
@@ -38,6 +41,7 @@ class ShopRegister(dict):
"des": d,
"discount": dd,
"limit_time": l,
"daily_limit": dl,
"func": func,
"kwargs": _temp_kwargs,
}
@@ -52,7 +56,12 @@ class ShopRegister(dict):
self._flag = False
for name in self._data.keys():
await shop.register_goods(
name, self._data[name]["price"], self._data[name]["des"], self._data[name]["discount"], self._data[name]["limit_time"]
name,
self._data[name]["price"],
self._data[name]["des"],
self._data[name]["discount"],
self._data[name]["limit_time"],
self._data[name]["daily_limit"],
)
use.register_use(
name, self._data[name]["func"], **self._data[name]["kwargs"]
@@ -66,6 +75,7 @@ class ShopRegister(dict):
discount: Union[float, Tuple[float, ...]] = 1,
limit_time: Union[int, Tuple[int, ...]] = 0,
load_status: Union[bool, Tuple[bool, ...]] = True,
daily_limit: Union[int, Tuple[int, ...]] = 0,
**kwargs,
):
_tuple_list = []
@@ -75,7 +85,9 @@ class ShopRegister(dict):
if _current_len == -1:
_current_len = len(x)
if _current_len != len(x):
raise ValueError(f"注册商品 {name} 中 name,price,des,discount,limit_time,load_status 数量不符!")
raise ValueError(
f"注册商品 {name} 中 name,price,des,discount,limit_time,load_status,daily_limit 数量不符!"
)
_current_len = _current_len if _current_len > -1 else 1
_name = name if isinstance(name, tuple) else (name,)
_price = (
@@ -101,7 +113,21 @@ class ShopRegister(dict):
if isinstance(load_status, tuple)
else tuple([load_status for _ in range(_current_len)])
)
return self.register(_name, _price, _des, _discount, _limit_time, _load_status, **kwargs)
_daily_limit = (
daily_limit
if isinstance(daily_limit, tuple)
else tuple([daily_limit for _ in range(_current_len)])
)
return self.register(
_name,
_price,
_des,
_discount,
_limit_time,
_load_status,
_daily_limit,
**kwargs,
)
def __setitem__(self, key, value):
self._data[key] = value
+35 -18
View File
@@ -6,7 +6,7 @@ from pathlib import Path
from httpx import Response
from asyncio.exceptions import TimeoutError
from nonebot.adapters.onebot.v11 import MessageSegment
from playwright.async_api import Page
from playwright.async_api import Page, BrowserContext
from .message_builder import image
from httpx import ConnectTimeout
from .browser import get_browser
@@ -30,15 +30,16 @@ class AsyncHttpx:
params: Optional[Dict[str, Any]] = None,
headers: Optional[Dict[str, str]] = None,
cookies: Optional[Dict[str, str]] = None,
verify: bool = True,
use_proxy: bool = True,
proxy: Dict[str, str] = None,
timeout: Optional[int] = 30,
**kwargs,
) -> Response:
"""
说明:
说明:
Get
参数:
参数:
:param url: url
:param params: params
:param headers: 请求头
@@ -50,7 +51,7 @@ class AsyncHttpx:
if not headers:
headers = get_user_agent()
proxy = proxy if proxy else cls.proxy if use_proxy else None
async with httpx.AsyncClient(proxies=proxy) as client:
async with httpx.AsyncClient(proxies=proxy, verify=verify) as client:
return await client.get(
url,
params=params,
@@ -68,6 +69,7 @@ class AsyncHttpx:
data: Optional[Dict[str, str]] = None,
content: Any = None,
files: Any = None,
verify: bool = True,
use_proxy: bool = True,
proxy: Dict[str, str] = None,
json: Optional[Dict[str, Union[Any]]] = None,
@@ -78,9 +80,9 @@ class AsyncHttpx:
**kwargs,
) -> Response:
"""
说明:
说明:
Post
参数:
参数:
:param url: url
:param data: data
:param content: content
@@ -96,7 +98,7 @@ class AsyncHttpx:
if not headers:
headers = get_user_agent()
proxy = proxy if proxy else cls.proxy if use_proxy else None
async with httpx.AsyncClient(proxies=proxy) as client:
async with httpx.AsyncClient(proxies=proxy, verify=verify) as client:
return await client.post(
url,
content=content,
@@ -117,6 +119,7 @@ class AsyncHttpx:
path: Union[str, Path],
*,
params: Optional[Dict[str, str]] = None,
verify: bool = True,
use_proxy: bool = True,
proxy: Dict[str, str] = None,
headers: Optional[Dict[str, str]] = None,
@@ -126,12 +129,13 @@ class AsyncHttpx:
**kwargs,
) -> bool:
"""
说明:
说明:
下载文件
参数:
参数:
:param url: url
:param path: 存储路径
:param params: params
:param verify: verify
:param use_proxy: 使用代理
:param proxy: 指定代理
:param headers: 请求头
@@ -169,7 +173,7 @@ class AsyncHttpx:
headers = get_user_agent()
proxy = proxy if proxy else cls.proxy if use_proxy else None
try:
async with httpx.AsyncClient(proxies=proxy) as client:
async with httpx.AsyncClient(proxies=proxy, verify=verify) as client:
async with client.stream(
"GET",
url,
@@ -220,9 +224,9 @@ class AsyncHttpx:
**kwargs,
) -> List[bool]:
"""
说明:
说明:
分组同时下载文件
参数:
参数:
:param url_list: url列表
:param path_list: 存储路径列表
:param limit_async_number: 限制同时请求数量
@@ -284,9 +288,9 @@ class AsyncPlaywright:
@classmethod
async def _new_page(cls, user_agent: Optional[str] = None, **kwargs) -> Page:
"""
说明:
说明:
获取一个新页面
参数:
参数:
:param user_agent: 请求头
"""
browser = await get_browser()
@@ -294,6 +298,19 @@ class AsyncPlaywright:
return await browser.new_page(user_agent=user_agent, **kwargs)
raise BrowserIsNone("获取Browser失败...")
@classmethod
async def new_context(cls, user_agent: Optional[str] = None, **kwargs) -> BrowserContext:
"""
说明:
获取一个新上下文
参数:
:param user_agent: 请求头
"""
browser = await get_browser()
if browser:
return await browser.new_context(user_agent=user_agent, **kwargs)
raise BrowserIsNone("获取Browser失败...")
@classmethod
async def goto(
cls,
@@ -307,9 +324,9 @@ class AsyncPlaywright:
**kwargs
) -> Optional[Page]:
"""
说明:
说明:
goto
参数:
参数:
:param url: 网址
:param timeout: 超时限制
:param wait_until: 等待类型
@@ -343,9 +360,9 @@ class AsyncPlaywright:
**kwargs
) -> Optional[MessageSegment]:
"""
说明:
说明:
截图,该方法仅用于简单快捷截图,复杂截图请操作 page
参数:
参数:
:param url: 网址
:param path: 存储路径
:param element: 元素选择
+127 -119
View File
@@ -14,6 +14,8 @@ from imagehash import ImageHash
from matplotlib import pyplot as plt
from PIL import Image, ImageDraw, ImageFile, ImageFilter, ImageFont
from services import logger
ImageFile.LOAD_TRUNCATED_IMAGES = True
Image.MAX_IMAGE_PIXELS = None
@@ -22,9 +24,9 @@ def compare_image_with_hash(
image_file1: str, image_file2: str, max_dif: int = 1.5
) -> bool:
"""
说明:
说明:
比较两张图片的hash值是否相同
参数:
参数:
:param image_file1: 图片文件路径
:param image_file2: 图片文件路径
:param max_dif: 允许最大hash差值, 越小越精确,最小为0
@@ -43,9 +45,9 @@ def compare_image_with_hash(
def get_img_hash(image_file: Union[str, Path]) -> ImageHash:
"""
说明:
说明:
获取图片的hash值
参数:
参数:
:param image_file: 图片文件路径
"""
with open(image_file, "rb") as fp:
@@ -57,9 +59,9 @@ def compressed_image(
in_file: Union[str, Path], out_file: Union[str, Path] = None, ratio: float = 0.9
):
"""
说明:
说明:
压缩图片
参数:
参数:
:param in_file: 被压缩的文件路径
:param out_file: 压缩后输出的文件路径
:param ratio: 压缩率,宽高 * 压缩率
@@ -78,9 +80,9 @@ def compressed_image(
def alpha2white_pil(pic: Image) -> Image:
"""
说明:
说明:
将图片透明背景转化为白色
参数:
参数:
:param pic: 通过PIL打开的图片文件
"""
img = pic.convert("RGBA")
@@ -97,9 +99,9 @@ def alpha2white_pil(pic: Image) -> Image:
def pic2b64(pic: Image) -> str:
"""
说明:
说明:
PIL图片转base64
参数:
参数:
:param pic: 通过PIL打开的图片文件
"""
buf = BytesIO()
@@ -110,9 +112,9 @@ def pic2b64(pic: Image) -> str:
def fig2b64(plt_: plt) -> str:
"""
说明:
说明:
matplotlib图片转base64
参数:
参数:
:param plt_: matplotlib生成的图片
"""
buf = BytesIO()
@@ -123,9 +125,9 @@ def fig2b64(plt_: plt) -> str:
def is_valid(file: Union[str, Path]) -> bool:
"""
说明:
说明:
判断图片是否损坏
参数:
参数:
:param file: 图片文件路径
"""
valid = True
@@ -158,7 +160,7 @@ class BuildImage:
font_color: Optional[Union[str, Tuple[int, int, int]]] = None,
):
"""
参数:
参数:
:param w: 自定义图片的宽度,w=0时为图片原本宽度
:param h: 自定义图片的高度,h=0时为图片原本高度
:param paste_image_width: 当图片做为背景图时,设置贴图的宽度,用于贴图自动换行
@@ -178,7 +180,7 @@ class BuildImage:
self.paste_image_height = int(paste_image_height)
self.current_w = 0
self.current_h = 0
self.font = ImageFont.truetype(str(FONT_PATH / font), font_size)
self.font = ImageFont.truetype(str(FONT_PATH / font), int(font_size))
if not plain_text and not color:
color = (255, 255, 255)
self.background = background
@@ -209,13 +211,16 @@ class BuildImage:
(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)
try:
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)
except Exception as e:
logger.warning(f"背景透明化发生错误..{type(e)}:{e}")
self.draw = ImageDraw.Draw(self.markImg)
self.size = self.w, self.h
if plain_text:
@@ -236,9 +241,9 @@ class BuildImage:
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
):
"""
说明:
说明:
异步 贴图
参数:
参数:
:param img: 已打开的图片文件,可以为 BuildImage 或 Image
:param pos: 贴图位置(左上角)
:param alpha: 图片背景是否为透明
@@ -254,9 +259,9 @@ class BuildImage:
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
):
"""
说明:
说明:
贴图
参数:
参数:
:param img: 已打开的图片文件,可以为 BuildImage 或 Image
:param pos: 贴图位置(左上角)
:param alpha: 图片背景是否为透明
@@ -299,9 +304,9 @@ class BuildImage:
def getsize(self, msg: str) -> Tuple[int, int]:
"""
说明:
说明:
获取文字在该图片 font_size 下所需要的空间
参数:
参数:
:param msg: 文字内容
"""
return self.font.getsize(msg)
@@ -310,9 +315,9 @@ class BuildImage:
self, pos: Tuple[int, int], fill: Optional[Tuple[int, int, int]] = None
):
"""
说明:
说明:
异步 绘制多个或单独的像素
参数:
参数:
:param pos: 坐标
:param fill: 填错颜色
"""
@@ -320,9 +325,9 @@ class BuildImage:
def point(self, pos: Tuple[int, int], fill: Optional[Tuple[int, int, int]] = None):
"""
说明:
说明:
绘制多个或单独的像素
参数:
参数:
:param pos: 坐标
:param fill: 填错颜色
"""
@@ -336,9 +341,9 @@ class BuildImage:
width: int = 1,
):
"""
说明:
说明:
异步 绘制圆
参数:
参数:
:param pos: 坐标范围
:param fill: 填充颜色
:param outline: 描线颜色
@@ -354,9 +359,9 @@ class BuildImage:
width: int = 1,
):
"""
说明:
说明:
绘制圆
参数:
参数:
:param pos: 坐标范围
:param fill: 填充颜色
:param outline: 描线颜色
@@ -372,9 +377,9 @@ class BuildImage:
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
):
"""
说明:
说明:
异步 在图片上添加文字
参数:
参数:
:param pos: 文字位置
:param text: 文字内容
:param fill: 文字颜色
@@ -390,9 +395,9 @@ class BuildImage:
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
):
"""
说明:
说明:
在图片上添加文字
参数:
参数:
:param pos: 文字位置
:param text: 文字内容
:param fill: 文字颜色
@@ -419,18 +424,18 @@ class BuildImage:
async def asave(self, path: Optional[Union[str, Path]] = None):
"""
说明:
说明:
异步 保存图片
参数:
参数:
:param path: 图片路径
"""
await self.loop.run_in_executor(None, self.save, path)
def save(self, path: Optional[Union[str, Path]] = None):
"""
说明:
说明:
保存图片
参数:
参数:
:param path: 图片路径
"""
if not path:
@@ -439,16 +444,16 @@ class BuildImage:
def show(self):
"""
说明:
说明:
显示图片
"""
self.markImg.show(self.markImg)
async def aresize(self, ratio: float = 0, w: int = 0, h: int = 0):
"""
说明:
说明:
异步 压缩图片
参数:
参数:
:param ratio: 压缩倍率
:param w: 压缩图片宽度至 w
:param h: 压缩图片高度至 h
@@ -457,9 +462,9 @@ class BuildImage:
def resize(self, ratio: float = 0, w: int = 0, h: int = 0):
"""
说明:
说明:
压缩图片
参数:
参数:
:param ratio: 压缩倍率
:param w: 压缩图片宽度至 w
:param h: 压缩图片高度至 h
@@ -476,18 +481,18 @@ class BuildImage:
async def acrop(self, box: Tuple[int, int, int, int]):
"""
说明:
说明:
异步 裁剪图片
参数:
参数:
:param box: 左上角坐标,右下角坐标 (left, upper, right, lower)
"""
await self.loop.run_in_executor(None, self.crop, box)
def crop(self, box: Tuple[int, int, int, int]):
"""
说明:
说明:
裁剪图片
参数:
参数:
:param box: 左上角坐标,右下角坐标 (left, upper, right, lower)
"""
self.markImg = self.markImg.crop(box)
@@ -497,18 +502,18 @@ class BuildImage:
def check_font_size(self, word: str) -> bool:
"""
说明:
说明:
检查文本所需宽度是否大于图片宽度
参数:
参数:
:param word: 文本内容
"""
return self.font.getsize(word)[0] > self.w
async def atransparent(self, alpha_ratio: float = 1, n: int = 0):
"""
说明:
说明:
异步 图片透明化
参数:
参数:
:param alpha_ratio: 透明化程度
:param n: 透明化大小内边距
"""
@@ -516,9 +521,9 @@ class BuildImage:
def transparent(self, alpha_ratio: float = 1, n: int = 0):
"""
说明:
说明:
图片透明化
参数:
参数:
:param alpha_ratio: 透明化程度
:param n: 透明化大小内边距
"""
@@ -533,7 +538,7 @@ class BuildImage:
def pic2bs4(self) -> str:
"""
说明:
说明:
BuildImage 转 base64
"""
buf = BytesIO()
@@ -543,9 +548,9 @@ class BuildImage:
def convert(self, type_: str):
"""
说明:
说明:
修改图片类型
参数:
参数:
:param type_: 类型
"""
self.markImg = self.markImg.convert(type_)
@@ -558,9 +563,9 @@ class BuildImage:
width: int = 1,
):
"""
说明:
说明:
异步 画框
参数:
参数:
:param xy: 坐标
:param fill: 填充颜色
:param outline: 轮廓颜色
@@ -576,9 +581,9 @@ class BuildImage:
width: int = 1,
):
"""
说明:
说明:
画框
参数:
参数:
:param xy: 坐标
:param fill: 填充颜色
:param outline: 轮廓颜色
@@ -595,7 +600,7 @@ class BuildImage:
"""
说明:
异步 画多边形
参数:
参数:
:param xy: 坐标
:param fill: 颜色
:param outline: 线宽
@@ -611,7 +616,7 @@ class BuildImage:
"""
说明:
画多边形
参数:
参数:
:param xy: 坐标
:param fill: 颜色
:param outline: 线宽
@@ -625,9 +630,9 @@ class BuildImage:
width: int = 1,
):
"""
说明:
说明:
异步 画线
参数:
参数:
:param xy: 坐标
:param fill: 填充
:param width: 线宽
@@ -641,9 +646,9 @@ class BuildImage:
width: int = 1,
):
"""
说明:
说明:
画线
参数:
参数:
:param xy: 坐标
:param fill: 填充
:param width: 线宽
@@ -652,14 +657,14 @@ class BuildImage:
async def acircle(self):
"""
说明:
说明:
异步 将 BuildImage 图片变为圆形
"""
await self.loop.run_in_executor(None, self.circle)
def circle(self):
"""
说明:
说明:
使图像变圆
"""
self.markImg.convert("RGBA")
@@ -681,22 +686,25 @@ class BuildImage:
right, bottom = [(value - offset) * antialias for value in ellipse_box[2:]]
draw.ellipse([left, top, right, bottom], fill=fill)
mask = mask.resize(self.markImg.size, Image.LANCZOS)
self.markImg.putalpha(mask)
try:
self.markImg.putalpha(mask)
except ValueError:
pass
async def acircle_corner(self, radii: int = 30):
"""
说明:
说明:
异步 矩形四角变圆
参数:
参数:
:param radii: 半径
"""
await self.loop.run_in_executor(None, self.circle_corner, radii)
def circle_corner(self, radii: int = 30):
"""
说明:
说明:
矩形四角变圆
参数:
参数:
:param radii: 半径
"""
# 画圆(用于分离4个角)
@@ -716,9 +724,9 @@ class BuildImage:
async def arotate(self, angle: int, expand: bool = False):
"""
说明:
说明:
异步 旋转图片
参数:
参数:
:param angle: 角度
:param expand: 放大图片适应角度
"""
@@ -726,9 +734,9 @@ class BuildImage:
def rotate(self, angle: int, expand: bool = False):
"""
说明:
说明:
旋转图片
参数:
参数:
:param angle: 角度
:param expand: 放大图片适应角度
"""
@@ -736,27 +744,27 @@ class BuildImage:
async def atranspose(self, angle: int):
"""
说明:
说明:
异步 旋转图片(包括边框)
参数:
参数:
:param angle: 角度
"""
await self.loop.run_in_executor(None, self.transpose, angle)
def transpose(self, angle: int):
"""
说明:
说明:
旋转图片(包括边框)
参数:
参数:
:param angle: 角度
"""
self.markImg.transpose(angle)
async def afilter(self, filter_: str, aud: int = None):
"""
说明:
说明:
异步 图片变化
参数:
参数:
:param filter_: 变化效果
:param aud: 利率
"""
@@ -764,9 +772,9 @@ class BuildImage:
def filter(self, filter_: str, aud: int = None):
"""
说明:
说明:
图片变化
参数:
参数:
:param filter_: 变化效果
:param aud: 利率
"""
@@ -796,9 +804,9 @@ class BuildImage:
replace_color: Tuple[int, int, int],
):
"""
说明:
说明:
异步 颜色替换
参数:
参数:
:param src_color: 目标颜色,或者使用列表,设置阈值
:param replace_color: 替换颜色
"""
@@ -814,9 +822,9 @@ class BuildImage:
replace_color: Tuple[int, int, int],
):
"""
说明:
说明:
颜色替换
参数:
参数:
:param src_color: 目标颜色,或者使用元祖,设置阈值
:param replace_color: 替换颜色
"""
@@ -872,9 +880,9 @@ class BuildMat:
bar_color: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
):
"""
说明:
说明:
初始化 BuildMat
参数:
参数:
:param y: 坐标值
:param mat_type: 图像类型 可能的值:[line]: 折线图,[bar]: 柱状图,[barh]: 横向柱状图
:param x_name: 横坐标名称
@@ -973,7 +981,7 @@ class BuildMat:
"""
说明:
给坐标点设置新值
参数:
参数:
:param y: 坐标点
"""
self._check_value(y, self.y_index)
@@ -983,7 +991,7 @@ class BuildMat:
"""
说明:
设置y轴坐标值
参数:
参数:
:param y_index: y轴坐标值
"""
self._check_value(self.y, y_index)
@@ -991,9 +999,9 @@ class BuildMat:
def set_title(self, title: str, color: Optional[Union[str, Tuple[int, int, int]]]):
"""
说明:
说明:
设置标题
参数:
参数:
:param title: 标题
:param color: 字体颜色
"""
@@ -1005,9 +1013,9 @@ class BuildMat:
self, background: Optional[List[str]], type_: Optional[str] = None
):
"""
说明:
说明:
设置背景图片
参数:
参数:
:param background: 图片路径列表
:param type_: 填充类型
"""
@@ -1016,32 +1024,32 @@ class BuildMat:
def show(self):
"""
说明:
说明:
展示图像
"""
self.markImg.show()
def pic2bs4(self) -> str:
"""
说明:
说明:
转base64
"""
return self.markImg.pic2bs4()
def resize(self, ratio: float = 0.9):
"""
说明:
说明:
调整图像大小
参数:
参数:
:param ratio: 比例
"""
self.markImg.resize(ratio)
def save(self, path: Union[str, Path]):
"""
说明:
说明:
保存图片
参数:
参数:
:param path: 路径
"""
self.markImg.save(path)
@@ -1055,7 +1063,7 @@ class BuildMat:
"""
说明:
检查值合法性
参数:
参数:
:param y: 坐标值
:param y_index: y轴坐标值
:param x_index: x轴坐标值
@@ -1079,7 +1087,7 @@ class BuildMat:
"""
说明:
生成折线图
参数:
参数:
:param y: 坐标点
:param display_num: 显示该点的值
"""
@@ -1126,9 +1134,9 @@ class BuildMat:
is_barh: bool = False,
):
"""
说明:
说明:
生成柱状图
参数:
参数:
:param y: 坐标值
:param display_num: 是否显示数值
:param is_barh: 横柱状图
@@ -1208,9 +1216,9 @@ class BuildMat:
is_grid: bool = False,
) -> BuildImage:
"""
说明:
说明:
初始化图像,生成xy轴
参数:
参数:
:param x_name: x轴名称
:param y_name: y轴名称
:param x_index: x轴坐标值
@@ -1339,7 +1347,7 @@ async def text2image(
_add_height: float = 0,
) -> BuildImage:
"""
说明:
说明:
解析文本并转为图片
使用标签
<f> </f>
@@ -1351,7 +1359,7 @@ async def text2image(
在不在,<f font=YSHaoShenTi-2.ttf font_size=30 font_color=red>HibiKi小姐</f>,
你最近还好吗,<f font_size=15 font_color=black>我非常想你</f>,这段时间我非常不好过,
<f font_size=25>抽卡抽不到金色</f>,这让我很痛苦
参数:
参数:
:param text: 文本
:param auto_parse: 是否自动解析,否则原样发送
:param font_size: 普通字体大小
@@ -1499,7 +1507,7 @@ async def text2image(
w, _ = _tmp.getsize(x.strip() or "正")
height += h + line_height
width = width if width > w else w
image_list.append(BuildImage(w, h, font=font, font_size=font_size, plain_text=x.strip()))
image_list.append(BuildImage(w, h, font=font, font_size=font_size, plain_text=x.strip(), color=color))
width += pw
height += ph
A = BuildImage(
+12 -7
View File
@@ -1,10 +1,11 @@
from typing import Union, Optional
from pathlib import Path
from ruamel.yaml import YAML
from ruamel import yaml
import ujson as json
import copy
yaml = YAML(typ="safe")
_yaml = YAML(typ="safe")
class StaticData:
@@ -26,16 +27,17 @@ class StaticData:
if f.read().strip():
raise ValueError(f"{file} 文件加载错误,请检查文件内容格式.")
elif file.name.endswith("yaml"):
self._data = yaml.load(f)
self._data = _yaml.load(f)
def set(self, key, value):
self._data[key] = value
self.save()
def set_module_data(self, module, key, value):
def set_module_data(self, module, key, value, auto_save: bool = True):
if module in self._data.keys():
self._data[module][key] = value
self.save()
if auto_save:
self.save()
def get(self, key):
return self._data.get(key)
@@ -51,19 +53,22 @@ class StaticData:
return copy.deepcopy(self._data)
def save(self, path: Union[str, Path] = None):
path = path if path else self.file
path = path or self.file
if isinstance(path, str):
path = Path(path)
if path:
with open(path, "w", encoding="utf8") as f:
json.dump(self._data, f, ensure_ascii=False, indent=4)
if path.name.endswith("yaml"):
yaml.dump(self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True)
else:
json.dump(self._data, f, ensure_ascii=False, indent=4)
def reload(self):
if self.file.exists():
if self.file.name.endswith("json"):
self._data: dict = json.load(open(self.file, "r", encoding="utf8"))
elif self.file.name.endswith("yaml"):
self._data: dict = yaml.load(open(self.file, "r", encoding="utf8"))
self._data: dict = _yaml.load(open(self.file, "r", encoding="utf8"))
def is_exists(self):
return self.file.exists()
+44 -44
View File
@@ -31,9 +31,9 @@ class GroupManager(StaticData):
def block_plugin(self, module: str, group_id: int):
"""
说明:
说明:
锁定插件
参数:
参数:
:param module: 功能模块名
:param group_id: 群组,None时为超级用户禁用
"""
@@ -41,9 +41,9 @@ class GroupManager(StaticData):
def unblock_plugin(self, module: str, group_id: int):
"""
说明:
说明:
解锁插件
参数:
参数:
:param module: 功能模块名
:param group_id: 群组
"""
@@ -51,27 +51,27 @@ class GroupManager(StaticData):
def turn_on_group_bot_status(self, group_id: int):
"""
说明:
说明:
开启群bot开关
参数:
参数:
:param group_id: 群号
"""
self._set_group_bot_status(group_id, True)
def shutdown_group_bot_status(self, group_id: int):
"""
说明:
说明:
关闭群bot开关
参数:
参数:
:param group_id: 群号
"""
self._set_group_bot_status(group_id, False)
def check_group_bot_status(self, group_id: int) -> bool:
"""
说明:
说明:
检查群聊bot总开关状态
参数:
参数:
:param group_id: 说明
"""
group_id = str(group_id)
@@ -86,9 +86,9 @@ class GroupManager(StaticData):
def set_group_level(self, group_id: int, level: int):
"""
说明:
说明:
设置群权限
参数:
参数:
:param group_id: 群组
:param level: 权限等级
"""
@@ -100,9 +100,9 @@ class GroupManager(StaticData):
def get_plugin_status(self, module: str, group_id: int) -> bool:
"""
说明:
说明:
获取插件状态
参数:
参数:
:param module: 功能模块名
:param group_id: 群组
"""
@@ -116,9 +116,9 @@ class GroupManager(StaticData):
def get_group_level(self, group_id: int) -> int:
"""
说明:
说明:
获取群等级
参数:
参数:
:param group_id: 群号
"""
group_id = str(group_id)
@@ -128,18 +128,18 @@ class GroupManager(StaticData):
def check_group_is_white(self, group_id: int) -> bool:
"""
说明:
说明:
检测群聊是否在白名单
参数:
参数:
:param group_id: 群号
"""
return group_id in self._data["super"]["white_group_list"]
def add_group_white_list(self, group_id: int):
"""
说明:
说明:
将群聊加入白名单
参数:
参数:
:param group_id: 群号
"""
if group_id not in self._data["super"]["white_group_list"]:
@@ -147,9 +147,9 @@ class GroupManager(StaticData):
def delete_group_white_list(self, group_id: int):
"""
说明:
说明:
将群聊从白名单中删除
参数:
参数:
:param group_id: 群号
"""
if group_id in self._data["super"]["white_group_list"]:
@@ -157,16 +157,16 @@ class GroupManager(StaticData):
def get_group_white_list(self) -> List[str]:
"""
说明:
说明:
获取所有群白名单
"""
return self._data["super"]["white_group_list"]
def delete_group(self, group_id: int):
"""
说明:
说明:
删除群配置
参数:
参数:
:param group_id: 群号
"""
if group_id in self._data["group_manager"]:
@@ -177,9 +177,9 @@ class GroupManager(StaticData):
async def open_group_task(self, group_id: int, task: str):
"""
说明:
说明:
开启群被动技能
参数:
参数:
:param group_id: 群号
:param task: 被动技能名称
"""
@@ -187,9 +187,9 @@ class GroupManager(StaticData):
async def close_group_task(self, group_id: int, task: str):
"""
说明:
说明:
关闭群被动技能
参数:
参数:
:param group_id: 群号
:param task: 被动技能名称
"""
@@ -197,9 +197,9 @@ class GroupManager(StaticData):
async def check_group_task_status(self, group_id: int, task: str) -> bool:
"""
说明:
说明:
查看群被动技能状态
参数:
参数:
:param group_id: 群号
:param task: 被动技能名称
"""
@@ -214,16 +214,16 @@ class GroupManager(StaticData):
def get_task_data(self) -> Dict[str, str]:
"""
说明:
说明:
获取所有被动任务
"""
return self._task
async def group_task_status(self, group_id: int) -> str:
"""
说明:
说明:
查看群被全部动技能状态
参数:
参数:
:param group_id: 群号
"""
x = "[群被动技能]:\n"
@@ -236,9 +236,9 @@ class GroupManager(StaticData):
async def _set_group_task_status(self, group_id: int, task: str, status: bool):
"""
说明:
说明:
管理群被动技能状态
参数:
参数:
:param group_id: 群号
:param task: 被动技能
:param status: 状态
@@ -257,7 +257,7 @@ class GroupManager(StaticData):
async def init_group_task(self, group_id: Optional[Union[int, str]] = None):
"""
说明:
说明:
初始化群聊 被动技能 状态
"""
if not self._task:
@@ -313,9 +313,9 @@ class GroupManager(StaticData):
group_id: int,
):
"""
说明:
说明:
设置功能开关状态
参数:
参数:
:param module: 功能模块名
:param status: 功能状态
:param group_id: 群组
@@ -333,9 +333,9 @@ class GroupManager(StaticData):
def _init_group(self, group_id: str):
"""
说明:
说明:
初始化群数据
参数:
参数:
:param group_id: 群号
"""
default_group_level = Config.get_config("group_manager", "DEFAULT_GROUP_LEVEL")
@@ -354,9 +354,9 @@ class GroupManager(StaticData):
def _set_group_bot_status(self, group_id: Union[int, str], status: bool):
"""
说明:
说明:
设置群聊bot总开关
参数:
参数:
:param group_id: 群号
:param status: 开关状态
"""
@@ -368,7 +368,7 @@ class GroupManager(StaticData):
def get_super_old_data(self) -> Optional[dict]:
"""
说明:
说明:
获取旧数据,平时使用请不要调用
"""
if self._data["super"].get("close_plugins"):
+13 -3
View File
@@ -2,8 +2,10 @@ from typing import List, Optional, Union, Tuple
from .data_class import StaticData
from pathlib import Path
from ruamel.yaml import YAML
from ruamel import yaml
yaml = YAML(typ="safe")
_yaml = YAML(typ="safe")
class Plugins2settingsManager(StaticData):
@@ -16,7 +18,7 @@ class Plugins2settingsManager(StaticData):
super().__init__(None)
if file.exists():
with open(file, "r", encoding="utf8") as f:
self._data = yaml.load(f)
self._data = _yaml.load(f)
if self._data:
if "PluginSettings" in self._data.keys():
self._data = (
@@ -91,11 +93,19 @@ class Plugins2settingsManager(StaticData):
return key
return keys
def save(self, path: Union[str, Path] = None):
path = path or self.file
if isinstance(path, str):
path = Path(path)
if path:
with open(path, "w", encoding="utf8") as f:
yaml.dump({"PluginSettings": self._data}, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True)
def reload(self):
"""
重载本地数据
"""
if self.file.exists():
with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f)
self._data: dict = _yaml.load(f)
self._data = self._data["PluginSettings"]
+10 -10
View File
@@ -48,9 +48,9 @@ class PluginsManager(StaticData):
self, module: str, group_id: Optional[int] = None, block_type: str = "all"
):
"""
说明:
说明:
锁定插件
参数:
参数:
:param module: 功能模块名
:param group_id: 群组,None时为超级用户禁用
:param block_type: 限制类型
@@ -59,9 +59,9 @@ class PluginsManager(StaticData):
def unblock_plugin(self, module: str, group_id: Optional[int] = None):
"""
说明:
说明:
解锁插件
参数:
参数:
:param module: 功能模块名
:param group_id: 群组
"""
@@ -71,9 +71,9 @@ class PluginsManager(StaticData):
self, module: str, block_type: str = "all"
) -> bool:
"""
说明:
说明:
获取插件状态
参数:
参数:
:param module: 功能模块名
:param block_type: 限制类型
"""
@@ -86,9 +86,9 @@ class PluginsManager(StaticData):
def get_plugin_block_type(self, module: str) -> str:
"""
说明:
说明:
获取功能限制类型
参数:
参数:
:param module: 模块名称
"""
if module in self._data.keys():
@@ -112,9 +112,9 @@ class PluginsManager(StaticData):
block_type: str = "all",
):
"""
说明:
说明:
设置功能开关状态
参数:
参数:
:param module: 功能模块名
:param status: 功能状态
:param group_id: 群组
+1 -2
View File
@@ -1,6 +1,5 @@
from utils.manager.data_class import StaticData
from nonebot.adapters.onebot.v11 import Bot
from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.adapters.onebot.v11 import Bot, ActionFailed
from services.log import logger
from typing import Optional, Literal
from utils.image_utils import BuildImage
+4 -4
View File
@@ -8,9 +8,9 @@ class WithdrawMessageManager:
def append(self, message_data: Tuple[Union[int, Dict[str, int]], int]):
"""
说明:
说明:
添加一个撤回消息id和时间
参数:
参数:
:param message_data: 撤回消息id和时间
"""
if isinstance(message_data[0], dict):
@@ -19,9 +19,9 @@ class WithdrawMessageManager:
def remove(self, message_data: Tuple[int, int]):
"""
说明:
说明:
删除一个数据
参数:
参数:
:param message_data: 消息id和时间
"""
self.data.remove(message_data)
+28 -26
View File
@@ -13,10 +13,10 @@ def image(
b64: str = None,
) -> Union[MessageSegment, str]:
"""
说明:
说明:
生成一个 MessageSegment.image 消息
生成顺序:绝对路径(abspath) > base64(b64) > img_name
参数:
参数:
:param file: 图片文件名称,默认在 resource/img 目录下
:param path: 图片所在路径,默认在 resource/img 目录下
:param b64: 图片base64
@@ -42,11 +42,11 @@ def image(
return ""
def at(qq: int) -> MessageSegment:
def at(qq: Union[int, str]) -> MessageSegment:
"""
说明:
说明:
生成一个 MessageSegment.at 消息
参数:
参数:
:param qq: qq号
"""
return MessageSegment.at(qq)
@@ -54,9 +54,9 @@ def at(qq: int) -> MessageSegment:
def record(voice_name: str, path: str = None) -> MessageSegment or str:
"""
说明:
说明:
生成一个 MessageSegment.record 消息
参数:
参数:
:param voice_name: 音频文件名称,默认在 resource/voice 目录下
:param path: 音频文件路径,默认在 resource/voice 目录下
"""
@@ -79,9 +79,9 @@ def record(voice_name: str, path: str = None) -> MessageSegment or str:
def text(msg: str) -> MessageSegment:
"""
说明:
说明:
生成一个 MessageSegment.text 消息
参数:
参数:
:param msg: 消息文本
"""
return MessageSegment.text(msg)
@@ -89,9 +89,9 @@ def text(msg: str) -> MessageSegment:
def contact_user(qq: int) -> MessageSegment:
"""
说明:
说明:
生成一个 MessageSegment.contact_user 消息
参数:
参数:
:param qq: qq号
"""
return MessageSegment.contact_user(qq)
@@ -101,9 +101,9 @@ def share(
url: str, title: str, content: str = None, image_url: str = None
) -> MessageSegment:
"""
说明:
说明:
生成一个 MessageSegment.share 消息
参数:
参数:
:param url: 自定义分享的链接
:param title: 自定义分享的包体
:param content: 自定义分享的内容
@@ -114,9 +114,9 @@ def share(
def xml(data: str) -> MessageSegment:
"""
说明:
说明:
生成一个 MessageSegment.xml 消息
参数:
参数:
:param data: 数据文本
"""
return MessageSegment.xml(data)
@@ -124,9 +124,9 @@ def xml(data: str) -> MessageSegment:
def json(data: str) -> MessageSegment:
"""
说明:
说明:
生成一个 MessageSegment.json 消息
参数:
参数:
:param data: 消息数据
"""
return MessageSegment.json(data)
@@ -134,9 +134,9 @@ def json(data: str) -> MessageSegment:
def face(id_: int) -> MessageSegment:
"""
说明:
说明:
生成一个 MessageSegment.face 消息
参数:
参数:
:param id_: 表情id
"""
return MessageSegment.face(id_)
@@ -144,9 +144,9 @@ def face(id_: int) -> MessageSegment:
def poke(qq: int) -> MessageSegment:
"""
说明:
说明:
生成一个 MessageSegment.poke 消息
参数:
参数:
:param qq: qq号
"""
return MessageSegment("poke", {"qq": qq})
@@ -157,13 +157,15 @@ def music(type_: str, id_: int) -> MessageSegment:
def custom_forward_msg(
msg_list: List[str], uin: Union[int, str], name: str = f"这里是{NICKNAME}"
msg_list: List[Union[str, Message]], uin: Union[int, str], name: str = f"这里是{NICKNAME}"
) -> List[dict]:
"""
生成自定义合并消息
:param msg_list: 消息列表
:param uin: 发送者 QQ
:param name: 自定义名称
说明:
生成自定义合并消息
参数:
:param msg_list: 消息列表
:param uin: 发送者 QQ
:param name: 自定义名称
"""
uin = int(uin)
mes_list = []
+45 -27
View File
@@ -5,6 +5,8 @@ from configs.config import SYSTEM_PROXY, Config
from typing import List, Union, Optional, Type, Any
from nonebot.adapters.onebot.v11 import Bot, Message
from nonebot.matcher import matchers, Matcher
from services.log import logger
from pathlib import Path
import httpx
import nonebot
import pytz
@@ -148,9 +150,9 @@ class DailyNumberLimiter:
def is_number(s: str) -> bool:
"""
说明:
说明:
检测 s 是否为数字
参数:
参数:
:param s: 文本
"""
try:
@@ -170,7 +172,7 @@ def is_number(s: str) -> bool:
def get_bot() -> Optional[Bot]:
"""
说明:
说明:
获取 bot 对象
"""
try:
@@ -192,9 +194,9 @@ def get_matchers() -> List[Type[Matcher]]:
def get_message_at(data: Union[str, Message]) -> List[int]:
"""
说明:
说明:
获取消息中所有的 at 对象的 qq
参数:
参数:
:param data: event.json()
"""
qq_list = []
@@ -212,9 +214,9 @@ def get_message_at(data: Union[str, Message]) -> List[int]:
def get_message_img(data: Union[str, Message]) -> List[str]:
"""
说明:
说明:
获取消息中所有的 图片 的链接
参数:
参数:
:param data: event.json()
"""
img_list = []
@@ -231,9 +233,9 @@ def get_message_img(data: Union[str, Message]) -> List[str]:
def get_message_img_file(data: Union[str, Message]) -> List[str]:
"""
说明:
说明:
获取消息中所有的 图片file
参数:
参数:
:param data: event.json()
"""
file_list = []
@@ -250,9 +252,9 @@ def get_message_img_file(data: Union[str, Message]) -> List[str]:
def get_message_text(data: Union[str, Message]) -> str:
"""
说明:
说明:
获取消息中 纯文本 的信息
参数:
参数:
:param data: event.json()
"""
result = ""
@@ -265,14 +267,14 @@ def get_message_text(data: Union[str, Message]) -> str:
else:
for seg in data["text"]:
result += seg.data["text"] + " "
return result
return result.strip()
def get_message_record(data: Union[str, Message]) -> List[str]:
"""
说明:
说明:
获取消息中所有 语音 的链接
参数:
参数:
:param data: event.json()
"""
record_list = []
@@ -289,9 +291,9 @@ def get_message_record(data: Union[str, Message]) -> List[str]:
def get_message_json(data: str) -> List[dict]:
"""
说明:
说明:
获取消息中所有 json
参数:
参数:
:param data: event.json()
"""
try:
@@ -307,7 +309,7 @@ def get_message_json(data: str) -> List[dict]:
def get_local_proxy():
"""
说明:
说明:
获取 config.py 中设置的代理
"""
return SYSTEM_PROXY if SYSTEM_PROXY else None
@@ -315,9 +317,9 @@ def get_local_proxy():
def is_chinese(word: str) -> bool:
"""
说明:
说明:
判断字符串是否为纯中文
参数:
参数:
:param word: 文本
"""
for ch in word:
@@ -328,9 +330,9 @@ def is_chinese(word: str) -> bool:
async def get_user_avatar(qq: int) -> Optional[bytes]:
"""
说明:
说明:
快捷获取用户头像
参数:
参数:
:param qq: qq号
"""
url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=160"
@@ -345,9 +347,9 @@ async def get_user_avatar(qq: int) -> Optional[bytes]:
async def get_group_avatar(group_id: int) -> Optional[bytes]:
"""
说明:
说明:
快捷获取用群头像
参数:
参数:
:param group_id: 群号
"""
url = f"http://p.qlogo.cn/gh/{group_id}/{group_id}/640/"
@@ -362,9 +364,9 @@ async def get_group_avatar(group_id: int) -> Optional[bytes]:
def cn2py(word: str) -> str:
"""
说明:
说明:
将字符串转化为拼音
参数:
参数:
:param word: 文本
"""
temp = ""
@@ -377,9 +379,9 @@ def change_pixiv_image_links(
url: str, size: Optional[str] = None, nginx_url: Optional[str] = None
):
"""
说明:
说明:
根据配置改变图片大小和反代链接
参数:
参数:
:param url: 图片原图链接
:param size: 模式
:param nginx_url: 反代
@@ -398,3 +400,19 @@ def change_pixiv_image_links(
.replace("_webp", "")
)
return url
def change_img_md5(path_file: Union[str, Path]) -> bool:
"""
说明:
改变图片MD5
参数:
:param path_file: 图片路径
"""
try:
with open(path_file, "a") as f:
f.write(str(int(time.time() * 1000)))
return True
except Exception as e:
logger.warning(f"改变图片MD5发生错误 {type(e)}:{e} Path:{path_file}")
return False