mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-09-29 00:32:06 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1862e9c68 | ||
|
|
731bde8e28 | ||
|
|
47c87f8694 | ||
|
|
5558cdacc3 | ||
|
|
4650d244a5 | ||
|
|
c65b8aae07 | ||
|
|
7ba2fb9584 | ||
|
|
9a2cfd0c9b | ||
|
|
a7d61b1f2b | ||
|
|
7ab185f7d7 | ||
|
|
724541d691 | ||
|
|
baa6cda9c2 | ||
|
|
9c987e9aad | ||
|
|
134974ea9c | ||
|
|
2d946958e3 | ||
|
|
ffe010e9ce | ||
|
|
1c67252b0c | ||
|
|
60c1be25d4 | ||
|
|
18323a0916 | ||
|
|
9d98abded9 | ||
|
|
b06a742b8c | ||
|
|
87fe44f188 | ||
|
|
96f6ef1693 | ||
|
|
23c4141e55 | ||
|
|
c21200c2a9 | ||
|
|
4a8b94259d | ||
|
|
28a58df27b | ||
|
|
caaf486bbe | ||
|
|
0a972a399e | ||
|
|
245dad1239 | ||
|
|
a6b6a2fbff | ||
|
|
53000a949b | ||
|
|
eae1dd59a7 | ||
|
|
e6347a76a8 | ||
|
|
13e0fb3df7 | ||
|
|
3f1b23ef8a | ||
|
|
acae7f0658 | ||
|
|
a9456b1bd6 | ||
|
|
e4d5a230d2 | ||
|
|
fedf44b9fa | ||
|
|
451db104e8 | ||
|
|
9ac4c7f4e3 | ||
|
|
7cf1c6f016 | ||
|
|
6dd87ee301 | ||
|
|
96837fa8db | ||
|
|
d816e76962 | ||
|
|
310945d9cd | ||
|
|
1aba480495 | ||
|
|
07407749fe | ||
|
|
dfab70dd90 | ||
|
|
3b15469c98 | ||
|
|
e4590800c2 | ||
|
|
c63d4b8ad0 | ||
|
|
1fb913e2ed | ||
|
|
72ace2dab7 | ||
|
|
3bcef18629 | ||
|
|
c91758519c | ||
|
|
9c8f2e7aa0 | ||
|
|
5f377af6d5 | ||
|
|
570b5b1766 | ||
|
|
c4d53d58eb | ||
|
|
ed65033cf1 | ||
|
|
41836bde26 | ||
|
|
8381858742 | ||
|
|
1040bd0d58 | ||
|
|
404e47332e | ||
|
|
3db128785e | ||
|
|
2189ea11df | ||
|
|
49b9bd65b0 | ||
|
|
b3fdb1ff58 | ||
|
|
c79e3fdcf0 | ||
|
|
d7509f7030 | ||
|
|
5c99b55502 | ||
|
|
fd255f022b | ||
|
|
41642589ae | ||
|
|
619fef3bff | ||
|
|
38c0da0cf8 | ||
|
|
b241a58e84 | ||
|
|
35c9585b22 | ||
|
|
d2fe95cc05 | ||
|
|
92e60ba141 | ||
|
|
2356527791 | ||
|
|
cab0f7b522 | ||
|
|
8d3f101a68 | ||
|
|
c8ac2b6281 | ||
|
|
d7d8efd305 | ||
|
|
a4bc04c958 | ||
|
|
5fc208c95a | ||
|
|
02743d5955 | ||
|
|
a7ffebea35 | ||
|
|
c511ef50a2 | ||
|
|
82902e0cde | ||
|
|
1de5ae09bc | ||
|
|
8b735f1cb5 | ||
|
|
33d1334174 | ||
|
|
324b58c21b | ||
|
|
b7b1651709 | ||
|
|
b5a4a6a9ff | ||
|
|
fe2c82b03c | ||
|
|
81e4bca9ef | ||
|
|
c0d055b825 | ||
|
|
188ae38525 | ||
|
|
86a8fe7096 | ||
|
|
0bb2b45f5c | ||
|
|
a17d8731c8 | ||
|
|
9cdd2326c8 | ||
|
|
d75653631d | ||
|
|
e234c8906e | ||
|
|
57baea18b5 | ||
|
|
0f3efe29c4 | ||
|
|
89b87a38b3 | ||
|
|
c52b7ca2e9 | ||
|
|
371b55dc9e | ||
|
|
53e572353c | ||
|
|
3ae71c74e9 | ||
|
|
cb643c04f7 | ||
|
|
faf9ee159b | ||
|
|
ffb3b2d73e | ||
|
|
ffcc327089 | ||
|
|
dfd5a6a86a | ||
|
|
d43f89b067 | ||
|
|
f15c3ab6a2 | ||
|
|
e27809298e | ||
|
|
4b3e28e14b | ||
|
|
71ce9153ed | ||
|
|
25d63966de | ||
|
|
98afbb54b6 | ||
|
|
03a51ca5dd | ||
|
|
428481b2d5 | ||
|
|
f87c60e6db | ||
|
|
6d824e38bc | ||
|
|
f0fd5bfb9e | ||
|
|
33374df671 | ||
|
|
c035b1b19c | ||
|
|
b3b09ed666 | ||
|
|
8029c00a02 | ||
|
|
a2c0921013 | ||
|
|
31cdabc229 |
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
name: Issue template
|
||||||
|
about: " issue template's purpose here."
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 系统版本:Ubuntu 20.04
|
||||||
|
### 真寻版本:0.1.5.3
|
||||||
|
|
||||||
|
### 错误截图
|
||||||
|
|
||||||
|
[img]
|
||||||
|
|
||||||
|
### 日志截图
|
||||||
|
|
||||||
|
[img]
|
||||||
|
|
||||||
|
### 错误说明
|
||||||
|
|
||||||
|
发生了xx错误...
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
name: Generate poetry.lock
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
paths:
|
||||||
|
- 'pyproject.toml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
poetry_lock:
|
||||||
|
name: Generate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Set up Python
|
||||||
|
uses: he0119/setup-python@main
|
||||||
|
with:
|
||||||
|
python-version: "3.9"
|
||||||
|
- name: poetry lock
|
||||||
|
run: |
|
||||||
|
rm -f poetry.lock
|
||||||
|
sed -i.bak "8,11d" pyproject.toml
|
||||||
|
poetry lock
|
||||||
|
mv pyproject.toml.bak pyproject.toml
|
||||||
|
# commit
|
||||||
|
- name: commit file
|
||||||
|
run: |
|
||||||
|
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git config --local user.name "github-actions[bot]"
|
||||||
|
git add poetry.lock
|
||||||
|
git commit -m "Auto generate poetry.lock" -a
|
||||||
|
# push
|
||||||
|
- name: push changes
|
||||||
|
uses: ad-m/github-push-action@master
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
### 系统版本:Ubuntu 20.04
|
||||||
|
### 真寻版本:0.1.5.3
|
||||||
|
|
||||||
|
### 错误截图
|
||||||
|
|
||||||
|
[img]
|
||||||
|
|
||||||
|
### 错误说明
|
||||||
|
发生了xx错误...
|
||||||
@@ -18,9 +18,10 @@
|
|||||||
## 声明
|
## 声明
|
||||||
此项目仅用于学习交流,请勿用于非法用途
|
此项目仅用于学习交流,请勿用于非法用途
|
||||||
|
|
||||||
## Gitee
|
# Nonebot2
|
||||||
|
<img style="height: 200px;width: 200px;" src="https://camo.githubusercontent.com/0ef71e86056da694c540790aa4a4e314396884d6c4fdb95362a7538b27a1b034/68747470733a2f2f76322e6e6f6e65626f742e6465762f6c6f676f2e706e67">
|
||||||
|
|
||||||
# [Gitee](https://gitee.com/two_Dimension/zhenxun_bot)
|
非常 [ **[NICE](https://github.com/nonebot/nonebot2)** ] 的OneBot框架
|
||||||
|
|
||||||
## 未完成的文档
|
## 未完成的文档
|
||||||
|
|
||||||
@@ -113,7 +114,7 @@
|
|||||||
- [x] 获取b站视频封面
|
- [x] 获取b站视频封面
|
||||||
- [x] 通过PID获取图片
|
- [x] 通过PID获取图片
|
||||||
- [x] 功能统计可视化
|
- [x] 功能统计可视化
|
||||||
|
- [x] 词云
|
||||||
- [x] 关于
|
- [x] 关于
|
||||||
|
|
||||||
### 已实现的管理员功能
|
### 已实现的管理员功能
|
||||||
@@ -235,25 +236,139 @@ python bot.py
|
|||||||
|
|
||||||
## 使用Docker
|
## 使用Docker
|
||||||
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
||||||
#### GitHub:[Sakuracio/zxenv](https://github.com/Sakuracio/zxenv)
|
#### GitHub:[Sakuracio/zhenxun_bot_docker](https://github.com/Sakuracio/zhenxun_bot_docker)
|
||||||
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
|
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 更新
|
## 更新
|
||||||
|
|
||||||
|
### 2022/5/29 \[v0.1.5.7]
|
||||||
|
|
||||||
|
* 修复错误的resource路径会删除IMAGE_PATH等重要文件夹
|
||||||
|
* 提供了真寻适配仓库的插件 安装/卸载 操作
|
||||||
|
|
||||||
|
### 2022/5/28
|
||||||
|
|
||||||
|
* 修复私聊无法添加昵称
|
||||||
|
* 修复原神玩家查询层岩巨渊地下矿区没开时报错
|
||||||
|
* 修复 ```休息吧``` 无法阻断戳一戳
|
||||||
|
* 当图库无图片时,戳一戳将略过发送图片
|
||||||
|
* 新增搜图提供配置项```ALLOW_GROUP_R18```:允许在群聊中使用r18参数
|
||||||
|
* 新增自动更新插件```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)
|
||||||
|
* 更多的中文提示
|
||||||
|
|
||||||
|
### 2022/5/26
|
||||||
|
|
||||||
|
* 修复\[滴滴滴]会被转义成[滴滴滴]导致无法触发的问题
|
||||||
|
* 将一些错误以中文提示输出
|
||||||
|
* 更新BT搜索源地址 [@pull/668](https://github.com/HibiKier/zhenxun_bot/pull/668)
|
||||||
|
* 更新抽卡插件 [@pull/667](https://github.com/HibiKier/zhenxun_bot/pull/667)
|
||||||
|
|
||||||
|
### 2022/5/25
|
||||||
|
|
||||||
|
* 修复webui中CountLimit字段limit_type类型错误
|
||||||
|
* 修改nickname插件:一处文案错误,添加敏感词 [@pull/624](https://github.com/HibiKier/zhenxun_bot/pull/624)
|
||||||
|
* gamedraw的ba卡池搬运了过来并且进行了真寻的适配 [@pull/617](https://github.com/HibiKier/zhenxun_bot/pull/617)
|
||||||
|
* feat: stream downloading and progress [@pull/607](https://github.com/HibiKier/zhenxun_bot/pull/607)
|
||||||
|
* 修改翻译插件,添加缺失的冒号 [@pull/602](https://github.com/HibiKier/zhenxun_bot/pull/602)
|
||||||
|
* 修复碧蓝航线/明日方舟up池解析出错的问题 [@pull/610](https://github.com/HibiKier/zhenxun_bot/pull/602)
|
||||||
|
|
||||||
|
### 2022/5/24
|
||||||
|
|
||||||
|
* fix: 修正了签到时日期时间的显示不补齐零的bug (符合日期时间表示法 ISO 8601)[@pull/600](https://github.com/HibiKier/zhenxun_bot/pull/600)
|
||||||
|
* 更新"微博热搜"接口 [@pull/579](https://github.com/HibiKier/zhenxun_bot/pull/579)
|
||||||
|
* refactor&fix(manager): modify argument [@pull/576](https://github.com/HibiKier/zhenxun_bot/pull/576)
|
||||||
|
* 修复复读不能复读图片的问题 [@pull/573](https://github.com/HibiKier/zhenxun_bot/pull/573)
|
||||||
|
* 修复抽卡插件:方舟抽卡的抽取和显示问题 [@pull/581](https://github.com/HibiKier/zhenxun_bot/pull/581)
|
||||||
|
|
||||||
|
### 2022/5/23 \[v0.1.5.6]
|
||||||
|
|
||||||
|
* 修复"清除已删除插件数据" [@pull/545](https://github.com/HibiKier/zhenxun_bot/pull/545)
|
||||||
|
* 修复有置顶的up主B站动态获取失败 [@pull/552](https://github.com/HibiKier/zhenxun_bot/pull/552)
|
||||||
|
* 添加pixiv搜图多关键词支持;修复p站搜图数量参数问题 [@pull/441](https://github.com/HibiKier/zhenxun_bot/pull/441)
|
||||||
|
* 修复开箱更新价格错误传参
|
||||||
|
* 修复pix无法正确查询uid
|
||||||
|
* 新增色图插件添加配置项```ALLOW_GROUP_R18```:允许群聊中使用色图r
|
||||||
|
* 新增PIX插件添加配置项```ALLOW_GROUP_SETU```:允许非超级用户使用-s参数
|
||||||
|
* 新增PIX插件添加配置项```ALLOW_GROUP_R18```:允许非超级用户使用-r参数
|
||||||
|
|
||||||
|
### 2022/5/22 \[v0.1.5.4]
|
||||||
|
|
||||||
|
* 使用action自动更新poetry.lock [@pull/515](https://github.com/HibiKier/zhenxun_bot/pull/515)
|
||||||
|
* fix(bilibili_sub): card is None and timeout [@pull/516](https://github.com/HibiKier/zhenxun_bot/pull/516)
|
||||||
|
* 修复了epic有时获取新免费游戏消息时获取不到图片
|
||||||
|
* 修复好感度满时签到出错(虽然是不可能满的
|
||||||
|
* 修复原神资源图标下载路径错误
|
||||||
|
* 修复自动更新群组可能失败
|
||||||
|
|
||||||
|
### 2022/5/21
|
||||||
|
|
||||||
|
* 修复搜番无结果时报错无正确反馈
|
||||||
|
* 解锁了windows上无法使用playwright的限制
|
||||||
|
* 修复p搜对应pid有多张图时出错,改为连续发送图片
|
||||||
|
* 修复p搜对数字的错误判断
|
||||||
|
* 修复添加商品折扣无法正确添加
|
||||||
|
* 修复了bilibili订阅直播间订阅up名称不一致的问题
|
||||||
|
* 修复原神玩家查询没开地图时报错
|
||||||
|
* 最低priority修改为 999
|
||||||
|
* 修复刷屏检测失效
|
||||||
|
* 修复刷屏检测设置命令无法生效
|
||||||
|
* 优化刷屏显示设置禁言时长显示,并改为分钟
|
||||||
|
* 修复了多连开箱无法指定武器箱
|
||||||
|
* 修复识番链接无法正确获取
|
||||||
|
* 新增真寻入群时即刻刷新权限
|
||||||
|
* 提高了微博热搜截图的等待时间
|
||||||
|
|
||||||
|
### 2022/5/19
|
||||||
|
|
||||||
|
* fix: mihoyo bbs api changed [@pull/357](https://github.com/HibiKier/zhenxun_bot/pull/357)
|
||||||
|
* Add word_clouds [@pull/265](https://github.com/HibiKier/zhenxun_bot/pull/265)
|
||||||
|
* Fix wrong live streamer name [@pull/284](https://github.com/HibiKier/zhenxun_bot/pull/284)
|
||||||
|
|
||||||
|
### 2022/5/16
|
||||||
|
|
||||||
|
* 词条支持图片和@问题 [@pull/160](https://github.com/HibiKier/zhenxun_bot/pull/160)
|
||||||
|
|
||||||
|
### 2022/5/15
|
||||||
|
|
||||||
|
* 修复了商店商品无法正确添加
|
||||||
|
* 修复了多张色图无法正确发送
|
||||||
|
|
||||||
|
### 2022/5/14
|
||||||
|
|
||||||
|
* 修复B站动态生成失败的问题 [@pull/159](https://github.com/HibiKier/zhenxun_bot/pull/159)
|
||||||
|
|
||||||
|
### 2022/5/11
|
||||||
|
|
||||||
|
* fix: 更改p搜api,解决p搜无法使用的问题 [@pull/155](https://github.com/HibiKier/zhenxun_bot/pull/155)
|
||||||
|
|
||||||
|
### 2022/5/9 \[v0.1.5.3]
|
||||||
|
|
||||||
|
* 替换了疫情API
|
||||||
|
* 修复了私聊.ban/.unban出错
|
||||||
|
|
||||||
|
### 2022/5/5
|
||||||
|
|
||||||
|
* 修改bilibili_sub插件在windows平台下报错 [@pull/153](https://github.com/HibiKier/zhenxun_bot/pull/153)
|
||||||
|
|
||||||
### 2022/5/3 \[v0.1.5.2]
|
### 2022/5/3 \[v0.1.5.2]
|
||||||
|
|
||||||
* 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数
|
* 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数
|
||||||
* 添加商品注册装饰器shop_register
|
* 添加商品注册装饰器shop_register
|
||||||
* 修复商品函数kwargs无法获取参数值
|
* 修复商品函数kwargs无法获取参数值
|
||||||
|
|
||||||
|
|
||||||
### 2022/5/1
|
### 2022/5/1
|
||||||
|
|
||||||
* 删除了`group_last_chat`插件(该功能可由`chat_history`替代
|
* 删除了`group_last_chat`插件(该功能可由`chat_history`替代
|
||||||
* 新增敏感词检测(全新反击系统,是时候重拳出击了
|
* 新增敏感词检测(全新反击系统,是时候重拳出击了
|
||||||
|
|
||||||
### 2022/4/26 \[v0.5.1.0]
|
### 2022/4/26
|
||||||
|
|
||||||
* 修复了群白名单无法正确添加
|
* 修复了群白名单无法正确添加
|
||||||
* 优化了管理员帮助图片,背景图层将位于最下层
|
* 优化了管理员帮助图片,背景图层将位于最下层
|
||||||
@@ -488,4 +603,4 @@ __..... 更多更新信息请查看文档__
|
|||||||
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
|
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
|
||||||
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
|
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
|
||||||
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
|
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
|
||||||
[KimigaiiWuyi / GenshinUID]("https://github.com/KimigaiiWuyi/GenshinUID") :一个基于HoshinoBot/NoneBot2的原神UID查询插件
|
[KimigaiiWuyi / GenshinUID](https://github.com/KimigaiiWuyi/GenshinUID) :一个基于HoshinoBot/NoneBot2的原神UID查询插件
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
__version__: v0.1.5.1
|
__version__: v0.1.5.6
|
||||||
@@ -232,10 +232,7 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
|
|||||||
_exist_member_list = []
|
_exist_member_list = []
|
||||||
# try:
|
# try:
|
||||||
for user_info in _group_user_list:
|
for user_info in _group_user_list:
|
||||||
if user_info["card"] == "":
|
nickname = user_info["card"] or user_info["nickname"]
|
||||||
nickname = user_info["nickname"]
|
|
||||||
else:
|
|
||||||
nickname = user_info["card"]
|
|
||||||
async with db.transaction():
|
async with db.transaction():
|
||||||
# 更新权限
|
# 更新权限
|
||||||
if (
|
if (
|
||||||
@@ -321,3 +318,4 @@ def set_group_bot_status(group_id: int, status: bool) -> str:
|
|||||||
# for x in group_manager.get_task_data():
|
# for x in group_manager.get_task_data():
|
||||||
# group_manager.close_group_task(group_id, x)
|
# group_manager.close_group_task(group_id, x)
|
||||||
return "那我先睡觉了..."
|
return "那我先睡觉了..."
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from nonebot import on_command, on_notice
|
|||||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
|
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
|
||||||
from ._data_source import update_member_info
|
from ._data_source import update_member_info
|
||||||
|
|
||||||
|
|
||||||
__zx_plugin_name__ = "更新群组成员列表 [Admin]"
|
__zx_plugin_name__ = "更新群组成员列表 [Admin]"
|
||||||
__plugin_usage__ = """
|
__plugin_usage__ = """
|
||||||
usage:
|
usage:
|
||||||
|
|||||||
@@ -125,11 +125,13 @@ async def _(
|
|||||||
msg = arg.extract_plain_text().strip()
|
msg = arg.extract_plain_text().strip()
|
||||||
if msg:
|
if msg:
|
||||||
if str(event.user_id) in bot.config.superusers:
|
if str(event.user_id) in bot.config.superusers:
|
||||||
if is_number(arg.extract_plain_text().strip().split()[0]):
|
msg_splt = msg.split()
|
||||||
qq = int(msg[0])
|
if is_number(msg_splt[0]):
|
||||||
msg = msg[1:]
|
|
||||||
|
qq = int(msg_splt[0])
|
||||||
|
msg = msg_splt[1:]
|
||||||
if cmd in [".ban", "/ban"]:
|
if cmd in [".ban", "/ban"]:
|
||||||
time = parse_ban_time(msg)
|
time = parse_ban_time(" ".join(msg))
|
||||||
if isinstance(time, str):
|
if isinstance(time, str):
|
||||||
await ban.finish(time)
|
await ban.finish(time)
|
||||||
result = await a_ban(qq, time, str(qq), event, 9)
|
result = await a_ban(qq, time, str(qq), event, 9)
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ def parse_ban_time(msg: str) -> Union[int, str]:
|
|||||||
return int(msg[0]) * 60 * 60 + int(msg[1]) * 60
|
return int(msg[0]) * 60 * 60 + int(msg[1]) * 60
|
||||||
|
|
||||||
|
|
||||||
async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None) -> str:
|
async def a_ban(
|
||||||
|
qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None
|
||||||
|
) -> str:
|
||||||
"""
|
"""
|
||||||
ban
|
ban
|
||||||
:param qq: qq
|
:param qq: qq
|
||||||
@@ -38,7 +40,8 @@ async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_lev
|
|||||||
ban_level = await LevelUser.get_user_level(event.user_id, event.group_id)
|
ban_level = await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||||
if await BanUser.ban(qq, ban_level, time):
|
if await BanUser.ban(qq, ban_level, time):
|
||||||
logger.info(
|
logger.info(
|
||||||
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time / 60} 分钟"
|
f"USER {event.user_id} GROUP"
|
||||||
|
f" {event.group_id if isinstance(event, GroupMessageEvent) else ''} 将 USER {qq} 封禁 时长 {time / 60} 分钟"
|
||||||
)
|
)
|
||||||
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
|
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
|
||||||
if time != -1:
|
if time != -1:
|
||||||
@@ -57,13 +60,3 @@ async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_lev
|
|||||||
time += " 分钟"
|
time += " 分钟"
|
||||||
result = f"{user_name} 已在黑名单!预计 {time}后解封"
|
result = f"{user_name} 已在黑名单!预计 {time}后解封"
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from configs.config import Config
|
|||||||
from models.chat_history import ChatHistory
|
from models.chat_history import ChatHistory
|
||||||
from nonebot import on_message
|
from nonebot import on_message
|
||||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
|
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
|
||||||
|
from utils.utils import get_message_text
|
||||||
|
|
||||||
from ._rule import rule
|
from ._rule import rule
|
||||||
|
|
||||||
@@ -22,10 +23,10 @@ chat_history = on_message(rule=rule, priority=1, block=False)
|
|||||||
async def _(event: MessageEvent):
|
async def _(event: MessageEvent):
|
||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
await ChatHistory.add_chat_msg(
|
await ChatHistory.add_chat_msg(
|
||||||
event.user_id, event.group_id, str(event.get_message())
|
event.user_id, event.group_id, str(event.get_message()), get_message_text(event.json())
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message()))
|
await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message()), get_message_text(event.json()))
|
||||||
|
|
||||||
|
|
||||||
# @test.handle()
|
# @test.handle()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from nonebot import on_notice, on_request
|
from nonebot import on_notice, on_request
|
||||||
from configs.path_config import IMAGE_PATH, DATA_PATH
|
from configs.path_config import IMAGE_PATH, DATA_PATH
|
||||||
|
from models.level_user import LevelUser
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from models.group_member_info import GroupInfoUser
|
from models.group_member_info import GroupInfoUser
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -96,6 +97,23 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
|
|||||||
for plugin in data.keys():
|
for plugin in data.keys():
|
||||||
if not data[plugin]["default_status"]:
|
if not data[plugin]["default_status"]:
|
||||||
group_manager.block_plugin(plugin, event.group_id)
|
group_manager.block_plugin(plugin, event.group_id)
|
||||||
|
# 即刻刷新权限
|
||||||
|
for user_info in await bot.get_group_member_list(group_id=event.group_id):
|
||||||
|
if user_info["role"] in [
|
||||||
|
"owner",
|
||||||
|
"admin",
|
||||||
|
] and not await LevelUser.is_group_flag(
|
||||||
|
user_info["user_id"], event.group_id
|
||||||
|
):
|
||||||
|
await LevelUser.set_level(
|
||||||
|
user_info["user_id"],
|
||||||
|
user_info["group_id"],
|
||||||
|
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
|
||||||
|
)
|
||||||
|
if str(user_info["user_id"]) in bot.config.superusers:
|
||||||
|
await LevelUser.set_level(
|
||||||
|
user_info["user_id"], user_info["group_id"], 9
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
join_time = datetime.now()
|
join_time = datetime.now()
|
||||||
user_info = await bot.get_group_member_info(
|
user_info = await bot.get_group_member_info(
|
||||||
@@ -128,9 +146,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
|
|||||||
msg = msg.replace("[at]", "")
|
msg = msg.replace("[at]", "")
|
||||||
at_flag = True
|
at_flag = True
|
||||||
if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists():
|
if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists():
|
||||||
img = image(
|
img = image(DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg")
|
||||||
DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg"
|
|
||||||
)
|
|
||||||
if msg or img:
|
if msg or img:
|
||||||
msg = msg.strip() + img
|
msg = msg.strip() + img
|
||||||
msg = "\n" + msg if at_flag else msg
|
msg = "\n" + msg if at_flag else msg
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ def _create_help_img(
|
|||||||
for matcher in _matchers:
|
for matcher in _matchers:
|
||||||
plugin_name = None
|
plugin_name = None
|
||||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||||
|
if not _plugin:
|
||||||
|
logger.warning(f"获取 功能:{matcher.plugin_name} 失败...")
|
||||||
|
continue
|
||||||
_module = _plugin.module
|
_module = _plugin.module
|
||||||
try:
|
try:
|
||||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||||
|
|||||||
@@ -91,7 +91,10 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
# 群黑名单检测 群总开关检测
|
# 群黑名单检测 群总开关检测
|
||||||
if isinstance(event, GroupMessageEvent) or matcher.plugin_name == other_limit_plugins:
|
if (
|
||||||
|
isinstance(event, GroupMessageEvent)
|
||||||
|
or matcher.plugin_name in other_limit_plugins
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
if (
|
if (
|
||||||
group_manager.get_group_level(event.group_id) < 0
|
group_manager.get_group_level(event.group_id) < 0
|
||||||
@@ -106,7 +109,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
|||||||
raise IgnoredException("功能总开关关闭状态")
|
raise IgnoredException("功能总开关关闭状态")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
if module in admin_manager.keys() and matcher.priority not in [1, 9]:
|
if module in admin_manager.keys() and matcher.priority not in [1, 999]:
|
||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
# 个人权限
|
# 个人权限
|
||||||
if (
|
if (
|
||||||
@@ -146,9 +149,13 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
|||||||
if event.is_tome():
|
if event.is_tome():
|
||||||
status_message_manager.add(event.user_id)
|
status_message_manager.add(event.user_id)
|
||||||
raise IgnoredException("权限不足")
|
raise IgnoredException("权限不足")
|
||||||
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
|
if module in plugins2info_dict.keys() and matcher.priority not in [1, 999]:
|
||||||
# 戳一戳单独判断
|
# 戳一戳单独判断
|
||||||
if isinstance(event, GroupMessageEvent) or isinstance(event, PokeNotifyEvent) or matcher.plugin_name in other_limit_plugins:
|
if (
|
||||||
|
isinstance(event, GroupMessageEvent)
|
||||||
|
or isinstance(event, PokeNotifyEvent)
|
||||||
|
or matcher.plugin_name in other_limit_plugins
|
||||||
|
):
|
||||||
if status_message_manager.get(event.group_id) is None:
|
if status_message_manager.get(event.group_id) is None:
|
||||||
status_message_manager.delete(event.group_id)
|
status_message_manager.delete(event.group_id)
|
||||||
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
|
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ _flmt = FreqLimiter(300)
|
|||||||
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
||||||
if (
|
if (
|
||||||
(isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent))
|
(isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent))
|
||||||
and matcher.priority not in [1, 9]
|
and matcher.priority not in [1, 999]
|
||||||
) or matcher.plugin_name in other_limit_plugins:
|
) or matcher.plugin_name in other_limit_plugins:
|
||||||
try:
|
try:
|
||||||
if (
|
if (
|
||||||
@@ -58,7 +58,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
|||||||
if not static_flmt.check(event.user_id):
|
if not static_flmt.check(event.user_id):
|
||||||
raise IgnoredException("用户处于黑名单中")
|
raise IgnoredException("用户处于黑名单中")
|
||||||
static_flmt.start_cd(event.user_id)
|
static_flmt.start_cd(event.user_id)
|
||||||
if matcher.priority != 9:
|
if matcher.priority != 999:
|
||||||
try:
|
try:
|
||||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||||
if (
|
if (
|
||||||
@@ -79,7 +79,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
|||||||
if not static_flmt.check(event.user_id):
|
if not static_flmt.check(event.user_id):
|
||||||
raise IgnoredException("用户处于黑名单中")
|
raise IgnoredException("用户处于黑名单中")
|
||||||
static_flmt.start_cd(event.user_id)
|
static_flmt.start_cd(event.user_id)
|
||||||
if matcher.priority != 9:
|
if matcher.priority != 999:
|
||||||
try:
|
try:
|
||||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||||
if ban_result and matcher.plugin_name not in ignore_rst_module:
|
if ban_result and matcher.plugin_name not in ignore_rst_module:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ _blmt = BanCheckLimiter(
|
|||||||
async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State):
|
async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||||
if not isinstance(event, MessageEvent):
|
if not isinstance(event, MessageEvent):
|
||||||
return
|
return
|
||||||
if matcher.type == "message" and matcher.priority not in [1, 9]:
|
if matcher.type == "message" and matcher.priority not in [1, 999]:
|
||||||
if state["_prefix"]["raw_command"]:
|
if state["_prefix"]["raw_command"]:
|
||||||
if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
|
if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
|
||||||
if await BanUser.ban(
|
if await BanUser.ban(
|
||||||
|
|||||||
@@ -20,26 +20,36 @@ def init_none_plugin_count_manager():
|
|||||||
"""
|
"""
|
||||||
清除已删除插件数据
|
清除已删除插件数据
|
||||||
"""
|
"""
|
||||||
modules = [x.module for x in get_matchers()]
|
modules = [x.plugin_name for x in get_matchers()]
|
||||||
for module in none_plugin_count_manager.keys():
|
plugins_manager_list = list(plugins_manager.keys())
|
||||||
if module not in modules:
|
for module in plugins_manager_list:
|
||||||
none_plugin_count_manager.add_count(module)
|
if module not in modules or none_plugin_count_manager.check(module):
|
||||||
else:
|
|
||||||
none_plugin_count_manager.reset(module)
|
|
||||||
if none_plugin_count_manager.check(module):
|
|
||||||
try:
|
try:
|
||||||
plugin_name = plugins_manager.get(module)["plugin_name"]
|
plugin_name = plugins_manager.get(module)["plugin_name"]
|
||||||
except (AttributeError, KeyError):
|
except (AttributeError, KeyError):
|
||||||
plugin_name = ""
|
plugin_name = ""
|
||||||
try:
|
if none_plugin_count_manager.check(module):
|
||||||
plugins2settings_manager.delete(module)
|
try:
|
||||||
plugins2count_manager.delete(module)
|
plugins2settings_manager.delete(module)
|
||||||
plugins2cd_manager.delete(module)
|
plugins2settings_manager.save()
|
||||||
plugins2block_manager.delete(module)
|
plugins2count_manager.delete(module)
|
||||||
plugins_manager.delete(module)
|
plugins2count_manager.save()
|
||||||
resources_manager.remove_resource(module)
|
plugins2cd_manager.delete(module)
|
||||||
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
|
plugins2cd_manager.save()
|
||||||
except Exception as e:
|
plugins2block_manager.delete(module)
|
||||||
logger.error(
|
plugins2block_manager.save()
|
||||||
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}"
|
plugins_manager.delete(module)
|
||||||
)
|
plugins_manager.save()
|
||||||
|
resources_manager.remove_resource(module)
|
||||||
|
none_plugin_count_manager.delete(module)
|
||||||
|
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(
|
||||||
|
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}")
|
||||||
|
else:
|
||||||
|
none_plugin_count_manager.add_count(module)
|
||||||
|
logger.info(
|
||||||
|
f"{module}:{plugin_name} 插件疑似已删除,加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,当前次数:{none_plugin_count_manager._data[module]}")
|
||||||
|
else:
|
||||||
|
none_plugin_count_manager.reset(module)
|
||||||
|
none_plugin_count_manager.save()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from ruamel.yaml import round_trip_load, round_trip_dump, YAML
|
|||||||
from utils.manager import admin_manager, plugins_manager
|
from utils.manager import admin_manager, plugins_manager
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
|
from utils.text_utils import prompt2cn
|
||||||
from utils.utils import get_matchers
|
from utils.utils import get_matchers
|
||||||
from ruamel import yaml
|
from ruamel import yaml
|
||||||
import nonebot
|
import nonebot
|
||||||
@@ -56,7 +57,9 @@ def init_plugins_config(data_path):
|
|||||||
_override=True,
|
_override=True,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
Config.add_plugin_config(matcher.plugin_name, key, plugin_configs[key])
|
Config.add_plugin_config(
|
||||||
|
matcher.plugin_name, key, plugin_configs[key]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
plugin_configs = _data[matcher.plugin_name]
|
plugin_configs = _data[matcher.plugin_name]
|
||||||
for key in plugin_configs:
|
for key in plugin_configs:
|
||||||
@@ -79,7 +82,10 @@ def init_plugins_config(data_path):
|
|||||||
_data[plugin].yaml_set_start_comment(plugin_name, indent=2)
|
_data[plugin].yaml_set_start_comment(plugin_name, indent=2)
|
||||||
# 初始化未设置的管理员权限等级
|
# 初始化未设置的管理员权限等级
|
||||||
for k, v in Config.get_admin_level_data():
|
for k, v in Config.get_admin_level_data():
|
||||||
admin_manager.set_admin_level(k, v)
|
try:
|
||||||
|
admin_manager.set_admin_level(k, v)
|
||||||
|
except KeyError as e:
|
||||||
|
raise KeyError(f"{e} ****** 请检查是否有插件加载失败 ******")
|
||||||
# 存完插件基本设置
|
# 存完插件基本设置
|
||||||
with open(plugins2config_file, "w", encoding="utf8") as wf:
|
with open(plugins2config_file, "w", encoding="utf8") as wf:
|
||||||
round_trip_dump(
|
round_trip_dump(
|
||||||
@@ -96,14 +102,23 @@ def init_plugins_config(data_path):
|
|||||||
for plugin in Config.keys():
|
for plugin in Config.keys():
|
||||||
_tmp_data[plugin] = {}
|
_tmp_data[plugin] = {}
|
||||||
for k in Config[plugin].keys():
|
for k in Config[plugin].keys():
|
||||||
if _data.get(plugin) and k in _data[plugin].keys():
|
try:
|
||||||
Config.set_config(plugin, k, _data[plugin][k])
|
if _data.get(plugin) and k in _data[plugin].keys():
|
||||||
if level2module := Config.get_level2module(plugin, k):
|
Config.set_config(plugin, k, _data[plugin][k])
|
||||||
try:
|
if level2module := Config.get_level2module(plugin, k):
|
||||||
admin_manager.set_admin_level(level2module, _data[plugin][k])
|
try:
|
||||||
except KeyError:
|
admin_manager.set_admin_level(
|
||||||
logger.warning(f"{level2module} 设置权限等级失败:{_data[plugin][k]}")
|
level2module, _data[plugin][k]
|
||||||
_tmp_data[plugin][k] = Config.get_config(plugin, k)
|
)
|
||||||
|
except KeyError:
|
||||||
|
logger.warning(
|
||||||
|
f"{level2module} 设置权限等级失败:{_data[plugin][k]}"
|
||||||
|
)
|
||||||
|
_tmp_data[plugin][k] = Config.get_config(plugin, k)
|
||||||
|
except AttributeError as e:
|
||||||
|
raise AttributeError(
|
||||||
|
f"{e}\n" + prompt2cn("可能为config.yaml配置文件填写不规范", 46)
|
||||||
|
)
|
||||||
Config.save()
|
Config.save()
|
||||||
temp_file = Path() / "configs" / "temp_config.yaml"
|
temp_file = Path() / "configs" / "temp_config.yaml"
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ def init_plugins_cd_limit(data_path):
|
|||||||
_module = _plugin.module
|
_module = _plugin.module
|
||||||
plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
|
plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
|
||||||
plugins2cd_manager.add_cd_limit(
|
plugins2cd_manager.add_cd_limit(
|
||||||
matcher.plugin_name, data_dict=plugin_cd_limit
|
matcher.plugin_name, **plugin_cd_limit
|
||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
@@ -76,7 +76,7 @@ def init_plugins_block_limit(data_path):
|
|||||||
_module = _plugin.module
|
_module = _plugin.module
|
||||||
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
|
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
|
||||||
plugins2block_manager.add_block_limit(
|
plugins2block_manager.add_block_limit(
|
||||||
matcher.plugin_name, data_dict=plugin_block_limit
|
matcher.plugin_name, **plugin_block_limit
|
||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
@@ -124,7 +124,7 @@ def init_plugins_count_limit(data_path):
|
|||||||
_module = _plugin.module
|
_module = _plugin.module
|
||||||
plugin_count_limit = _module.__getattribute__("__plugin_count_limit__")
|
plugin_count_limit = _module.__getattribute__("__plugin_count_limit__")
|
||||||
plugins2count_manager.add_count_limit(
|
plugins2count_manager.add_count_limit(
|
||||||
matcher.plugin_name, data_dict=plugin_count_limit
|
matcher.plugin_name, **plugin_count_limit
|
||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ __plugin_configs__ = {
|
|||||||
|
|
||||||
friend_req = on_request(priority=5, block=True)
|
friend_req = on_request(priority=5, block=True)
|
||||||
group_req = on_request(priority=5, block=True)
|
group_req = on_request(priority=5, block=True)
|
||||||
x = on_message(priority=9, block=False)
|
x = on_message(priority=999, block=False)
|
||||||
|
|
||||||
exists_data = {"private": {}, "group": {}}
|
exists_data = {"private": {}, "group": {}}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message
|
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message, MessageEvent
|
||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.rule import to_me
|
from nonebot.rule import to_me
|
||||||
@@ -24,7 +24,7 @@ __plugin_version__ = 0.1
|
|||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier"
|
||||||
__plugin_configs__ = {
|
__plugin_configs__ = {
|
||||||
"BLACK_WORD": {
|
"BLACK_WORD": {
|
||||||
"value": ["爸", "爹", "爷"],
|
"value": ["爸", "爹", "爷", "父亲"],
|
||||||
"help": "昵称所屏蔽的关键词,会被替换为 *",
|
"help": "昵称所屏蔽的关键词,会被替换为 *",
|
||||||
"default_value": None
|
"default_value": None
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=Tru
|
|||||||
|
|
||||||
|
|
||||||
@nickname.handle()
|
@nickname.handle()
|
||||||
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||||
msg = arg.extract_plain_text().strip()
|
msg = arg.extract_plain_text().strip()
|
||||||
if not msg:
|
if not msg:
|
||||||
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
|
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
|
||||||
@@ -73,7 +73,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
|||||||
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
||||||
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
||||||
f"好突然,突然要叫你昵称什么的...{msg}..",
|
f"好突然,突然要叫你昵称什么的...{msg}..",
|
||||||
f"{NICKNAME}会好好记住的{msg}的,放心吧",
|
f"{NICKNAME}会好好记住{msg}的,放心吧",
|
||||||
f"好..好.,那窝以后就叫你{msg}了.",
|
f"好..好.,那窝以后就叫你{msg}了.",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -90,7 +90,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
|||||||
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
f"好啦好啦,我知道啦,{msg},以后就这么叫你吧",
|
||||||
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}",
|
||||||
f"好突然,突然要叫你昵称什么的...{msg}..",
|
f"好突然,突然要叫你昵称什么的...{msg}..",
|
||||||
f"{NICKNAME}会好好记住的{msg}的,放心吧",
|
f"{NICKNAME}会好好记住{msg}的,放心吧",
|
||||||
f"好..好.,那窝以后就叫你{msg}了.",
|
f"好..好.,那窝以后就叫你{msg}了.",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
from nonebot import on_command, on_regex
|
||||||
|
|
||||||
|
from .data_source import show_plugin_repo, install_plugin, uninstall_plugin
|
||||||
|
from services.log import logger
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
|
||||||
|
from nonebot.params import CommandArg
|
||||||
|
|
||||||
|
from utils.message_builder import image
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
|
||||||
|
|
||||||
|
__zx_plugin_name__ = "插件商店 [Superuser]"
|
||||||
|
__plugin_usage__ = """
|
||||||
|
usage:
|
||||||
|
下载安装插件
|
||||||
|
指令:
|
||||||
|
查看插件仓库
|
||||||
|
安装插件 [name/id]
|
||||||
|
卸载插件 [name/id]
|
||||||
|
""".strip()
|
||||||
|
__plugin_des__ = "从真寻适配仓库中下载插件"
|
||||||
|
__plugin_cmd__ = [""]
|
||||||
|
__plugin_version__ = 0.1
|
||||||
|
__plugin_author__ = "HibiKier"
|
||||||
|
|
||||||
|
show_repo = on_regex("^查看插件仓库$", priority=1, block=True, permission=SUPERUSER)
|
||||||
|
|
||||||
|
install_plugin_matcher = on_command("安装插件", priority=1, block=True, permission=SUPERUSER)
|
||||||
|
|
||||||
|
uninstall_plugin_matcher = on_command("卸载插件", priority=1, block=True, permission=SUPERUSER)
|
||||||
|
|
||||||
|
|
||||||
|
@install_plugin_matcher.handle()
|
||||||
|
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||||
|
arg = arg.extract_plain_text().strip()
|
||||||
|
msg = await install_plugin(arg)
|
||||||
|
await install_plugin_matcher.send(msg)
|
||||||
|
|
||||||
|
|
||||||
|
@uninstall_plugin_matcher.handle()
|
||||||
|
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||||
|
arg = arg.extract_plain_text().strip()
|
||||||
|
msg = await uninstall_plugin(arg)
|
||||||
|
await install_plugin_matcher.send(msg)
|
||||||
|
|
||||||
|
|
||||||
|
@show_repo.handle()
|
||||||
|
async def _(bot: Bot, event: MessageEvent):
|
||||||
|
msg = await show_plugin_repo()
|
||||||
|
if isinstance(msg, int):
|
||||||
|
await show_repo.finish("文件下载失败或解压失败..")
|
||||||
|
await show_repo.send(image(b64=msg))
|
||||||
|
logger.info(
|
||||||
|
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
|
f" 查看插件仓库"
|
||||||
|
)
|
||||||
|
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Union, Tuple
|
||||||
|
|
||||||
|
import ujson as json
|
||||||
|
|
||||||
|
from services import logger
|
||||||
|
from utils.http_utils import AsyncHttpx
|
||||||
|
from configs.path_config import TEMP_PATH, DATA_PATH
|
||||||
|
from utils.image_utils import text2image, BuildImage
|
||||||
|
from utils.utils import is_number
|
||||||
|
|
||||||
|
path = DATA_PATH / "plugin_shop"
|
||||||
|
if not path.exists():
|
||||||
|
path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
repo_json_url = "https://github.com/zhenxun-org/nonebot_plugins_zhenxun_bot/archive/refs/heads/index.zip"
|
||||||
|
repo_zip_path = TEMP_PATH / "plugin_repo_json.zip"
|
||||||
|
plugin_json = path / "zhenxun_plugins.json"
|
||||||
|
|
||||||
|
extensive_plugin_path = Path() / "extensive_plugin"
|
||||||
|
|
||||||
|
path = DATA_PATH / "plugin_shop"
|
||||||
|
if not path.exists():
|
||||||
|
path.mkdir(parents=True, exist_ok=True)
|
||||||
|
if not extensive_plugin_path.exists():
|
||||||
|
extensive_plugin_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
|
||||||
|
async def install_plugin(name: str) -> str:
|
||||||
|
"""
|
||||||
|
安装插件
|
||||||
|
:param name: 插件名或下标
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if is_number(name):
|
||||||
|
name, code = await get_plugin_name(int(name))
|
||||||
|
if code != 200:
|
||||||
|
return name
|
||||||
|
plugin_url = data[name]["download_url"]
|
||||||
|
url = (await AsyncHttpx.get(plugin_url)).headers.get("Location")
|
||||||
|
zip_file = TEMP_PATH / f"{name}.zip"
|
||||||
|
if zip_file.exists():
|
||||||
|
zip_file.unlink()
|
||||||
|
if await AsyncHttpx.download_file(url, zip_file):
|
||||||
|
logger.debug("开始解压插件压缩包...")
|
||||||
|
# 解压
|
||||||
|
zf = zipfile.ZipFile(zip_file, "r")
|
||||||
|
extract_path = TEMP_PATH / f"{name}"
|
||||||
|
if extract_path.exists():
|
||||||
|
shutil.rmtree(extract_path.absolute(), ignore_errors=True)
|
||||||
|
extract_path.mkdir(exist_ok=True, parents=True)
|
||||||
|
for file in zf.namelist():
|
||||||
|
zf.extract(file, extract_path)
|
||||||
|
zf.close()
|
||||||
|
logger.debug("解压插件压缩包完成...")
|
||||||
|
logger.debug("开始移动插件文件夹...")
|
||||||
|
if (extensive_plugin_path / f"{name}").exists():
|
||||||
|
logger.debug("extensive_plugin目录下文件夹已存在,删除该目录插件文件夹...")
|
||||||
|
shutil.rmtree(
|
||||||
|
(extensive_plugin_path / f"{name}").absolute(), ignore_errors=True
|
||||||
|
)
|
||||||
|
extract_path.rename(extensive_plugin_path / f"{name}")
|
||||||
|
tmp = ""
|
||||||
|
if "pyproject.toml" in os.listdir(extensive_plugin_path / f"{name}"):
|
||||||
|
tmp = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
|
||||||
|
os.system(
|
||||||
|
f"poetry run pip install -r {(extensive_plugin_path / f'{name}' / 'pyproject.toml').absolute()}"
|
||||||
|
)
|
||||||
|
logger.debug("移动插件文件夹完成...")
|
||||||
|
logger.info(f"成功安装插件 {name} 成功!\n{tmp}")
|
||||||
|
return f"成功安装插件 {name},请重启bot!"
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"安装插件 {name} 失败 {type(e)}:{e}")
|
||||||
|
return f"安装插件 {name} 失败 {type(e)}:{e}"
|
||||||
|
|
||||||
|
|
||||||
|
async def uninstall_plugin(name: str) -> str:
|
||||||
|
"""
|
||||||
|
删除插件
|
||||||
|
:param name: 插件名或下标
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if is_number(name):
|
||||||
|
name, code = await get_plugin_name(int(name))
|
||||||
|
if code != 200:
|
||||||
|
return name
|
||||||
|
if name not in os.listdir(extensive_plugin_path):
|
||||||
|
return f"未安装 {name} 插件!"
|
||||||
|
shutil.rmtree((extensive_plugin_path / name).absolute(), ignore_errors=True)
|
||||||
|
logger.info(f"插件 {name} 删除成功!")
|
||||||
|
return f"插件 {name} 删除成功!"
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"删除插件 {name} 失败 {type(e)}:{e}")
|
||||||
|
return f"删除插件 {name} 失败 {type(e)}:{e}"
|
||||||
|
|
||||||
|
|
||||||
|
async def show_plugin_repo() -> Union[int, str]:
|
||||||
|
"""
|
||||||
|
获取插件仓库数据并格式化
|
||||||
|
"""
|
||||||
|
if not plugin_json.exists():
|
||||||
|
code = await download_json()
|
||||||
|
if code != 200:
|
||||||
|
return code
|
||||||
|
plugin_info = json.load(open(plugin_json, "r", encoding="utf8"))
|
||||||
|
image_list = []
|
||||||
|
w, h = 0, 0
|
||||||
|
line_height = 10
|
||||||
|
for i, key in enumerate(plugin_info.keys()):
|
||||||
|
data[key] = {
|
||||||
|
"名称": plugin_info[key]["plugin_name"],
|
||||||
|
"模块": key,
|
||||||
|
"作者": plugin_info[key]["author"],
|
||||||
|
"版本": plugin_info[key]["version"],
|
||||||
|
"简介": plugin_info[key]["introduction"],
|
||||||
|
"download_url": plugin_info[key]["download_url"],
|
||||||
|
"github_url": plugin_info[key]["github_url"],
|
||||||
|
}
|
||||||
|
s = (
|
||||||
|
f'id:{i+1}\n名称:{plugin_info[key]["plugin_name"]}\n'
|
||||||
|
f'模块:{key}\n'
|
||||||
|
f'作者:{plugin_info[key]["author"]}\n'
|
||||||
|
f'版本:{plugin_info[key]["version"]}\n'
|
||||||
|
f'简介:{plugin_info[key]["introduction"]}\n'
|
||||||
|
f"-------------------"
|
||||||
|
)
|
||||||
|
img = await text2image(s, font_size=20, color="#f9f6f2")
|
||||||
|
w = w if w > img.w else img.w
|
||||||
|
h += img.h + line_height
|
||||||
|
image_list.append(img)
|
||||||
|
A = BuildImage(w + 100, h + 100, color="#f9f6f2")
|
||||||
|
cur_h = 50
|
||||||
|
for img in image_list:
|
||||||
|
await A.apaste(img, (50, cur_h))
|
||||||
|
cur_h += img.h + line_height
|
||||||
|
return A.pic2bs4()
|
||||||
|
|
||||||
|
|
||||||
|
async def download_json() -> int:
|
||||||
|
"""
|
||||||
|
下载插件库json文件
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
url = (await AsyncHttpx.get(repo_json_url)).headers.get("Location")
|
||||||
|
if repo_zip_path.exists():
|
||||||
|
repo_zip_path.unlink()
|
||||||
|
if await AsyncHttpx.download_file(url, repo_zip_path):
|
||||||
|
zf = zipfile.ZipFile(repo_zip_path, "r")
|
||||||
|
extract_path = path / "temp"
|
||||||
|
for file in zf.namelist():
|
||||||
|
zf.extract(file, extract_path)
|
||||||
|
zf.close()
|
||||||
|
if plugin_json.exists():
|
||||||
|
plugin_json.unlink()
|
||||||
|
(
|
||||||
|
extract_path
|
||||||
|
/ "nonebot_plugins_zhenxun_bot-index"
|
||||||
|
/ "zhenxun_plugins.json"
|
||||||
|
).rename(plugin_json)
|
||||||
|
shutil.rmtree(extract_path.absolute(), ignore_errors=True)
|
||||||
|
return 200
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"下载插件库压缩包失败或解压失败 {type(e)}:{e}")
|
||||||
|
return 999
|
||||||
|
|
||||||
|
|
||||||
|
async def get_plugin_name(name: int) -> Tuple[str, int]:
|
||||||
|
"""
|
||||||
|
通过下标获取插件名
|
||||||
|
:param name: 下标
|
||||||
|
"""
|
||||||
|
name = int(name)
|
||||||
|
if not data:
|
||||||
|
await show_plugin_repo()
|
||||||
|
if name < 1 or name > len(data.keys()):
|
||||||
|
return "下标超过上下限!", 999
|
||||||
|
name = list(data.keys())[name - 1]
|
||||||
|
return name, 200
|
||||||
@@ -108,6 +108,10 @@ async def _():
|
|||||||
"ALTER TABLE genshin ADD bind_group Integer;",
|
"ALTER TABLE genshin ADD bind_group Integer;",
|
||||||
"genshin"
|
"genshin"
|
||||||
), # 新增原神群号绑定字段
|
), # 新增原神群号绑定字段
|
||||||
|
(
|
||||||
|
"ALTER TABLE chat_history ADD plain_text Text;",
|
||||||
|
"chat_history"
|
||||||
|
), # 新增纯文本
|
||||||
]
|
]
|
||||||
for sql in sql_str:
|
for sql in sql_str:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import time
|
|||||||
|
|
||||||
driver: Driver = nonebot.get_driver()
|
driver: Driver = nonebot.get_driver()
|
||||||
|
|
||||||
|
|
||||||
use = require("use")
|
use = require("use")
|
||||||
|
|
||||||
|
|
||||||
@@ -139,8 +140,7 @@ async def register_goods(
|
|||||||
des: str,
|
des: str,
|
||||||
discount: Optional[float] = 1,
|
discount: Optional[float] = 1,
|
||||||
limit_time: Optional[int] = 0,
|
limit_time: Optional[int] = 0,
|
||||||
**kwargs,
|
) -> bool:
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
添加商品
|
添加商品
|
||||||
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
|
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
|
||||||
@@ -151,18 +151,11 @@ async def register_goods(
|
|||||||
:param des: 商品简介
|
:param des: 商品简介
|
||||||
:param discount: 商品折扣
|
:param discount: 商品折扣
|
||||||
:param limit_time: 商品限时销售时间,单位为小时
|
:param limit_time: 商品限时销售时间,单位为小时
|
||||||
:param kwargs: kwargs
|
|
||||||
:return: 是否添加成功
|
:return: 是否添加成功
|
||||||
"""
|
"""
|
||||||
if kwargs:
|
if not await GoodsInfo.get_goods_info(name):
|
||||||
name = kwargs.get("name")
|
|
||||||
price = kwargs.get("price")
|
|
||||||
des = kwargs.get("des")
|
|
||||||
discount = kwargs.get("discount")
|
|
||||||
limit_time = kwargs.get("time_limit")
|
|
||||||
if await GoodsInfo.get_goods_info(name):
|
|
||||||
limit_time = float(limit_time) if limit_time else limit_time
|
limit_time = float(limit_time) if limit_time else limit_time
|
||||||
discount = discount if discount is None else 1
|
discount = discount if discount is not None else 1
|
||||||
limit_time = (
|
limit_time = (
|
||||||
int(time.time() + limit_time * 60 * 60)
|
int(time.time() + limit_time * 60 * 60)
|
||||||
if limit_time is not None and limit_time != 0
|
if limit_time is not None and limit_time != 0
|
||||||
@@ -171,6 +164,7 @@ async def register_goods(
|
|||||||
return await GoodsInfo.add_goods(
|
return await GoodsInfo.add_goods(
|
||||||
name, int(price), des, float(discount), limit_time
|
name, int(price), des, float(discount), limit_time
|
||||||
)
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
# 删除商品
|
# 删除商品
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class GoodsUseFuncManager:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return self._data[goods_name]["func"](
|
return self._data[goods_name]["func"](
|
||||||
**kwargs,
|
*parse_args(args)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
|
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
|||||||
level = 0
|
level = 0
|
||||||
if not msg:
|
if not msg:
|
||||||
await add_group_level.finish("用法:修改群权限 [group] [level]")
|
await add_group_level.finish("用法:修改群权限 [group] [level]")
|
||||||
msg = msg.split(" ")
|
msg = msg.split()
|
||||||
if len(msg) < 2:
|
if len(msg) < 2:
|
||||||
await add_group_level.finish("参数不完全..[group] [level]")
|
await add_group_level.finish("参数不完全..[group] [level]")
|
||||||
if is_number(msg[0]) and is_number(msg[1]):
|
if is_number(msg[0]) and is_number(msg[1]):
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ async def _():
|
|||||||
group_info["group_name"],
|
group_info["group_name"],
|
||||||
group_info["max_member_count"],
|
group_info["max_member_count"],
|
||||||
group_info["member_count"],
|
group_info["member_count"],
|
||||||
|
1
|
||||||
):
|
):
|
||||||
num += 1
|
num += 1
|
||||||
logger.info(f"自动更新群组 {g} 信息成功")
|
logger.info(f"自动更新群组 {g} 信息成功")
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ driver.on_shutdown(disconnect)
|
|||||||
nonebot.load_plugin("nonebot_plugin_apscheduler")
|
nonebot.load_plugin("nonebot_plugin_apscheduler")
|
||||||
nonebot.load_plugins("basic_plugins")
|
nonebot.load_plugins("basic_plugins")
|
||||||
nonebot.load_plugins("plugins")
|
nonebot.load_plugins("plugins")
|
||||||
|
nonebot.load_plugins("extensive_plugin")
|
||||||
# 最后加载权限控制
|
# 最后加载权限控制
|
||||||
nonebot.load_plugins("basic_plugins/hooks")
|
nonebot.load_plugins("basic_plugins/hooks")
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from typing import Optional, Any, Union
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
from ruamel import yaml
|
from ruamel import yaml
|
||||||
|
from ruamel.yaml.scanner import ScannerError
|
||||||
|
|
||||||
|
|
||||||
class ConfigsManager:
|
class ConfigsManager:
|
||||||
@@ -21,9 +22,24 @@ class ConfigsManager:
|
|||||||
if file.exists():
|
if file.exists():
|
||||||
with open(file, "r", encoding="utf8") as f:
|
with open(file, "r", encoding="utf8") as f:
|
||||||
self._data = _yaml.load(f)
|
self._data = _yaml.load(f)
|
||||||
|
if not self._data:
|
||||||
|
self.file.unlink()
|
||||||
|
raise ValueError(
|
||||||
|
"配置文件为空!\n"
|
||||||
|
"***********************************************************\n"
|
||||||
|
"****** 配置文件 plugins2config.yaml 为空,已删除,请重启 ******\n"
|
||||||
|
"***********************************************************"
|
||||||
|
)
|
||||||
if self._simple_file.exists():
|
if self._simple_file.exists():
|
||||||
with open(self._simple_file, "r", encoding="utf8") as f:
|
try:
|
||||||
self._simple_data = _yaml.load(f)
|
with open(self._simple_file, "r", encoding="utf8") as f:
|
||||||
|
self._simple_data = _yaml.load(f)
|
||||||
|
except ScannerError as e:
|
||||||
|
raise ScannerError(
|
||||||
|
f"{e}\n**********************************************\n"
|
||||||
|
f"****** 可能为config.yaml配置文件填写不规范 ******\n"
|
||||||
|
f"**********************************************"
|
||||||
|
)
|
||||||
|
|
||||||
def add_plugin_config(
|
def add_plugin_config(
|
||||||
self,
|
self,
|
||||||
@@ -86,7 +102,10 @@ class ConfigsManager:
|
|||||||
:param value: 值
|
:param value: 值
|
||||||
"""
|
"""
|
||||||
if module in self._data.keys():
|
if module in self._data.keys():
|
||||||
if self._data[module].get(key) is not None and self._data[module][key] != value:
|
if (
|
||||||
|
self._data[module].get(key) is not None
|
||||||
|
and self._data[module][key] != value
|
||||||
|
):
|
||||||
self._data[module][key]["value"] = value
|
self._data[module][key]["value"] = value
|
||||||
self._simple_data[module][key] = value
|
self._simple_data[module][key] = value
|
||||||
self.save()
|
self.save()
|
||||||
@@ -115,7 +134,9 @@ class ConfigsManager:
|
|||||||
self._data[module][key]["default_value"] = value
|
self._data[module][key]["default_value"] = value
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def get_config(self, module: str, key: str, default: Optional[Any] = None) -> Optional[Any]:
|
def get_config(
|
||||||
|
self, module: str, key: str, default: Optional[Any] = None
|
||||||
|
) -> Optional[Any]:
|
||||||
"""
|
"""
|
||||||
获取指定配置值
|
获取指定配置值
|
||||||
:param module: 模块名
|
:param module: 模块名
|
||||||
@@ -161,7 +182,11 @@ class ConfigsManager:
|
|||||||
if save_simple_data:
|
if save_simple_data:
|
||||||
with open(self._simple_file, "w", encoding="utf8") as f:
|
with open(self._simple_file, "w", encoding="utf8") as f:
|
||||||
yaml.dump(
|
yaml.dump(
|
||||||
self._simple_data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
self._simple_data,
|
||||||
|
f,
|
||||||
|
indent=2,
|
||||||
|
Dumper=yaml.RoundTripDumper,
|
||||||
|
allow_unicode=True,
|
||||||
)
|
)
|
||||||
path = path if path else self.file
|
path = path if path else self.file
|
||||||
with open(path, "w", encoding="utf8") as f:
|
with open(path, "w", encoding="utf8") as f:
|
||||||
|
|||||||
+1450
-155
File diff suppressed because it is too large
Load Diff
@@ -11,12 +11,13 @@ class ChatHistory(db.Model):
|
|||||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||||
group_id = db.Column(db.BigInteger())
|
group_id = db.Column(db.BigInteger())
|
||||||
text = db.Column(db.Text())
|
text = db.Column(db.Text())
|
||||||
|
plain_text = db.Column(db.Text())
|
||||||
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
|
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str):
|
async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str, plain_text: str):
|
||||||
await cls.create(
|
await cls.create(
|
||||||
user_qq=user_qq, group_id=group_id, text=text, create_time=datetime.now()
|
user_qq=user_qq, group_id=group_id, text=text, plain_text=plain_text, create_time=datetime.now()
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -97,7 +98,6 @@ class ChatHistory(db.Model):
|
|||||||
if date_scope:
|
if date_scope:
|
||||||
sql += f"AND create_time BETWEEN '{date_scope[0]}' AND '{date_scope[1]}' "
|
sql += f"AND create_time BETWEEN '{date_scope[0]}' AND '{date_scope[1]}' "
|
||||||
sql += f"GROUP BY user_qq ORDER BY sum {order if order and order.upper() != 'DES' else ''} LIMIT {limit}"
|
sql += f"GROUP BY user_qq ORDER BY sum {order if order and order.upper() != 'DES' else ''} LIMIT {limit}"
|
||||||
print(sql)
|
|
||||||
return await db.all(db.text(sql))
|
return await db.all(db.text(sql))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -114,8 +114,7 @@ class GoodsInfo(db.Model):
|
|||||||
参数:
|
参数:
|
||||||
:param goods_name: 商品名称
|
:param goods_name: 商品名称
|
||||||
"""
|
"""
|
||||||
query = await cls.query.where(cls.goods_name == goods_name).gino.first()
|
return await cls.query.where(cls.goods_name == goods_name).gino.first()
|
||||||
return query
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_all_goods(cls) -> List["GoodsInfo"]:
|
async def get_all_goods(cls) -> List["GoodsInfo"]:
|
||||||
|
|||||||
+15
-10
@@ -1,3 +1,5 @@
|
|||||||
|
from asyncpg import UniqueViolationError
|
||||||
|
|
||||||
from services.db_context import db
|
from services.db_context import db
|
||||||
|
|
||||||
|
|
||||||
@@ -44,16 +46,19 @@ class LevelUser(db.Model):
|
|||||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||||
query = query.with_for_update()
|
query = query.with_for_update()
|
||||||
user = await query.gino.first()
|
user = await query.gino.first()
|
||||||
if user is None:
|
try:
|
||||||
await cls.create(
|
if not user:
|
||||||
user_qq=user_qq,
|
await cls.create(
|
||||||
group_id=group_id,
|
user_qq=user_qq,
|
||||||
user_level=level,
|
group_id=group_id,
|
||||||
group_flag=group_flag,
|
user_level=level,
|
||||||
)
|
group_flag=group_flag,
|
||||||
return True
|
)
|
||||||
else:
|
return True
|
||||||
await user.update(user_level=level, group_flag=group_flag).apply()
|
else:
|
||||||
|
await user.update(user_level=level, group_flag=group_flag).apply()
|
||||||
|
return False
|
||||||
|
except UniqueViolationError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Config.add_plugin_config(
|
|||||||
"alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token"
|
"alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token"
|
||||||
)
|
)
|
||||||
|
|
||||||
ai = on_message(rule=to_me(), priority=8)
|
ai = on_message(rule=to_me(), priority=998)
|
||||||
|
|
||||||
|
|
||||||
@ai.handle()
|
@ai.handle()
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
from nonebot.adapters.onebot.v11 import MessageSegment
|
|
||||||
from utils.image_utils import BuildImage
|
|
||||||
from utils.message_builder import image
|
|
||||||
from configs.path_config import IMAGE_PATH
|
|
||||||
from typing import Optional, Tuple, Union
|
from typing import Optional, Tuple, Union
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
@@ -23,27 +19,8 @@ async def get_data(url: str, params: Optional[dict] = None) -> Tuple[Union[dict,
|
|||||||
return "没有搜索到...", 997
|
return "没有搜索到...", 997
|
||||||
return data, 200
|
return data, 200
|
||||||
else:
|
else:
|
||||||
|
if data["code"] == 101:
|
||||||
|
return "缺失ALAPI TOKEN,请在配置文件中填写!", 999
|
||||||
return f'发生了错误...code:{data["code"]}', 999
|
return f'发生了错误...code:{data["code"]}', 999
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
return "超时了....", 998
|
return "超时了....", 998
|
||||||
|
|
||||||
|
|
||||||
def gen_wbtop_pic(data: dict) -> MessageSegment:
|
|
||||||
"""
|
|
||||||
生成微博热搜图片
|
|
||||||
:param data: 微博热搜数据
|
|
||||||
"""
|
|
||||||
bk = BuildImage(700, 32 * 50 + 280, 700, 32, color="#797979")
|
|
||||||
wbtop_bk = BuildImage(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
|
|
||||||
bk.paste(wbtop_bk)
|
|
||||||
text_bk = BuildImage(700, 32 * 50, 700, 32, color="#797979")
|
|
||||||
for i, data in enumerate(data):
|
|
||||||
title = f"{i+1}. {data['hot_word']}"
|
|
||||||
hot = data["hot_word_num"]
|
|
||||||
img = BuildImage(700, 30, font_size=20)
|
|
||||||
w, h = img.getsize(title)
|
|
||||||
img.text((10, int((30 - h) / 2)), title)
|
|
||||||
img.text((580, int((30 - h) / 2)), hot)
|
|
||||||
text_bk.paste(img)
|
|
||||||
bk.paste(text_bk, (0, 280))
|
|
||||||
return image(b64=bk.pic2bs4())
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ usage:
|
|||||||
__plugin_des__ = "非常便利的B站订阅通知"
|
__plugin_des__ = "非常便利的B站订阅通知"
|
||||||
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"]
|
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"]
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier & NumberSir"
|
||||||
__plugin_settings__ = {
|
__plugin_settings__ = {
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"default_status": True,
|
"default_status": True,
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
from bilibili_api.exceptions.ResponseCodeException import ResponseCodeException
|
from bilireq.exceptions import ResponseCodeError
|
||||||
from utils.manager import resources_manager
|
from utils.manager import resources_manager
|
||||||
from asyncio.exceptions import TimeoutError
|
from asyncio.exceptions import TimeoutError
|
||||||
from .model import BilibiliSub
|
from .model import BilibiliSub
|
||||||
from bilibili_api.live import LiveRoom
|
from bilireq.live import get_room_info_by_id
|
||||||
from bilibili_api import bangumi
|
from .utils import get_meta
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from bilibili_api.user import User
|
from bilireq.user import get_user_info
|
||||||
from bilibili_api import user
|
from bilireq import dynamic
|
||||||
|
from .utils import get_videos
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from configs.path_config import IMAGE_PATH
|
from configs.path_config import IMAGE_PATH
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -36,9 +37,9 @@ async def add_live_sub(live_id: int, sub_user: str) -> str:
|
|||||||
try:
|
try:
|
||||||
async with db.transaction():
|
async with db.transaction():
|
||||||
try:
|
try:
|
||||||
live = LiveRoom(live_id)
|
"""bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
|
||||||
live_info = (await live.get_room_info())["room_info"]
|
live_info = await get_room_info_by_id(live_id)
|
||||||
except ResponseCodeException:
|
except ResponseCodeError:
|
||||||
return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确"
|
return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确"
|
||||||
uid = live_info["uid"]
|
uid = live_info["uid"]
|
||||||
room_id = live_info["room_id"]
|
room_id = live_info["room_id"]
|
||||||
@@ -78,16 +79,18 @@ async def add_up_sub(uid: int, sub_user: str) -> str:
|
|||||||
try:
|
try:
|
||||||
async with db.transaction():
|
async with db.transaction():
|
||||||
try:
|
try:
|
||||||
u = user.User(uid)
|
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
|
||||||
user_info = await u.get_user_info()
|
user_info = await get_user_info(uid)
|
||||||
except ResponseCodeException:
|
except ResponseCodeError:
|
||||||
return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
|
return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
|
||||||
uname = user_info["name"]
|
uname = user_info["name"]
|
||||||
dynamic_info = await u.get_dynamics(0)
|
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
|
||||||
|
dynamic_info = await dynamic.get_user_dynamics(uid)
|
||||||
dynamic_upload_time = 0
|
dynamic_upload_time = 0
|
||||||
if dynamic_info.get("cards"):
|
if dynamic_info.get("cards"):
|
||||||
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
||||||
video_info = await u.get_videos()
|
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
|
||||||
|
video_info = await get_videos(uid)
|
||||||
latest_video_created = 0
|
latest_video_created = 0
|
||||||
if video_info["list"].get("vlist"):
|
if video_info["list"].get("vlist"):
|
||||||
latest_video_created = video_info["list"]["vlist"][0]["created"]
|
latest_video_created = video_info["list"]["vlist"][0]["created"]
|
||||||
@@ -117,8 +120,9 @@ async def add_season_sub(media_id: int, sub_user: str) -> str:
|
|||||||
try:
|
try:
|
||||||
async with db.transaction():
|
async with db.transaction():
|
||||||
try:
|
try:
|
||||||
season_info = await bangumi.get_meta(media_id)
|
"""bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
|
||||||
except ResponseCodeException:
|
season_info = await get_meta(media_id)
|
||||||
|
except ResponseCodeError:
|
||||||
return f"未找到media_id:{media_id} 的信息,请检查Id是否正确"
|
return f"未找到media_id:{media_id} 的信息,请检查Id是否正确"
|
||||||
season_id = season_info["media"]["season_id"]
|
season_id = season_info["media"]["season_id"]
|
||||||
season_current_episode = season_info["media"]["new_ep"]["index"]
|
season_current_episode = season_info["media"]["new_ep"]["index"]
|
||||||
@@ -200,7 +204,7 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
|||||||
return await _get_up_status(id_)
|
return await _get_up_status(id_)
|
||||||
elif sub_type == "season":
|
elif sub_type == "season":
|
||||||
return await _get_season_status(id_)
|
return await _get_season_status(id_)
|
||||||
except ResponseCodeException:
|
except ResponseCodeError:
|
||||||
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||||
# except Exception as e:
|
# except Exception as e:
|
||||||
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
|
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
|
||||||
@@ -212,12 +216,12 @@ async def _get_live_status(id_: int) -> Optional[str]:
|
|||||||
获取直播订阅状态
|
获取直播订阅状态
|
||||||
:param id_: 直播间 id
|
:param id_: 直播间 id
|
||||||
"""
|
"""
|
||||||
live = LiveRoom(id_)
|
"""bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
|
||||||
live_info = (await live.get_room_info())["room_info"]
|
live_info = await get_room_info_by_id(id_)
|
||||||
title = live_info["title"]
|
title = live_info["title"]
|
||||||
room_id = live_info["room_id"]
|
room_id = live_info["room_id"]
|
||||||
live_status = live_info["live_status"]
|
live_status = live_info["live_status"]
|
||||||
cover = live_info["cover"]
|
cover = live_info["user_cover"]
|
||||||
sub = await BilibiliSub.get_sub(id_)
|
sub = await BilibiliSub.get_sub(id_)
|
||||||
if sub.live_status != live_status:
|
if sub.live_status != live_status:
|
||||||
await BilibiliSub.update_sub_info(id_, live_status=live_status)
|
await BilibiliSub.update_sub_info(id_, live_status=live_status)
|
||||||
@@ -238,15 +242,16 @@ async def _get_up_status(id_: int) -> Optional[str]:
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
_user = await BilibiliSub.get_sub(id_)
|
_user = await BilibiliSub.get_sub(id_)
|
||||||
u = user.User(_user.uid)
|
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
|
||||||
user_info = await u.get_user_info()
|
user_info = await get_user_info(_user.uid)
|
||||||
uname = user_info["name"]
|
uname = user_info["name"]
|
||||||
video_info = await u.get_videos()
|
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
|
||||||
|
video_info = await get_videos(id_)
|
||||||
latest_video_created = 0
|
latest_video_created = 0
|
||||||
video = None
|
video = None
|
||||||
if _user.uname != uname:
|
if _user.uname != uname:
|
||||||
await BilibiliSub.update_sub_info(id_, uname=uname)
|
await BilibiliSub.update_sub_info(id_, uname=uname)
|
||||||
dynamic_img, dynamic_upload_time = await get_user_dynamic(u, _user)
|
dynamic_img, dynamic_upload_time = await get_user_dynamic(id_, _user)
|
||||||
if video_info["list"].get("vlist"):
|
if video_info["list"].get("vlist"):
|
||||||
video = video_info["list"]["vlist"][0]
|
video = video_info["list"]["vlist"][0]
|
||||||
latest_video_created = video["created"]
|
latest_video_created = video["created"]
|
||||||
@@ -280,7 +285,8 @@ async def _get_season_status(id_) -> Optional[str]:
|
|||||||
获取 番剧 更新状态
|
获取 番剧 更新状态
|
||||||
:param id_: 番剧 id
|
:param id_: 番剧 id
|
||||||
"""
|
"""
|
||||||
season_info = await bangumi.get_meta(id_)
|
"""bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
|
||||||
|
season_info = await get_meta(id_)
|
||||||
title = season_info["media"]["title"]
|
title = season_info["media"]["title"]
|
||||||
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode
|
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode
|
||||||
new_ep = season_info["media"]["new_ep"]["index"]
|
new_ep = season_info["media"]["new_ep"]["index"]
|
||||||
@@ -297,15 +303,16 @@ async def _get_season_status(id_) -> Optional[str]:
|
|||||||
|
|
||||||
|
|
||||||
async def get_user_dynamic(
|
async def get_user_dynamic(
|
||||||
u: User, local_user: BilibiliSub
|
uid: int, local_user: BilibiliSub
|
||||||
) -> "Optional[MessageSegment], int":
|
) -> "Optional[MessageSegment], int":
|
||||||
"""
|
"""
|
||||||
获取用户动态
|
获取用户动态
|
||||||
:param u: 用户类
|
:param uid: 用户uid
|
||||||
:param local_user: 数据库存储的用户数据
|
:param local_user: 数据库存储的用户数据
|
||||||
:return: 最新动态截图与时间
|
:return: 最新动态截图与时间
|
||||||
"""
|
"""
|
||||||
dynamic_info = await u.get_dynamics(0)
|
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
|
||||||
|
dynamic_info = await dynamic.get_user_dynamics(uid)
|
||||||
browser = await get_browser()
|
browser = await get_browser()
|
||||||
if dynamic_info.get("cards") and browser:
|
if dynamic_info.get("cards") and browser:
|
||||||
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
||||||
@@ -317,21 +324,21 @@ async def get_user_dynamic(
|
|||||||
wait_until="networkidle",
|
wait_until="networkidle",
|
||||||
timeout=10000,
|
timeout=10000,
|
||||||
)
|
)
|
||||||
await page.set_viewport_size({"width": 2560, "height": 1080})
|
await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s
|
||||||
# 删除置顶
|
# 删除置顶
|
||||||
await page.evaluate(
|
await page.evaluate(
|
||||||
"""
|
"""
|
||||||
xs = document.getElementsByClassName('first-card-with-title');
|
xs = document.getElementsByClassName('bili-dyn-item__tag');
|
||||||
for (x of xs) {
|
for (x of xs) {
|
||||||
x.remove();
|
x.parentNode.parentNode.remove();
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
card = await page.query_selector(".card")
|
card = page.locator(".bili-dyn-list__item").first
|
||||||
|
await card.wait_for()
|
||||||
# 截图并保存
|
# 截图并保存
|
||||||
await card.screenshot(
|
await card.screenshot(
|
||||||
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||||
timeout=100000,
|
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
|
logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
from utils.image_utils import BuildImage
|
from utils.image_utils import BuildImage
|
||||||
from configs.path_config import IMAGE_PATH
|
from configs.path_config import IMAGE_PATH
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
from bilibili_api import user
|
# from bilibili_api import user
|
||||||
|
from bilireq.user import get_user_info
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
|
||||||
@@ -28,8 +29,8 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
|
|||||||
:param des: 直播简介
|
:param des: 直播简介
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
u = user.User(uid)
|
|
||||||
user_info = await u.get_user_info()
|
user_info = await get_user_info(uid)
|
||||||
name = user_info["name"]
|
name = user_info["name"]
|
||||||
sex = user_info["sex"]
|
sex = user_info["sex"]
|
||||||
face = user_info["face"]
|
face = user_info["face"]
|
||||||
@@ -37,7 +38,6 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
|
|||||||
ava = BuildImage(100, 100, background=BytesIO(await get_pic(face)))
|
ava = BuildImage(100, 100, background=BytesIO(await get_pic(face)))
|
||||||
ava.circle()
|
ava.circle()
|
||||||
cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover)))
|
cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover)))
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
def _create_live_des_image(
|
def _create_live_des_image(
|
||||||
@@ -68,3 +68,47 @@ def _create_live_des_image(
|
|||||||
border_img = BuildImage(1772, 2657, background=border)
|
border_img = BuildImage(1772, 2657, background=border)
|
||||||
bk = BuildImage(1772, 2657, font_size=30)
|
bk = BuildImage(1772, 2657, font_size=30)
|
||||||
bk.paste(cover, (0, 100), center_type="by_width")
|
bk.paste(cover, (0, 100), center_type="by_width")
|
||||||
|
|
||||||
|
|
||||||
|
async def get_meta(media_id: int, auth=None, reqtype="both", **kwargs):
|
||||||
|
"""
|
||||||
|
根据番剧 ID 获取番剧元数据信息,
|
||||||
|
作为bilibili_api和bilireq的替代品。
|
||||||
|
如果bilireq.bangumi更新了,可以转为调用bilireq.bangumi的get_meta方法,两者完全一致。
|
||||||
|
"""
|
||||||
|
from bilireq.utils import get
|
||||||
|
|
||||||
|
BASE_URL = "https://api.bilibili.com"
|
||||||
|
url = f"{BASE_URL}/pgc/review/user"
|
||||||
|
params = {"media_id": media_id}
|
||||||
|
raw_json = await get(url, raw=True, params=params, auth=auth, reqtype=reqtype, **kwargs)
|
||||||
|
return raw_json['result']
|
||||||
|
|
||||||
|
|
||||||
|
async def get_videos(
|
||||||
|
uid: int, tid: int = 0, pn: int = 1, keyword: str = "", order: str = "pubdate",
|
||||||
|
*, auth=None, reqtype="both", **kwargs
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
获取用户投该视频信息
|
||||||
|
作为bilibili_api和bilireq的替代品。
|
||||||
|
如果bilireq.user更新了,可以转为调用bilireq.user的get_videos方法,两者完全一致。
|
||||||
|
|
||||||
|
:param uid: 用户 UID
|
||||||
|
:param tid: 分区 ID
|
||||||
|
:param pn: 页码
|
||||||
|
:param keyword: 搜索关键词
|
||||||
|
:param order: 排序方式,可以为 “pubdate(上传日期从新到旧), stow(收藏从多到少), click(播放量从多到少)”
|
||||||
|
"""
|
||||||
|
from bilireq.utils import get
|
||||||
|
BASE_URL = "https://api.bilibili.com"
|
||||||
|
url = f"{BASE_URL}/x/space/arc/search"
|
||||||
|
params = {
|
||||||
|
"mid": uid,
|
||||||
|
"ps": 30,
|
||||||
|
"tid": tid,
|
||||||
|
"pn": pn,
|
||||||
|
"keyword": keyword,
|
||||||
|
"order": order
|
||||||
|
}
|
||||||
|
return await get(url, params=params, auth=auth, reqtype=reqtype, **kwargs)
|
||||||
@@ -8,6 +8,7 @@ from nonebot.adapters.onebot.v11 import (
|
|||||||
from nonebot.matcher import Matcher
|
from nonebot.matcher import Matcher
|
||||||
from nonebot.message import run_preprocessor
|
from nonebot.message import run_preprocessor
|
||||||
from utils.image_utils import BuildImage
|
from utils.image_utils import BuildImage
|
||||||
|
from utils.manager import group_manager
|
||||||
from utils.utils import get_message_text, is_number
|
from utils.utils import get_message_text, is_number
|
||||||
from nonebot.params import RegexGroup, CommandArg
|
from nonebot.params import RegexGroup, CommandArg
|
||||||
from .utils import black_word_manager
|
from .utils import black_word_manager
|
||||||
@@ -155,7 +156,11 @@ async def _(
|
|||||||
and matcher.plugin_name == "black_word"
|
and matcher.plugin_name == "black_word"
|
||||||
and not await BanUser.is_ban(event.user_id)
|
and not await BanUser.is_ban(event.user_id)
|
||||||
and str(event.user_id) not in bot.config.superusers
|
and str(event.user_id) not in bot.config.superusers
|
||||||
|
and not get_message_text(event.json()).startswith("原神绑定")
|
||||||
):
|
):
|
||||||
|
# 屏蔽群权限-1的群
|
||||||
|
if isinstance(event, GroupMessageEvent) and group_manager.get_group_level(event.group_id) < 0:
|
||||||
|
return
|
||||||
user_id = event.user_id
|
user_id = event.user_id
|
||||||
group_id = event.group_id if isinstance(event, GroupMessageEvent) else None
|
group_id = event.group_id if isinstance(event, GroupMessageEvent) else None
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
@@ -241,7 +246,6 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
|
|||||||
uid = int(msg[0])
|
uid = int(msg[0])
|
||||||
id_ = int(msg[1])
|
id_ = int(msg[1])
|
||||||
punish_level = int(msg[2])
|
punish_level = int(msg[2])
|
||||||
print(uid, id_, punish_level)
|
|
||||||
rst = await set_user_punish(uid, id_, punish_level)
|
rst = await set_user_punish(uid, id_, punish_level)
|
||||||
await set_punish.send(rst)
|
await set_punish.send(rst)
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ async def show_black_text_image(
|
|||||||
(punish_level_str, "等级"),
|
(punish_level_str, "等级"),
|
||||||
(create_time_str, "记录日期"),
|
(create_time_str, "记录日期"),
|
||||||
]:
|
]:
|
||||||
img = await text2image(s, color="#f9f6f2", _add_height=3.32)
|
img = await text2image(s, color="#f9f6f2", _add_height=2.1)
|
||||||
w = _tmp_img.getsize(type_)[0] if _tmp_img.getsize(type_)[0] > img.w else img.w
|
w = _tmp_img.getsize(type_)[0] if _tmp_img.getsize(type_)[0] > img.w else img.w
|
||||||
A = BuildImage(w + 11, img.h + 50, color="#f9f6f2", font_size=35, font="CJGaoDeGuo.otf")
|
A = BuildImage(w + 11, img.h + 50, color="#f9f6f2", font_size=35, font="CJGaoDeGuo.otf")
|
||||||
await A.atext((10, 10), type_)
|
await A.atext((10, 10), type_)
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ class BlackWord(db.Model):
|
|||||||
user = await query.where(cls.black_word == black_word).order_by(cls.id.desc()).gino.first()
|
user = await query.where(cls.black_word == black_word).order_by(cls.id.desc()).gino.first()
|
||||||
elif id_:
|
elif id_:
|
||||||
user_list = await query.gino.all()
|
user_list = await query.gino.all()
|
||||||
print(len(user_list))
|
|
||||||
if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)):
|
if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)):
|
||||||
return False
|
return False
|
||||||
user = user_list[id_]
|
user = user_list[id_]
|
||||||
|
|||||||
@@ -88,9 +88,7 @@ class BlackWordManager:
|
|||||||
:param group_id: 群号
|
:param group_id: 群号
|
||||||
:param message: 消息
|
:param message: 消息
|
||||||
"""
|
"""
|
||||||
print(user_id, group_id, message)
|
|
||||||
if data := self._check(message):
|
if data := self._check(message):
|
||||||
print(data)
|
|
||||||
if data[0]:
|
if data[0]:
|
||||||
await _add_user_black_word(
|
await _add_user_black_word(
|
||||||
user_id, group_id, data[0], message, int(data[1])
|
user_id, group_id, data[0], message, int(data[1])
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ from configs.config import Config
|
|||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
if platform.system() == "Windows":
|
# if platform.system() == "Windows":
|
||||||
import asyncio
|
# import asyncio
|
||||||
|
#
|
||||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||||
|
|
||||||
|
|
||||||
url = "http://www.eclzz.mobi"
|
url = "http://www.eclzz.win"
|
||||||
|
|
||||||
|
|
||||||
async def get_bt_info(keyword: str, page: int):
|
async def get_bt_info(keyword: str, page: int):
|
||||||
@@ -19,7 +19,7 @@ async def get_bt_info(keyword: str, page: int):
|
|||||||
:param page: 页数
|
:param page: 页数
|
||||||
"""
|
"""
|
||||||
text = (await AsyncHttpx.get(f"{url}/s/{keyword}_rel_{page}.html", timeout=5)).text
|
text = (await AsyncHttpx.get(f"{url}/s/{keyword}_rel_{page}.html", timeout=5)).text
|
||||||
if text.find("大约0条结果") != -1:
|
if "大约0条结果" in text:
|
||||||
return
|
return
|
||||||
soup = BeautifulSoup(text, "lxml")
|
soup = BeautifulSoup(text, "lxml")
|
||||||
item_lst = soup.find_all("div", {"class": "search-item"})
|
item_lst = soup.find_all("div", {"class": "search-item"})
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ __plugin_cmd__ = ["检查更新真寻", "重启"]
|
|||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier"
|
||||||
__plugin_configs__ = {
|
__plugin_configs__ = {
|
||||||
|
"UPDATE_REMIND": {
|
||||||
|
"value": True,
|
||||||
|
"help": "真寻是否自动检查更新",
|
||||||
|
"default": True,
|
||||||
|
},
|
||||||
"AUTO_UPDATE_ZHENXUN": {
|
"AUTO_UPDATE_ZHENXUN": {
|
||||||
"value": False,
|
"value": False,
|
||||||
"help": "真寻是否自动检查更新",
|
"help": "真寻是否自动检查更新",
|
||||||
@@ -72,7 +77,7 @@ async def _():
|
|||||||
await restart.finish("暂无windows重启脚本...")
|
await restart.finish("暂无windows重启脚本...")
|
||||||
|
|
||||||
|
|
||||||
@restart.got("flag", prompt="确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)")
|
@restart.got("flag", prompt="确定是否重启真寻?确定请回复[是|好|确定](重启失败咱们将失去联系,请谨慎!)")
|
||||||
async def _(flag: str = ArgStr("flag")):
|
async def _(flag: str = ArgStr("flag")):
|
||||||
if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
|
if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
|
||||||
await restart.send("开始重启真寻..请稍等...")
|
await restart.send("开始重启真寻..请稍等...")
|
||||||
@@ -88,7 +93,7 @@ async def _(flag: str = ArgStr("flag")):
|
|||||||
minute=0,
|
minute=0,
|
||||||
)
|
)
|
||||||
async def _():
|
async def _():
|
||||||
if Config.get_config("check_zhenxun_update", "AUTO_UPDATE_ZHENXUN"):
|
if Config.get_config("check_zhenxun_update", "UPDATE_REMIND"):
|
||||||
_version = "v0.0.0"
|
_version = "v0.0.0"
|
||||||
_version_file = Path() / "__version__"
|
_version_file = Path() / "__version__"
|
||||||
if _version_file.exists():
|
if _version_file.exists():
|
||||||
@@ -108,17 +113,18 @@ async def _():
|
|||||||
message=f"检测到真寻版本更新\n"
|
message=f"检测到真寻版本更新\n"
|
||||||
f"当前版本:{_version},最新版本:{latest_version}",
|
f"当前版本:{_version},最新版本:{latest_version}",
|
||||||
)
|
)
|
||||||
# try:
|
if Config.get_config("check_zhenxun_update", "AUTO_UPDATE_ZHENXUN"):
|
||||||
# code = await check_update(bot)
|
try:
|
||||||
# except Exception as e:
|
code = await check_update(bot)
|
||||||
# logger.error(f"更新真寻未知错误 {type(e)}:{e}")
|
except Exception as e:
|
||||||
# await bot.send_private_msg(
|
logger.error(f"更新真寻未知错误 {type(e)}:{e}")
|
||||||
# user_id=int(list(bot.config.superusers)[0]),
|
await bot.send_private_msg(
|
||||||
# message=f"更新真寻未知错误 {type(e)}:{e}\n",
|
user_id=int(list(bot.config.superusers)[0]),
|
||||||
# )
|
message=f"更新真寻未知错误 {type(e)}:{e}\n",
|
||||||
# else:
|
)
|
||||||
# if code == 200:
|
else:
|
||||||
# await bot.send_private_msg(
|
if code == 200:
|
||||||
# user_id=int(list(bot.config.superusers)[0]),
|
await bot.send_private_msg(
|
||||||
# message=f"更新完毕,请重启真寻....",
|
user_id=int(list(bot.config.superusers)[0]),
|
||||||
# )
|
message=f"更新完毕,请重启真寻....",
|
||||||
|
)
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import tarfile
|
|||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
|
|
||||||
if str(platform.system()).lower() == "windows":
|
# if str(platform.system()).lower() == "windows":
|
||||||
policy = asyncio.WindowsSelectorEventLoopPolicy()
|
# policy = asyncio.WindowsSelectorEventLoopPolicy()
|
||||||
asyncio.set_event_loop_policy(policy)
|
# asyncio.set_event_loop_policy(policy)
|
||||||
|
|
||||||
|
|
||||||
driver = nonebot.get_driver()
|
driver = nonebot.get_driver()
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ __plugin_settings__ = {
|
|||||||
dialogue_data = {}
|
dialogue_data = {}
|
||||||
|
|
||||||
|
|
||||||
dialogue = on_command("[滴滴滴]", aliases={"滴滴滴-"}, priority=5, block=True)
|
dialogue = on_command("[滴滴滴]", aliases={"滴滴滴-"}, priority=5, block=True)
|
||||||
reply = on_command("/t", priority=1, permission=SUPERUSER, block=True)
|
reply = on_command("/t", priority=1, permission=SUPERUSER, block=True)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from .handles.onmyoji_handle import OnmyojiHandle
|
|||||||
from .handles.pcr_handle import PcrHandle
|
from .handles.pcr_handle import PcrHandle
|
||||||
from .handles.pretty_handle import PrettyHandle
|
from .handles.pretty_handle import PrettyHandle
|
||||||
from .handles.prts_handle import PrtsHandle
|
from .handles.prts_handle import PrtsHandle
|
||||||
|
from .handles.ba_handle import BaHandle
|
||||||
|
|
||||||
from .config import draw_config
|
from .config import draw_config
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ from .config import draw_config
|
|||||||
__zx_plugin_name__ = "游戏抽卡"
|
__zx_plugin_name__ = "游戏抽卡"
|
||||||
__plugin_usage__ = """
|
__plugin_usage__ = """
|
||||||
usage:
|
usage:
|
||||||
模拟赛马娘,原神,明日方舟,坎公骑冠剑,公主连结(国/台),碧蓝航线,FGO,阴阳师进行抽卡
|
模拟赛马娘,原神,明日方舟,坎公骑冠剑,公主连结(国/台),碧蓝航线,FGO,阴阳师,碧蓝档案进行抽卡
|
||||||
指令:
|
指令:
|
||||||
原神[1-180]抽: 原神常驻池
|
原神[1-180]抽: 原神常驻池
|
||||||
原神角色[1-180]抽: 原神角色UP池子
|
原神角色[1-180]抽: 原神角色UP池子
|
||||||
@@ -43,6 +44,7 @@ usage:
|
|||||||
碧蓝航线/碧蓝[重型/轻型/特型/活动][1-300]抽: 碧蓝航线重型/轻型/特型/活动卡池
|
碧蓝航线/碧蓝[重型/轻型/特型/活动][1-300]抽: 碧蓝航线重型/轻型/特型/活动卡池
|
||||||
fgo[1-300]抽: fgo卡池
|
fgo[1-300]抽: fgo卡池
|
||||||
阴阳师[1-300]抽: 阴阳师卡池
|
阴阳师[1-300]抽: 阴阳师卡池
|
||||||
|
ba/碧蓝档案[1-200]抽:碧蓝档案卡池
|
||||||
* 以上指令可以通过 XX一井 来指定最大抽取数量 *
|
* 以上指令可以通过 XX一井 来指定最大抽取数量 *
|
||||||
* 示例:原神一井 *
|
* 示例:原神一井 *
|
||||||
""".strip()
|
""".strip()
|
||||||
@@ -73,6 +75,7 @@ __plugin_cmd__ = [
|
|||||||
"pcr/公主连接[1-300]抽",
|
"pcr/公主连接[1-300]抽",
|
||||||
"fgo[1-300]抽",
|
"fgo[1-300]抽",
|
||||||
"阴阳师[1-300]抽",
|
"阴阳师[1-300]抽",
|
||||||
|
"碧蓝档案[1-200]抽",
|
||||||
"更新方舟信息 [_superuser]",
|
"更新方舟信息 [_superuser]",
|
||||||
"重载方舟卡池 [_superuser]",
|
"重载方舟卡池 [_superuser]",
|
||||||
"更新原神信息 [_superuser]",
|
"更新原神信息 [_superuser]",
|
||||||
@@ -83,6 +86,7 @@ __plugin_cmd__ = [
|
|||||||
"更新碧蓝航线信息 [_superuser]",
|
"更新碧蓝航线信息 [_superuser]",
|
||||||
"更新fgo信息 [_superuser]",
|
"更新fgo信息 [_superuser]",
|
||||||
"更新阴阳师信息 [_superuser]",
|
"更新阴阳师信息 [_superuser]",
|
||||||
|
"更新碧蓝档案信息 [_superuser]",
|
||||||
]
|
]
|
||||||
__plugin_type__ = ("抽卡相关", 1)
|
__plugin_type__ = ("抽卡相关", 1)
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.1
|
||||||
@@ -105,7 +109,7 @@ class Game:
|
|||||||
|
|
||||||
|
|
||||||
games = (
|
games = (
|
||||||
Game({"azur", "碧蓝", "碧蓝航线"}, AzurHandle(), draw_config.AZUR_FLAG),
|
Game({"azur", "碧蓝航线"}, AzurHandle(), draw_config.AZUR_FLAG),
|
||||||
Game({"fgo", "命运冠位指定"}, FgoHandle(), draw_config.FGO_FLAG),
|
Game({"fgo", "命运冠位指定"}, FgoHandle(), draw_config.FGO_FLAG),
|
||||||
Game(
|
Game(
|
||||||
{"genshin", "原神"},
|
{"genshin", "原神"},
|
||||||
@@ -130,6 +134,11 @@ games = (
|
|||||||
reload_time=4,
|
reload_time=4,
|
||||||
),
|
),
|
||||||
Game({"prts", "方舟", "明日方舟"}, PrtsHandle(), draw_config.PRTS_FLAG, reload_time=4),
|
Game({"prts", "方舟", "明日方舟"}, PrtsHandle(), draw_config.PRTS_FLAG, reload_time=4),
|
||||||
|
Game(
|
||||||
|
{"ba","碧蓝档案"},BaHandle(),
|
||||||
|
draw_config.BA_FLAG,
|
||||||
|
max_count=200,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,12 @@ class OnmyojiConfig(BaseModel, extra=Extra.ignore):
|
|||||||
ONMYOJI_SR: float = 0.2
|
ONMYOJI_SR: float = 0.2
|
||||||
ONMYOJI_R: float = 0.7875
|
ONMYOJI_R: float = 0.7875
|
||||||
|
|
||||||
|
#碧蓝档案
|
||||||
|
class BaConfig(BaseModel, extra=Extra.ignore):
|
||||||
|
BA_THREE_P: float = 0.025
|
||||||
|
BA_TWO_P: float = 0.185
|
||||||
|
BA_ONE_P: float = 0.79
|
||||||
|
BA_G_TWO_P: float = 0.975
|
||||||
|
|
||||||
class Config(BaseModel, extra=Extra.ignore):
|
class Config(BaseModel, extra=Extra.ignore):
|
||||||
# 开关
|
# 开关
|
||||||
@@ -98,6 +104,7 @@ class Config(BaseModel, extra=Extra.ignore):
|
|||||||
AZUR_FLAG: bool = AConfig.get_config("draw_card", "AZUR_FLAG")
|
AZUR_FLAG: bool = AConfig.get_config("draw_card", "AZUR_FLAG")
|
||||||
FGO_FLAG: bool = AConfig.get_config("draw_card", "FGO_FLAG")
|
FGO_FLAG: bool = AConfig.get_config("draw_card", "FGO_FLAG")
|
||||||
ONMYOJI_FLAG: bool = AConfig.get_config("draw_card", "ONMYOJI_FLAG")
|
ONMYOJI_FLAG: bool = AConfig.get_config("draw_card", "ONMYOJI_FLAG")
|
||||||
|
BA_FLAG: bool = AConfig.get_config("draw_card", "BA_FLAG")
|
||||||
|
|
||||||
# 其他配置
|
# 其他配置
|
||||||
PCR_TAI: bool = AConfig.get_config("draw_card", "PCR_TAI")
|
PCR_TAI: bool = AConfig.get_config("draw_card", "PCR_TAI")
|
||||||
@@ -112,6 +119,7 @@ class Config(BaseModel, extra=Extra.ignore):
|
|||||||
azur: AzurConfig = AzurConfig()
|
azur: AzurConfig = AzurConfig()
|
||||||
fgo: FgoConfig = FgoConfig()
|
fgo: FgoConfig = FgoConfig()
|
||||||
onmyoji: OnmyojiConfig = OnmyojiConfig()
|
onmyoji: OnmyojiConfig = OnmyojiConfig()
|
||||||
|
ba: BaConfig = BaConfig()
|
||||||
|
|
||||||
|
|
||||||
driver = nonebot.get_driver()
|
driver = nonebot.get_driver()
|
||||||
@@ -133,8 +141,9 @@ for game_flag, game_name in zip(
|
|||||||
"FGO_FLAG",
|
"FGO_FLAG",
|
||||||
"ONMYOJI_FLAG",
|
"ONMYOJI_FLAG",
|
||||||
"PCR_TAI",
|
"PCR_TAI",
|
||||||
|
"BA_FLAG"
|
||||||
],
|
],
|
||||||
["明日方舟", "原神", "赛马娘", "坎公骑冠剑", "公主连结", "碧蓝航线", "命运-冠位指定(FGO)", "阴阳师", "pcr台服卡池"],
|
["明日方舟", "原神", "赛马娘", "坎公骑冠剑", "公主连结", "碧蓝航线", "命运-冠位指定(FGO)", "阴阳师", "pcr台服卡池","碧蓝档案"],
|
||||||
):
|
):
|
||||||
AConfig.add_plugin_config(
|
AConfig.add_plugin_config(
|
||||||
"draw_card",
|
"draw_card",
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ class AzurHandle(BaseHandle[AzurChar]):
|
|||||||
type_ = ship.xpath("./tbody/tr/td[2]/p/small/text()")[0] # 舰船类型
|
type_ = ship.xpath("./tbody/tr/td[2]/p/small/text()")[0] # 舰船类型
|
||||||
try:
|
try:
|
||||||
p = float(str(ship.xpath(".//sup/text()")[0]).strip("%"))
|
p = float(str(ship.xpath(".//sup/text()")[0]).strip("%"))
|
||||||
except IndexError:
|
except (IndexError, ValueError):
|
||||||
p = 0
|
p = 0
|
||||||
star = self.parse_star(
|
star = self.parse_star(
|
||||||
ship.xpath("./tbody/tr/td[1]/div/div/div/a/img/@alt")[0]
|
ship.xpath("./tbody/tr/td[1]/div/div/div/a/img/@alt")[0]
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
import random
|
||||||
|
from lxml import etree
|
||||||
|
from typing import List, Tuple
|
||||||
|
from PIL import ImageDraw
|
||||||
|
from urllib.parse import unquote
|
||||||
|
from nonebot.log import logger
|
||||||
|
|
||||||
|
from .base_handle import BaseHandle, BaseData
|
||||||
|
from ..config import draw_config
|
||||||
|
from ..util import remove_prohibited_str, cn2py, load_font
|
||||||
|
from utils.image_utils import BuildImage
|
||||||
|
|
||||||
|
|
||||||
|
class BaChar(BaseData):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BaHandle(BaseHandle[BaChar]):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("ba", "碧蓝档案")
|
||||||
|
self.max_star = 3
|
||||||
|
self.config = draw_config.ba
|
||||||
|
self.ALL_CHAR: List[BaChar] = []
|
||||||
|
|
||||||
|
def get_card(self, mode: int = 1) -> BaChar:
|
||||||
|
if mode == 2:
|
||||||
|
star = self.get_star(
|
||||||
|
[3, 2], [self.config.BA_THREE_P, self.config.BA_G_TWO_P]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
star = self.get_star(
|
||||||
|
[3, 2, 1],
|
||||||
|
[self.config.BA_THREE_P, self.config.BA_TWO_P, self.config.BA_ONE_P],
|
||||||
|
)
|
||||||
|
chars = [x for x in self.ALL_CHAR if x.star == star and not x.limited]
|
||||||
|
return random.choice(chars)
|
||||||
|
|
||||||
|
def get_cards(self, count: int, **kwargs) -> List[Tuple[BaChar, int]]:
|
||||||
|
card_list = []
|
||||||
|
card_count = 0 # 保底计算
|
||||||
|
for i in range(count):
|
||||||
|
card_count += 1
|
||||||
|
# 十连保底
|
||||||
|
if card_count == 10:
|
||||||
|
card = self.get_card(2)
|
||||||
|
card_count = 0
|
||||||
|
else:
|
||||||
|
card = self.get_card(1)
|
||||||
|
if card.star > self.max_star - 2:
|
||||||
|
card_count = 0
|
||||||
|
card_list.append((card, i + 1))
|
||||||
|
return card_list
|
||||||
|
|
||||||
|
def generate_card_img(self, card: BaChar) -> BuildImage:
|
||||||
|
sep_w = 5
|
||||||
|
sep_h = 5
|
||||||
|
star_h = 15
|
||||||
|
img_w = 90
|
||||||
|
img_h = 100
|
||||||
|
font_h = 20
|
||||||
|
bar_h = 20
|
||||||
|
bar_w = 90
|
||||||
|
bg = BuildImage(img_w + sep_w * 2, img_h + font_h + sep_h * 2, color="#EFF2F5")
|
||||||
|
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
|
||||||
|
img = BuildImage(img_w, img_h, background=img_path)
|
||||||
|
bar = BuildImage(bar_w, bar_h, color="#6495ED")
|
||||||
|
bg.paste(img, (sep_w, sep_h), alpha=True)
|
||||||
|
bg.paste(bar, (sep_w, img_h - bar_h + sep_h), alpha=True)
|
||||||
|
if (card.star == 1):
|
||||||
|
star_path = str(self.img_path / "star-1.png")
|
||||||
|
star_w = 15
|
||||||
|
elif (card.star == 2):
|
||||||
|
star_path = str(self.img_path / "star-2.png")
|
||||||
|
star_w = 30
|
||||||
|
else:
|
||||||
|
star_path = str(self.img_path / "star-3.png")
|
||||||
|
star_w = 45
|
||||||
|
star = BuildImage(star_w, star_h, background=star_path)
|
||||||
|
bg.paste(star, (img_w // 2 - 15 * (card.star - 1) // 2, img_h - star_h), alpha=True)
|
||||||
|
text = card.name[:5] + "..." if len(card.name) > 6 else card.name
|
||||||
|
font = load_font(fontsize=14)
|
||||||
|
text_w, text_h = font.getsize(text)
|
||||||
|
draw = ImageDraw.Draw(bg.markImg)
|
||||||
|
draw.text(
|
||||||
|
(sep_w + (img_w - text_w) / 2, sep_h + img_h + (font_h - text_h) / 2),
|
||||||
|
text,
|
||||||
|
font=font,
|
||||||
|
fill="gray",
|
||||||
|
)
|
||||||
|
return bg
|
||||||
|
|
||||||
|
def _init_data(self):
|
||||||
|
self.ALL_CHAR = [
|
||||||
|
BaChar(
|
||||||
|
name=value["名称"],
|
||||||
|
star=int(value["星级"]),
|
||||||
|
limited=True if "(" in key else False,
|
||||||
|
)
|
||||||
|
for key, value in self.load_data().items()
|
||||||
|
]
|
||||||
|
|
||||||
|
def title2star(self, title: int):
|
||||||
|
if title == 'Star-3.png':
|
||||||
|
return 3
|
||||||
|
elif title == 'Star-2.png':
|
||||||
|
return 2
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
async def _update_info(self):
|
||||||
|
info = {}
|
||||||
|
url = "https://wiki.biligame.com/bluearchive/学生筛选"
|
||||||
|
result = await self.get_url(url)
|
||||||
|
if not result:
|
||||||
|
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
dom = etree.HTML(result, etree.HTMLParser())
|
||||||
|
char_list = dom.xpath("//div[@class='filters']/table[2]/tbody/tr")
|
||||||
|
for char in char_list:
|
||||||
|
try:
|
||||||
|
name = char.xpath("./td[2]/a/div/text()")[0]
|
||||||
|
avatar = char.xpath("./td[1]/div/div/a/img/@data-src")[0]
|
||||||
|
star_pic = char.xpath("./td[4]/img/@alt")[0]
|
||||||
|
except IndexError:
|
||||||
|
continue
|
||||||
|
member_dict = {
|
||||||
|
"头像": unquote(str(avatar)),
|
||||||
|
"名称": remove_prohibited_str(name),
|
||||||
|
"星级": self.title2star(star_pic),
|
||||||
|
}
|
||||||
|
info[member_dict["名称"]] = member_dict
|
||||||
|
self.dump_data(info)
|
||||||
|
logger.info(f"{self.game_name_cn} 更新成功")
|
||||||
|
# 下载头像
|
||||||
|
for value in info.values():
|
||||||
|
await self.download_img(value["头像"], value["名称"])
|
||||||
|
# 下载星星
|
||||||
|
await self.download_img(
|
||||||
|
"https://patchwiki.biligame.com/images/bluearchive/thumb/e/e0/82nj2x9sxko473g7782r14fztd4zyky.png/15px-Star-1.png",
|
||||||
|
"star-1",
|
||||||
|
)
|
||||||
|
await self.download_img(
|
||||||
|
"https://patchwiki.biligame.com/images/bluearchive/thumb/0/0b/msaff2g0zk6nlyl1rrn7n1ri4yobcqc.png/30px-Star-2.png",
|
||||||
|
"star-2",
|
||||||
|
)
|
||||||
|
await self.download_img(
|
||||||
|
"https://patchwiki.biligame.com/images/bluearchive/thumb/8/8a/577yv79x1rwxk8efdccpblo0lozl158.png/46px-Star-3.png",
|
||||||
|
"star-3"
|
||||||
|
)
|
||||||
@@ -3,7 +3,6 @@ import random
|
|||||||
import dateparser
|
import dateparser
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from PIL import ImageDraw
|
from PIL import ImageDraw
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
@@ -32,8 +31,9 @@ class Operator(BaseData):
|
|||||||
|
|
||||||
class PrtsHandle(BaseHandle[Operator]):
|
class PrtsHandle(BaseHandle[Operator]):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("prts", "明日方舟", "#eff2f5")
|
super().__init__(game_name="prts", game_name_cn="明日方舟")
|
||||||
self.max_star = 6
|
self.max_star = 6
|
||||||
|
self.game_card_color = "#eff2f5"
|
||||||
self.config = draw_config.prts
|
self.config = draw_config.prts
|
||||||
|
|
||||||
self.ALL_OPERATOR: List[Operator] = []
|
self.ALL_OPERATOR: List[Operator] = []
|
||||||
@@ -41,8 +41,8 @@ class PrtsHandle(BaseHandle[Operator]):
|
|||||||
|
|
||||||
def get_card(self, add: float) -> Operator:
|
def get_card(self, add: float) -> Operator:
|
||||||
star = self.get_star(
|
star = self.get_star(
|
||||||
[6, 5, 4, 3],
|
star_list=[6, 5, 4, 3],
|
||||||
[
|
probability_list=[
|
||||||
self.config.PRTS_SIX_P + add,
|
self.config.PRTS_SIX_P + add,
|
||||||
self.config.PRTS_FIVE_P,
|
self.config.PRTS_FIVE_P,
|
||||||
self.config.PRTS_FOUR_P,
|
self.config.PRTS_FOUR_P,
|
||||||
@@ -53,7 +53,7 @@ class PrtsHandle(BaseHandle[Operator]):
|
|||||||
all_operators = [
|
all_operators = [
|
||||||
x
|
x
|
||||||
for x in self.ALL_OPERATOR
|
for x in self.ALL_OPERATOR
|
||||||
if x.star == star and not any([x.limited, x.event_only, x.recruit_only])
|
if x.star == star and not any([x.limited, x.recruit_only, x.event_only])
|
||||||
]
|
]
|
||||||
acquire_operator = None
|
acquire_operator = None
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ class PrtsHandle(BaseHandle[Operator]):
|
|||||||
acquire_operator = random.choice(all_operators)
|
acquire_operator = random.choice(all_operators)
|
||||||
return acquire_operator
|
return acquire_operator
|
||||||
|
|
||||||
def get_cards(self, count: int) -> List[Tuple[Operator, int]]:
|
def get_cards(self, count: int, **kwargs) -> List[Tuple[Operator, int]]:
|
||||||
card_list = [] # 获取所有角色
|
card_list = [] # 获取所有角色
|
||||||
add = 0.0
|
add = 0.0
|
||||||
count_idx = 0
|
count_idx = 0
|
||||||
@@ -109,7 +109,8 @@ class PrtsHandle(BaseHandle[Operator]):
|
|||||||
|
|
||||||
def _draw(self, count: int, **kwargs) -> Message:
|
def _draw(self, count: int, **kwargs) -> Message:
|
||||||
index2card = self.get_cards(count)
|
index2card = self.get_cards(count)
|
||||||
cards = [card[0] for card in self.get_cards(count)]
|
"""这里cards修复了抽卡图文不符的bug"""
|
||||||
|
cards = [card[0] for card in index2card]
|
||||||
up_list = [x.name for x in self.UP_EVENT.up_char] if self.UP_EVENT else []
|
up_list = [x.name for x in self.UP_EVENT.up_char] if self.UP_EVENT else []
|
||||||
result = self.format_result(index2card, up_list=up_list)
|
result = self.format_result(index2card, up_list=up_list)
|
||||||
pool_info = self.format_pool_info()
|
pool_info = self.format_pool_info()
|
||||||
@@ -162,7 +163,11 @@ class PrtsHandle(BaseHandle[Operator]):
|
|||||||
def load_up_char(self):
|
def load_up_char(self):
|
||||||
try:
|
try:
|
||||||
data = self.load_data(f"draw_card_up/{self.game_name}_up_char.json")
|
data = self.load_data(f"draw_card_up/{self.game_name}_up_char.json")
|
||||||
self.UP_EVENT = UpEvent.parse_obj(data.get("char", {}))
|
"""这里的 waring 有点模糊,更新游戏信息时没有up池的情况下也会报错,所以细分了一下"""
|
||||||
|
if not data:
|
||||||
|
logger.warning(f"当前无UP池或 {self.game_name}_up_char.json 文件不存在")
|
||||||
|
else:
|
||||||
|
self.UP_EVENT = UpEvent.parse_obj(data.get("char", {}))
|
||||||
except ValidationError:
|
except ValidationError:
|
||||||
logger.warning(f"{self.game_name}_up_char 解析出错")
|
logger.warning(f"{self.game_name}_up_char 解析出错")
|
||||||
|
|
||||||
@@ -185,14 +190,15 @@ class PrtsHandle(BaseHandle[Operator]):
|
|||||||
avatar = char.xpath("./td[1]/div/div/div/a/img/@srcset")[0]
|
avatar = char.xpath("./td[1]/div/div/div/a/img/@srcset")[0]
|
||||||
name = char.xpath("./td[2]/a/text()")[0]
|
name = char.xpath("./td[2]/a/text()")[0]
|
||||||
star = char.xpath("./td[5]/text()")[0]
|
star = char.xpath("./td[5]/text()")[0]
|
||||||
sources = str(char.xpath("./td[8]/text()")[0]).split("\n")
|
"""这里sources修好了干员获取标签有问题的bug,如三星只能抽到卡缇就是这个原因"""
|
||||||
|
sources = [_.strip('\n') for _ in char.xpath("./td[8]/text()")]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
continue
|
continue
|
||||||
member_dict = {
|
member_dict = {
|
||||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||||
"名称": remove_prohibited_str(str(name).strip()),
|
"名称": remove_prohibited_str(str(name).strip()),
|
||||||
"星级": int(str(star).strip()),
|
"星级": int(str(star).strip()),
|
||||||
"获取途径": [s for s in sources if s],
|
"获取途径": sources,
|
||||||
}
|
}
|
||||||
info[member_dict["名称"]] = member_dict
|
info[member_dict["名称"]] = member_dict
|
||||||
self.dump_data(info)
|
self.dump_data(info)
|
||||||
@@ -208,6 +214,7 @@ class PrtsHandle(BaseHandle[Operator]):
|
|||||||
await self.update_up_char()
|
await self.update_up_char()
|
||||||
|
|
||||||
async def update_up_char(self):
|
async def update_up_char(self):
|
||||||
|
"""重载卡池"""
|
||||||
announcement_url = "https://ak.hypergryph.com/news.html"
|
announcement_url = "https://ak.hypergryph.com/news.html"
|
||||||
result = await self.get_url(announcement_url)
|
result = await self.get_url(announcement_url)
|
||||||
if not result:
|
if not result:
|
||||||
@@ -221,41 +228,53 @@ class PrtsHandle(BaseHandle[Operator]):
|
|||||||
end_time = None
|
end_time = None
|
||||||
up_chars = []
|
up_chars = []
|
||||||
pool_img = ""
|
pool_img = ""
|
||||||
title = ""
|
for activity_url in activity_urls[:10]: # 减少响应时间, 10个就够了
|
||||||
for activity_url in activity_urls:
|
|
||||||
activity_url = f"https://ak.hypergryph.com{activity_url}"
|
activity_url = f"https://ak.hypergryph.com{activity_url}"
|
||||||
result = await self.get_url(activity_url)
|
result = await self.get_url(activity_url)
|
||||||
if not result:
|
if not result:
|
||||||
logger.warning(f"{self.game_name_cn}获取公告 {activity_url} 出错")
|
logger.warning(f"{self.game_name_cn}获取公告 {activity_url} 出错")
|
||||||
continue
|
continue
|
||||||
soup = BeautifulSoup(result, "lxml")
|
|
||||||
contents = soup.find_all("p")
|
"""因为鹰角的前端太自由了,这里重写了匹配规则以尽可能避免因为前端乱七八糟而导致的重载失败"""
|
||||||
|
dom = etree.HTML(result, etree.HTMLParser())
|
||||||
|
contents = dom.xpath(
|
||||||
|
"//div[@class='article-content']/p/text() | //div[@class='article-content']/p/span/text() | //div[@class='article-content']/div[@class='media-wrap image-wrap']/img/@src"
|
||||||
|
)
|
||||||
|
title = ""
|
||||||
|
time = ""
|
||||||
|
chars: List[str] = []
|
||||||
for index, content in enumerate(contents):
|
for index, content in enumerate(contents):
|
||||||
if re.search("(.*)(寻访|复刻).*?开启", content.text):
|
if re.search("(.*)(寻访|复刻).*?开启", content):
|
||||||
title = content.text
|
title = re.split(r"[【】]", content)
|
||||||
if "【" in title and "】" in title:
|
title = "".join(title[1:-1]) if "-" in title else title[1]
|
||||||
title = re.split(r"[【】]", title)[1]
|
lines = [contents[index-2+_] for _ in range(8)] # 从 -2 开始是因为xpath获取的时间有的会在寻访开启这一句之前
|
||||||
lines = [str(contents[index + i + 1].text) for i in range(5)]
|
lines.append("") # 防止IndexError,加个空字符串
|
||||||
time = ""
|
for idx, line in enumerate(lines):
|
||||||
chars: List[str] = []
|
|
||||||
for line in lines:
|
|
||||||
match = re.search(
|
match = re.search(
|
||||||
r"(\d{1,2}月\d{1,2}日.*?-.*?\d{1,2}月\d{1,2}日.*?$)", line
|
r"(\d{1,2}月\d{1,2}日.*?-.*?\d{1,2}月\d{1,2}日.*?$)", line
|
||||||
)
|
)
|
||||||
if match:
|
if match:
|
||||||
time = match.group(1)
|
time = match.group(1)
|
||||||
if "★" in line:
|
"""因为 <p> 的诡异排版,所以有了下面的一段"""
|
||||||
chars.append(line)
|
if ("★★" in line and "%" in line) or ("★★" in line and "%" in lines[idx + 1]):
|
||||||
|
chars.append(line) if ("★★" in line and "%" in line) else chars.append(line + lines[idx + 1])
|
||||||
if not time:
|
if not time:
|
||||||
continue
|
continue
|
||||||
start, end = time.replace("月", "/").replace("日", "").split("-")[:2]
|
start, end = time.replace("月", "/").replace("日", " ").split("-")[:2] # 日替换为空格是因为有日后面不接空格的情况,导致 split 出问题
|
||||||
start_time = dateparser.parse(start)
|
start_time = dateparser.parse(start)
|
||||||
end_time = dateparser.parse(end)
|
end_time = dateparser.parse(end)
|
||||||
pool_img = content.find_previous("img")["src"]
|
pool_img = contents[index-2]
|
||||||
|
r"""两类格式:用/分割,用\分割;★+(概率)+名字,★+名字+(概率)"""
|
||||||
for char in chars:
|
for char in chars:
|
||||||
star = char.split("(")[0].count("★")
|
star = char.split("(")[0].count("★")
|
||||||
name = re.split(r"[:(]", char)[1]
|
name = re.split(r"[:(]", char)[1] if "★(" not in char else re.split("):", char)[1] # 有的括号在前面有的在后面
|
||||||
names = name.split("/") if "/" in name else [name]
|
if "\\" in name:
|
||||||
|
names = name.split("\\")
|
||||||
|
elif "/" in name:
|
||||||
|
names = name.split("/")
|
||||||
|
else:
|
||||||
|
names = [name] # 既有用/分割的,又有用\分割的
|
||||||
|
|
||||||
names = [name.replace("[限定]", "").strip() for name in names]
|
names = [name.replace("[限定]", "").strip() for name in names]
|
||||||
if "权值" in char:
|
if "权值" in char:
|
||||||
match = re.search(r"(在.*?以.*?(\d+).*?倍权值.*?)", char)
|
match = re.search(r"(在.*?以.*?(\d+).*?倍权值.*?)", char)
|
||||||
@@ -269,7 +288,7 @@ class PrtsHandle(BaseHandle[Operator]):
|
|||||||
up_chars.append(
|
up_chars.append(
|
||||||
UpChar(name=name, star=star, limited=False, zoom=zoom)
|
UpChar(name=name, star=star, limited=False, zoom=zoom)
|
||||||
)
|
)
|
||||||
break
|
break # 这里break会导致个问题:如果一个公告里有两个池子,会漏掉下面的池子,比如 5.19 的定向寻访。但目前我也没啥好想法解决
|
||||||
if title and start_time and end_time:
|
if title and start_time and end_time:
|
||||||
if start_time <= datetime.now() <= end_time:
|
if start_time <= datetime.now() <= end_time:
|
||||||
self.UP_EVENT = UpEvent(
|
self.UP_EVENT = UpEvent(
|
||||||
|
|||||||
+24
-37
@@ -1,58 +1,34 @@
|
|||||||
from httpx import AsyncClient
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
from nonebot.adapters.onebot.v11 import Bot
|
from nonebot.adapters.onebot.v11 import Bot
|
||||||
from configs.config import NICKNAME
|
from configs.config import NICKNAME
|
||||||
|
from utils.http_utils import AsyncHttpx
|
||||||
|
|
||||||
|
|
||||||
# 获取所有 Epic Game Store 促销游戏
|
# 获取所有 Epic Game Store 促销游戏
|
||||||
# 方法参考:RSSHub /epicgames 路由
|
# 方法参考:RSSHub /epicgames 路由
|
||||||
# https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js
|
# https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js
|
||||||
async def get_epic_game():
|
async def get_epic_game():
|
||||||
# 现在没用 graphql 辣
|
|
||||||
"""prv_graphql Code
|
|
||||||
epic_url = "https://www.epicgames.com/store/backend/graphql-proxy"
|
|
||||||
headers = {
|
|
||||||
"Referer": "https://www.epicgames.com/store/zh-CN/",
|
|
||||||
"Content-Type": "application/json; charset=utf-8",
|
|
||||||
}
|
|
||||||
data = {
|
|
||||||
"query": "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, $keywords: String, $locale: String, $namespace: String, $sortBy: String, $sortDir: String, $start: Int, $tag: String, $withPrice: Boolean = false, $withPromotions: Boolean = false) {\n Catalog {\n searchStore(allowCountries: $allowCountries, category: $category, count: $count, country: $country, keywords: $keywords, locale: $locale, namespace: $namespace, sortBy: $sortBy, sortDir: $sortDir, start: $start, tag: $tag) {\n elements {\n title\n id\n namespace\n description\n effectiveDate\n keyImages {\n type\n url\n }\n seller {\n id\n name\n }\n productSlug\n urlSlug\n url\n items {\n id\n namespace\n }\n customAttributes {\n key\n value\n }\n categories {\n path\n }\n price(country: $country) @include(if: $withPrice) {\n totalPrice {\n discountPrice\n originalPrice\n voucherDiscount\n discount\n currencyCode\n currencyInfo {\n decimals\n }\n fmtPrice(locale: $locale) {\n originalPrice\n discountPrice\n intermediatePrice\n }\n }\n lineOffers {\n appliedRules {\n id\n endDate\n discountSetting {\n discountType\n }\n }\n }\n }\n promotions(category: $category) @include(if: $withPromotions) {\n promotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n upcomingPromotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n }\n }\n paging {\n count\n total\n }\n }\n }\n}\n",
|
|
||||||
"variables": {
|
|
||||||
"allowCountries": "CN",
|
|
||||||
"category": "freegames",
|
|
||||||
"count": 1000,
|
|
||||||
"country": "CN",
|
|
||||||
"locale": "zh-CN",
|
|
||||||
"sortBy": "effectiveDate",
|
|
||||||
"sortDir": "asc",
|
|
||||||
"withPrice": True,
|
|
||||||
"withPromotions": True,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
epic_url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN"
|
epic_url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN"
|
||||||
headers = {
|
headers = {
|
||||||
"Referer": "https://www.epicgames.com/store/zh-CN/",
|
"Referer": "https://www.epicgames.com/store/zh-CN/",
|
||||||
"Content-Type": "application/json; charset=utf-8",
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36",
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36",
|
||||||
}
|
}
|
||||||
async with AsyncClient(headers=headers) as client:
|
try:
|
||||||
try:
|
res = await AsyncHttpx.get(epic_url, headers=headers, timeout=10)
|
||||||
res = await client.get(epic_url, timeout=10.0)
|
res_json = res.json()
|
||||||
res_json = res.json()
|
games = res_json["data"]["Catalog"]["searchStore"]["elements"]
|
||||||
games = res_json["data"]["Catalog"]["searchStore"]["elements"]
|
return games
|
||||||
return games
|
except Exception as e:
|
||||||
except Exception as e:
|
logger.error(f"Epic 访问接口错误 {type(e)}:{e}")
|
||||||
logger.error(str(e))
|
return None
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# 获取 Epic Game Store 免费游戏信息
|
# 获取 Epic Game Store 免费游戏信息
|
||||||
# 处理免费游戏的信息方法借鉴 pip 包 epicstore_api 示例
|
# 处理免费游戏的信息方法借鉴 pip 包 epicstore_api 示例
|
||||||
# https://github.com/SD4RK/epicstore_api/blob/master/examples/free_games_example.py
|
# https://github.com/SD4RK/epicstore_api/blob/master/examples/free_games_example.py
|
||||||
async def get_epic_free(bot: Bot, Type_Event: str):
|
async def get_epic_free(bot: Bot, type_event: str):
|
||||||
games = await get_epic_game()
|
games = await get_epic_game()
|
||||||
if not games:
|
if not games:
|
||||||
return "Epic 可能又抽风啦,请稍后再试(", 404
|
return "Epic 可能又抽风啦,请稍后再试(", 404
|
||||||
@@ -81,7 +57,7 @@ async def get_epic_free(bot: Bot, Type_Event: str):
|
|||||||
end_date = datetime.fromisoformat(end_date_iso).strftime(
|
end_date = datetime.fromisoformat(end_date_iso).strftime(
|
||||||
"%b.%d %H:%M"
|
"%b.%d %H:%M"
|
||||||
)
|
)
|
||||||
if Type_Event == "Group":
|
if type_event == "Group":
|
||||||
_message = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format(
|
_message = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format(
|
||||||
game_corp, game_name, game_price, start_date, end_date
|
game_corp, game_name, game_price, start_date, end_date
|
||||||
)
|
)
|
||||||
@@ -101,8 +77,19 @@ async def get_epic_free(bot: Bot, Type_Event: str):
|
|||||||
msg_list.append(msg)
|
msg_list.append(msg)
|
||||||
else:
|
else:
|
||||||
for image in game["keyImages"]:
|
for image in game["keyImages"]:
|
||||||
if image["type"] == "Thumbnail":
|
if (
|
||||||
|
image.get("url")
|
||||||
|
and not game_thumbnail
|
||||||
|
and image["type"]
|
||||||
|
in [
|
||||||
|
"Thumbnail",
|
||||||
|
"VaultOpened",
|
||||||
|
"DieselStoreFrontWide",
|
||||||
|
"OfferImageWide",
|
||||||
|
]
|
||||||
|
):
|
||||||
game_thumbnail = image["url"]
|
game_thumbnail = image["url"]
|
||||||
|
break
|
||||||
for pair in game["customAttributes"]:
|
for pair in game["customAttributes"]:
|
||||||
if pair["key"] == "developerName":
|
if pair["key"] == "developerName":
|
||||||
game_dev = pair["value"]
|
game_dev = pair["value"]
|
||||||
@@ -127,7 +114,7 @@ async def get_epic_free(bot: Bot, Type_Event: str):
|
|||||||
game_url = "https://www.epicgames.com/store/zh-CN/p/{}".format(
|
game_url = "https://www.epicgames.com/store/zh-CN/p/{}".format(
|
||||||
game_url_part
|
game_url_part
|
||||||
)
|
)
|
||||||
if Type_Event == "Group":
|
if type_event == "Group":
|
||||||
_message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format(
|
_message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format(
|
||||||
game_thumbnail,
|
game_thumbnail,
|
||||||
game_name,
|
game_name,
|
||||||
|
|||||||
+11
-9
@@ -9,6 +9,7 @@ from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
|||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
|
from configs.config import NICKNAME
|
||||||
|
|
||||||
|
|
||||||
__zx_plugin_name__ = "复读"
|
__zx_plugin_name__ = "复读"
|
||||||
@@ -74,15 +75,15 @@ class Fudu:
|
|||||||
_fudu_list = Fudu()
|
_fudu_list = Fudu()
|
||||||
|
|
||||||
|
|
||||||
fudu = on_message(permission=GROUP, priority=9)
|
fudu = on_message(permission=GROUP, priority=999)
|
||||||
|
|
||||||
|
|
||||||
@fudu.handle()
|
@fudu.handle()
|
||||||
async def _(event: GroupMessageEvent):
|
async def _(event: GroupMessageEvent):
|
||||||
if event.is_tome():
|
if event.is_tome():
|
||||||
return
|
return
|
||||||
if get_message_text(event.json()):
|
if msg := get_message_text(event.json()):
|
||||||
if get_message_text(event.json()).find("@可爱的小真寻") != -1:
|
if msg.startswith(f"@可爱的{NICKNAME}"):
|
||||||
await fudu.finish("复制粘贴的虚空艾特?", at_sender=True)
|
await fudu.finish("复制粘贴的虚空艾特?", at_sender=True)
|
||||||
img = get_message_img(event.json())
|
img = get_message_img(event.json())
|
||||||
msg = get_message_text(event.json())
|
msg = get_message_text(event.json())
|
||||||
@@ -105,20 +106,21 @@ async def _(event: GroupMessageEvent):
|
|||||||
"fudu", "FUDU_PROBABILITY"
|
"fudu", "FUDU_PROBABILITY"
|
||||||
) and not _fudu_list.is_repeater(event.group_id):
|
) and not _fudu_list.is_repeater(event.group_id):
|
||||||
if random.random() < 0.2:
|
if random.random() < 0.2:
|
||||||
await fudu.finish("[[_task|fudu]]打断施法!")
|
if msg.endswith("打断施法!"):
|
||||||
|
await fudu.finish("[[_task|fudu]]打断" + msg)
|
||||||
|
else:
|
||||||
|
await fudu.finish("[[_task|fudu]]打断施法!")
|
||||||
_fudu_list.set_repeater(event.group_id)
|
_fudu_list.set_repeater(event.group_id)
|
||||||
if img and msg:
|
if img and msg:
|
||||||
rst = msg + image(f"compare_{event.group_id}_img.jpg", "temp")
|
rst = msg + image(TEMP_PATH / f"compare_{event.group_id}_img.jpg")
|
||||||
elif img:
|
elif img:
|
||||||
rst = image(f"compare_{event.group_id}_img.jpg", "temp")
|
rst = image(TEMP_PATH / f"compare_{event.group_id}_img.jpg")
|
||||||
elif msg:
|
elif msg:
|
||||||
rst = msg
|
rst = msg
|
||||||
else:
|
else:
|
||||||
rst = ""
|
rst = ""
|
||||||
if rst:
|
if rst:
|
||||||
if rst.endswith("打断施法!"):
|
await fudu.finish("[[_task|fudu]]" + rst)
|
||||||
rst = "打断" + rst
|
|
||||||
await fudu.send("[[_task|fudu]]" + rst)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_fudu_img_hash(url, group_id):
|
async def get_fudu_img_hash(url, group_id):
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ Config.add_plugin_config(
|
|||||||
default_value=True,
|
default_value=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
almanac = on_command("原神黄历", priority=5, block=True)
|
almanac = on_command("原神黄历", priority=15, block=True)
|
||||||
|
|
||||||
|
|
||||||
ALC_PATH = IMAGE_PATH / "genshin" / "alc"
|
ALC_PATH = IMAGE_PATH / "genshin" / "alc"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
from pathlib import Path
|
||||||
from typing import Tuple, Optional, List
|
from typing import Tuple, Optional, List
|
||||||
from configs.path_config import IMAGE_PATH, TEXT_PATH
|
from configs.path_config import IMAGE_PATH, TEXT_PATH
|
||||||
from PIL.Image import UnidentifiedImageError
|
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from utils.image_utils import BuildImage
|
from utils.image_utils import BuildImage
|
||||||
@@ -137,7 +137,7 @@ async def download_resource_data(semaphore: Semaphore):
|
|||||||
asyncio.ensure_future(
|
asyncio.ensure_future(
|
||||||
download_image(
|
download_image(
|
||||||
img_url,
|
img_url,
|
||||||
f"{icon_path}/{id_}.png",
|
icon_path / f"{id_}.png",
|
||||||
semaphore,
|
semaphore,
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
@@ -179,7 +179,7 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
|
|||||||
map_url = _map_data["url"]
|
map_url = _map_data["url"]
|
||||||
await download_image(
|
await download_image(
|
||||||
map_url,
|
map_url,
|
||||||
f"{map_path}/{idx}.png",
|
map_path / f"{idx}.png",
|
||||||
semaphore,
|
semaphore,
|
||||||
force_flag=flag,
|
force_flag=flag,
|
||||||
)
|
)
|
||||||
@@ -228,15 +228,14 @@ async def download_resource_type():
|
|||||||
except (TimeoutError, ConnectTimeout):
|
except (TimeoutError, ConnectTimeout):
|
||||||
logger.warning("下载原神资源类型数据超时....")
|
logger.warning("下载原神资源类型数据超时....")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"载原神资源类型数据超时 {type(e)}:{e}")
|
logger.error(f"载原神资源类型数据错误 {type(e)}:{e}")
|
||||||
|
|
||||||
|
|
||||||
# 初始化资源图标
|
# 初始化资源图标
|
||||||
def gen_icon(icon: str):
|
def gen_icon(icon: Path):
|
||||||
A = BuildImage(0, 0, background=f"{icon_path}/box.png")
|
A = BuildImage(0, 0, background=f"{icon_path}/box.png")
|
||||||
B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png")
|
B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png")
|
||||||
icon_ = icon_path / f"{icon}"
|
icon_img = BuildImage(115, 115, background=icon)
|
||||||
icon_img = BuildImage(115, 115, background=icon_)
|
|
||||||
icon_img.circle()
|
icon_img.circle()
|
||||||
B.paste(icon_img, (17, 10), True)
|
B.paste(icon_img, (17, 10), True)
|
||||||
B.paste(A, alpha=True)
|
B.paste(A, alpha=True)
|
||||||
@@ -247,22 +246,22 @@ def gen_icon(icon: str):
|
|||||||
# 下载图片
|
# 下载图片
|
||||||
async def download_image(
|
async def download_image(
|
||||||
img_url: str,
|
img_url: str,
|
||||||
path: str,
|
path: Path,
|
||||||
semaphore: Semaphore,
|
semaphore: Semaphore,
|
||||||
gen_flag: bool = False,
|
gen_flag: bool = False,
|
||||||
force_flag: bool = False,
|
force_flag: bool = False,
|
||||||
):
|
):
|
||||||
async with semaphore:
|
async with semaphore:
|
||||||
try:
|
try:
|
||||||
if not os.path.exists(path) or not is_valid or force_flag:
|
if not path.exists() or not is_valid(path) or force_flag:
|
||||||
if await AsyncHttpx.download_file(img_url, path, timeout=10):
|
if await AsyncHttpx.download_file(img_url, path, timeout=10):
|
||||||
logger.info(f"下载原神资源图标:{img_url}")
|
logger.info(f"下载原神资源图标:{img_url}")
|
||||||
if gen_flag:
|
if gen_flag:
|
||||||
gen_icon(path)
|
gen_icon(path)
|
||||||
else:
|
else:
|
||||||
logger.info(f"下载原神资源图标:{img_url} 失败,等待下次更新...")
|
logger.info(f"下载原神资源图标:{img_url} 失败,等待下次更新...")
|
||||||
except UnidentifiedImageError:
|
except Exception as e:
|
||||||
logger.warning(f"原神图片打开错误..已删除,等待下次更新... file: {path}")
|
logger.warning(f"原神图片错误..已删除,等待下次更新... file: {path} {type(e)}:{e}")
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ async def get_character(
|
|||||||
) -> Optional[dict]:
|
) -> Optional[dict]:
|
||||||
try:
|
try:
|
||||||
req = await AsyncHttpx.post(
|
req = await AsyncHttpx.post(
|
||||||
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/character",
|
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character",
|
||||||
headers={
|
headers={
|
||||||
"Accept": "application/json, text/plain, */*",
|
"Accept": "application/json, text/plain, */*",
|
||||||
"DS": get_ds(
|
"DS": get_ds(
|
||||||
@@ -232,7 +232,7 @@ async def get_mys_data(uid: str, mys_id: Optional[str]) -> Optional[List[Dict]]:
|
|||||||
if mys_id:
|
if mys_id:
|
||||||
try:
|
try:
|
||||||
req = await AsyncHttpx.get(
|
req = await AsyncHttpx.get(
|
||||||
url=f"https://api-takumi.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
|
url=f"https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
|
||||||
headers={
|
headers={
|
||||||
"DS": get_ds(f"uid={mys_id}"),
|
"DS": get_ds(f"uid={mys_id}"),
|
||||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||||
|
|||||||
@@ -300,6 +300,8 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
|||||||
region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2")
|
region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2")
|
||||||
height = 0
|
height = 0
|
||||||
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]:
|
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]:
|
||||||
|
if not world_data_dict.get(country):
|
||||||
|
continue
|
||||||
x = BuildImage(790, 250, color="#3A4467")
|
x = BuildImage(790, 250, color="#3A4467")
|
||||||
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
|
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
|
||||||
tmp_bk = BuildImage(770, 230, color="#606779")
|
tmp_bk = BuildImage(770, 230, color="#606779")
|
||||||
@@ -328,18 +330,19 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
|||||||
f"{world_data_dict['层岩巨渊']['exploration_percentage'] / 10}%",
|
f"{world_data_dict['层岩巨渊']['exploration_percentage'] / 10}%",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
content_bk.text((300, 85), "地下矿区探索", fill=(239, 211, 114))
|
if world_data_dict.get('层岩巨渊·地下矿区'):
|
||||||
content_bk.text(
|
content_bk.text((300, 85), "地下矿区探索", fill=(239, 211, 114))
|
||||||
(570, 85),
|
content_bk.text(
|
||||||
f"{world_data_dict['层岩巨渊·地下矿区']['exploration_percentage'] / 10}%",
|
(570, 85),
|
||||||
fill=(255, 255, 255),
|
f"{world_data_dict['层岩巨渊·地下矿区']['exploration_percentage'] / 10}%",
|
||||||
)
|
fill=(255, 255, 255),
|
||||||
content_bk.text((300, 150), "流明石触媒", fill=(239, 211, 114))
|
)
|
||||||
content_bk.text(
|
content_bk.text((300, 150), "流明石触媒", fill=(239, 211, 114))
|
||||||
(570, 150),
|
content_bk.text(
|
||||||
f"LV.{world_data_dict['层岩巨渊·地下矿区']['offerings'][0]['level']}",
|
(570, 150),
|
||||||
fill=(255, 255, 255),
|
f"LV.{world_data_dict['层岩巨渊·地下矿区']['offerings'][0]['level']}",
|
||||||
)
|
fill=(255, 255, 255),
|
||||||
|
)
|
||||||
elif country in ["龙脊雪山"]:
|
elif country in ["龙脊雪山"]:
|
||||||
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
||||||
content_bk.text(
|
content_bk.text(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from nonebot.adapters.onebot.v11 import ActionFailed
|
||||||
|
|
||||||
from utils.utils import get_bot, scheduler
|
from utils.utils import get_bot, scheduler
|
||||||
from utils.message_builder import at
|
from utils.message_builder import at
|
||||||
from models.group_member_info import GroupInfoUser
|
from models.group_member_info import GroupInfoUser
|
||||||
@@ -178,10 +180,13 @@ async def _remind(user_id: int, uid: str):
|
|||||||
group_list = await GroupInfoUser.get_user_all_group(user_id)
|
group_list = await GroupInfoUser.get_user_all_group(user_id)
|
||||||
if group_list:
|
if group_list:
|
||||||
group_id = group_list[0]
|
group_id = group_list[0]
|
||||||
await bot.send_group_msg(
|
try:
|
||||||
group_id=group_id,
|
await bot.send_group_msg(
|
||||||
message=at(user_id) + msg
|
group_id=group_id,
|
||||||
)
|
message=at(user_id) + msg
|
||||||
|
)
|
||||||
|
except ActionFailed as e:
|
||||||
|
logger.error(f"树脂提醒推送发生错误 {type(e)}:{e}")
|
||||||
if not next_time:
|
if not next_time:
|
||||||
if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"):
|
if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"):
|
||||||
await Genshin.set_resin_remind(int(uid), False)
|
await Genshin.set_resin_remind(int(uid), False)
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ async def _generate_open_redbag_pic(user_id: int, send_user_nickname: str, amoun
|
|||||||
head = BuildImage(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_12.png')
|
head = BuildImage(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_12.png')
|
||||||
size = BuildImage(0, 0, font_size=50).getsize(send_user_nickname)
|
size = BuildImage(0, 0, font_size=50).getsize(send_user_nickname)
|
||||||
# QQ头像
|
# QQ头像
|
||||||
ava_bk = BuildImage(100 + size[0], 66, color='white', font_size=50)
|
ava_bk = BuildImage(100 + size[0], 66, is_alpha=True, font_size=50)
|
||||||
ava = BuildImage(66, 66, background=BytesIO(await get_user_avatar(user_id)))
|
ava = BuildImage(66, 66, is_alpha=True, background=BytesIO(await get_user_avatar(user_id)))
|
||||||
ava_bk.paste(ava)
|
ava_bk.paste(ava)
|
||||||
ava_bk.text((100, 7), send_user_nickname)
|
ava_bk.text((100, 7), send_user_nickname)
|
||||||
# ava_bk.show()
|
# ava_bk.show()
|
||||||
@@ -73,7 +73,7 @@ async def _generate_open_redbag_pic(user_id: int, send_user_nickname: str, amoun
|
|||||||
head.paste(ava_bk, (int((1000 - ava_bk_w) / 2), 300))
|
head.paste(ava_bk, (int((1000 - ava_bk_w) / 2), 300))
|
||||||
# 金额
|
# 金额
|
||||||
size = BuildImage(0, 0, font_size=150).getsize(amount)
|
size = BuildImage(0, 0, font_size=150).getsize(amount)
|
||||||
price = BuildImage(size[0], size[1], font_size=150)
|
price = BuildImage(size[0], size[1], is_alpha=True, font_size=150)
|
||||||
price.text((0, 0), amount, fill=(209, 171, 108))
|
price.text((0, 0), amount, fill=(209, 171, 108))
|
||||||
# 金币中文
|
# 金币中文
|
||||||
head.paste(price, (int((1000 - size[0]) / 2) - 50, 460))
|
head.paste(price, (int((1000 - size[0]) / 2) - 50, 460))
|
||||||
|
|||||||
+14
-16
@@ -1,8 +1,7 @@
|
|||||||
from nonebot import on_message, on_command
|
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
|
||||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||||
from utils.utils import is_number, get_message_img
|
from utils.utils import is_number, get_message_img, get_message_text
|
||||||
from nonebot.typing import T_State
|
|
||||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||||
from configs.path_config import DATA_PATH, TEMP_PATH
|
from configs.path_config import DATA_PATH, TEMP_PATH
|
||||||
from utils.image_utils import get_img_hash
|
from utils.image_utils import get_img_hash
|
||||||
@@ -10,7 +9,7 @@ from services.log import logger
|
|||||||
from configs.config import NICKNAME, Config
|
from configs.config import NICKNAME, Config
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
from nonebot.params import CommandArg, Command
|
from nonebot.params import CommandArg, Command
|
||||||
from typing import Tuple
|
from typing import Tuple, Dict, Any
|
||||||
import time
|
import time
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -57,7 +56,7 @@ mute_setting = on_command(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_data():
|
def get_data() -> Dict[Any, Any]:
|
||||||
try:
|
try:
|
||||||
with open(DATA_PATH / "group_mute_data.json", "r", encoding="utf8") as f:
|
with open(DATA_PATH / "group_mute_data.json", "r", encoding="utf8") as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
@@ -72,7 +71,7 @@ def save_data():
|
|||||||
json.dump(mute_data, f, indent=4)
|
json.dump(mute_data, f, indent=4)
|
||||||
|
|
||||||
|
|
||||||
async def download_img_and_hash(url, group_id):
|
async def download_img_and_hash(url, group_id) -> str:
|
||||||
if await AsyncHttpx.download_file(
|
if await AsyncHttpx.download_file(
|
||||||
url, TEMP_PATH / f"mute_{group_id}_img.jpg"
|
url, TEMP_PATH / f"mute_{group_id}_img.jpg"
|
||||||
):
|
):
|
||||||
@@ -85,9 +84,9 @@ mute_data = get_data()
|
|||||||
|
|
||||||
|
|
||||||
@mute.handle()
|
@mute.handle()
|
||||||
async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
async def _(bot: Bot, event: GroupMessageEvent):
|
||||||
group_id = str(event.group_id)
|
group_id = str(event.group_id)
|
||||||
msg = arg.extract_plain_text().strip()
|
msg = get_message_text(event.json())
|
||||||
img_list = get_message_img(event.json())
|
img_list = get_message_img(event.json())
|
||||||
img_hash = ""
|
img_hash = ""
|
||||||
for img in img_list:
|
for img in img_list:
|
||||||
@@ -102,8 +101,6 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
|
|||||||
if not mute_dict.get(event.user_id):
|
if not mute_dict.get(event.user_id):
|
||||||
mute_dict[event.user_id] = {"time": time.time(), "count": 1, "msg": msg}
|
mute_dict[event.user_id] = {"time": time.time(), "count": 1, "msg": msg}
|
||||||
else:
|
else:
|
||||||
if cmd or not msg:
|
|
||||||
return
|
|
||||||
if msg and msg.find(mute_dict[event.user_id]["msg"]) != -1:
|
if msg and msg.find(mute_dict[event.user_id]["msg"]) != -1:
|
||||||
mute_dict[event.user_id]["count"] += 1
|
mute_dict[event.user_id]["count"] += 1
|
||||||
else:
|
else:
|
||||||
@@ -123,7 +120,7 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
|
|||||||
await bot.set_group_ban(
|
await bot.set_group_ban(
|
||||||
group_id=event.group_id,
|
group_id=event.group_id,
|
||||||
user_id=event.user_id,
|
user_id=event.user_id,
|
||||||
duration=mute_data[group_id]["duration"],
|
duration=mute_data[group_id]["duration"] * 60,
|
||||||
)
|
)
|
||||||
await mute.send(f"检测到恶意刷屏,{NICKNAME}要把你关进小黑屋!", at_sender=True)
|
await mute.send(f"检测到恶意刷屏,{NICKNAME}要把你关进小黑屋!", at_sender=True)
|
||||||
mute_dict[event.user_id]["count"] = 0
|
mute_dict[event.user_id]["count"] = 0
|
||||||
@@ -137,27 +134,28 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
|
|||||||
|
|
||||||
@mute_setting.handle()
|
@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)
|
group_id = str(event.group_id)
|
||||||
if not mute_data.get(group_id):
|
if not mute_data.get(group_id):
|
||||||
mute_data[group_id] = {"count": 10, "time": 7, "duration": 0}
|
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()
|
msg = arg.extract_plain_text().strip()
|
||||||
if cmd[0] == "刷屏检测设置":
|
if cmd[0] == "刷屏检测设置":
|
||||||
await mute_setting.finish(
|
await mute_setting.finish(
|
||||||
f'最大次数:{mute_data[group_id]["count"]} 次\n'
|
f'最大次数:{mute_data[group_id]["count"]} 次\n'
|
||||||
f'规定时间:{mute_data[group_id]["time"]} 秒\n'
|
f'规定时间:{mute_data[group_id]["time"]} 秒\n'
|
||||||
f'禁言时长:{mute_data[group_id]["duration"] / 60} 分钟\n'
|
f'禁言时长:{mute_data[group_id]["duration"]:.2f} 分钟\n'
|
||||||
f"【在规定时间内发送相同消息超过最大次数则禁言\n当禁言时长为0时关闭此功能】"
|
f"【在规定时间内发送相同消息超过最大次数则禁言\n当禁言时长为0时关闭此功能】"
|
||||||
)
|
)
|
||||||
if not is_number(msg):
|
if not is_number(msg):
|
||||||
await mute.finish("设置的参数必须是数字啊!", at_sender=True)
|
await mute.finish("设置的参数必须是数字啊!", at_sender=True)
|
||||||
if cmd[0] == "设置检测时间":
|
if cmd[0] == "设置刷屏检测时间":
|
||||||
mute_data[group_id]["time"] = int(msg)
|
mute_data[group_id]["time"] = int(msg)
|
||||||
msg += "秒"
|
msg += "秒"
|
||||||
if cmd[0] == "设置检测次数":
|
if cmd[0] == "设置刷屏检测次数":
|
||||||
mute_data[group_id]["count"] = int(msg)
|
mute_data[group_id]["count"] = int(msg)
|
||||||
msg += " 次"
|
msg += " 次"
|
||||||
if cmd[0] == "设置禁言时长":
|
if cmd[0] == "设置刷屏禁言时长":
|
||||||
mute_data[group_id]["duration"] = int(msg) * 60
|
mute_data[group_id]["duration"] = int(msg)
|
||||||
msg += " 分钟"
|
msg += " 分钟"
|
||||||
await mute_setting.send(f'刷屏检测:{cmd[0]}为 {msg}')
|
await mute_setting.send(f'刷屏检测:{cmd[0]}为 {msg}')
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import Type
|
from typing import Type, Tuple, Any
|
||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from nonebot.matcher import Matcher
|
from nonebot.matcher import Matcher
|
||||||
from utils.utils import scheduler, is_number
|
from utils.utils import scheduler, is_number
|
||||||
@@ -9,7 +9,7 @@ from nonebot.permission import SUPERUSER
|
|||||||
import random
|
import random
|
||||||
from nonebot.plugin import MatcherGroup
|
from nonebot.plugin import MatcherGroup
|
||||||
from configs.path_config import IMAGE_PATH
|
from configs.path_config import IMAGE_PATH
|
||||||
from nonebot.params import CommandArg
|
from nonebot.params import CommandArg, RegexGroup
|
||||||
from .open_cases_c import (
|
from .open_cases_c import (
|
||||||
open_case,
|
open_case,
|
||||||
total_open_statistics,
|
total_open_statistics,
|
||||||
@@ -145,12 +145,12 @@ async def _(event: GroupMessageEvent):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
open_shilian: Type[Matcher] = cases_matcher_group.on_regex("(.*)连开箱(.*?)")
|
open_shilian: Type[Matcher] = cases_matcher_group.on_regex("(.*)连开箱(.*)?")
|
||||||
|
|
||||||
|
|
||||||
@open_shilian.handle()
|
@open_shilian.handle()
|
||||||
async def _(event: GroupMessageEvent, state: T_State):
|
async def _(event: GroupMessageEvent, state: T_State, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||||
num = state["_matched_groups"][0].strip()
|
num, case_name = reg_group
|
||||||
if is_number(num) or num_dict.get(num):
|
if is_number(num) or num_dict.get(num):
|
||||||
try:
|
try:
|
||||||
num = num_dict[num]
|
num = num_dict[num]
|
||||||
@@ -162,7 +162,6 @@ async def _(event: GroupMessageEvent, state: T_State):
|
|||||||
await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True)
|
await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True)
|
||||||
else:
|
else:
|
||||||
await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True)
|
await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True)
|
||||||
case_name = state["_matched_groups"][1].strip()
|
|
||||||
case_name = case_name.replace("武器箱", "").strip()
|
case_name = case_name.replace("武器箱", "").strip()
|
||||||
if not case_name:
|
if not case_name:
|
||||||
case_name = random.choice(cases_name)
|
case_name = random.choice(cases_name)
|
||||||
@@ -212,16 +211,16 @@ update_price = on_command("更新开箱价格", priority=1, permission=SUPERUSER
|
|||||||
|
|
||||||
|
|
||||||
@update_price.handle()
|
@update_price.handle()
|
||||||
async def _( event: MessageEvent):
|
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||||
await update_price.send(await util_get_buff_price(str(event.get_message())))
|
await update_price.send(await util_get_buff_price(arg.extract_plain_text().strip() or "狂牙大行动"))
|
||||||
|
|
||||||
|
|
||||||
update_img = on_command("更新开箱图片", priority=1, permission=SUPERUSER, block=True)
|
update_img = on_command("更新开箱图片", priority=1, permission=SUPERUSER, block=True)
|
||||||
|
|
||||||
|
|
||||||
@update_img.handle()
|
@update_img.handle()
|
||||||
async def _(event: MessageEvent):
|
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||||
await update_img.send(await util_get_buff_img(str(event.get_message())))
|
await update_img.send(await util_get_buff_img(arg.extract_plain_text().strip() or "狂牙大行动"))
|
||||||
|
|
||||||
|
|
||||||
# 重置开箱
|
# 重置开箱
|
||||||
|
|||||||
+166
-171
@@ -1,171 +1,166 @@
|
|||||||
from nonebot import on_message
|
# from nonebot import on_message
|
||||||
from services.log import logger
|
# from services.log import logger
|
||||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
# from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||||
from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
|
# from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
|
||||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
# from nonebot.adapters.onebot.v11.permission import GROUP
|
||||||
from bilibili_api import video
|
# from utils.message_builder import image
|
||||||
from utils.message_builder import image
|
# from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
# from utils.image_utils import BuildImage
|
||||||
from utils.image_utils import BuildImage
|
# from utils.browser import get_browser
|
||||||
from utils.browser import get_browser
|
# from configs.path_config import IMAGE_PATH
|
||||||
from configs.path_config import IMAGE_PATH
|
# from utils.http_utils import AsyncHttpx
|
||||||
from utils.http_utils import AsyncHttpx
|
# from configs.config import Config
|
||||||
from configs.config import Config
|
# from utils.user_agent import get_user_agent
|
||||||
from utils.user_agent import get_user_agent
|
# import aiohttp
|
||||||
import aiohttp
|
# import asyncio
|
||||||
import asyncio
|
# import time
|
||||||
import time
|
# import ujson as json
|
||||||
from bilibili_api import settings
|
#
|
||||||
import ujson as json
|
#
|
||||||
|
# __zx_plugin_name__ = "B站转发解析"
|
||||||
|
# __plugin_usage__ = """
|
||||||
__zx_plugin_name__ = "B站转发解析"
|
# usage:
|
||||||
__plugin_usage__ = """
|
# B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
|
||||||
usage:
|
# """.strip()
|
||||||
B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
|
# __plugin_des__ = "B站转发解析"
|
||||||
""".strip()
|
# __plugin_type__ = ("其他",)
|
||||||
__plugin_des__ = "B站转发解析"
|
# __plugin_version__ = 0.1
|
||||||
__plugin_type__ = ("其他",)
|
# __plugin_author__ = "HibiKier"
|
||||||
__plugin_version__ = 0.1
|
# __plugin_task__ = {"bilibili_parse": "b站转发解析"}
|
||||||
__plugin_author__ = "HibiKier"
|
# Config.add_plugin_config(
|
||||||
__plugin_task__ = {"bilibili_parse": "b站转发解析"}
|
# "_task",
|
||||||
Config.add_plugin_config(
|
# "DEFAULT_BILIBILI_PARSE",
|
||||||
"_task",
|
# True,
|
||||||
"DEFAULT_BILIBILI_PARSE",
|
# help_="被动 B站转发解析 进群默认开关状态",
|
||||||
True,
|
# default_value=True,
|
||||||
help_="被动 B站转发解析 进群默认开关状态",
|
# )
|
||||||
default_value=True,
|
#
|
||||||
)
|
#
|
||||||
|
# parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
|
||||||
|
#
|
||||||
if get_local_proxy():
|
# _tmp = {}
|
||||||
settings.proxy = get_local_proxy()
|
#
|
||||||
|
#
|
||||||
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
|
# @parse_bilibili_json.handle()
|
||||||
|
# async def _(event: GroupMessageEvent):
|
||||||
_tmp = {}
|
# vd_info = None
|
||||||
|
# url = None
|
||||||
|
# if get_message_json(event.json()):
|
||||||
@parse_bilibili_json.handle()
|
# try:
|
||||||
async def _(event: GroupMessageEvent):
|
# data = json.loads(get_message_json(event.json())[0]["data"])
|
||||||
vd_info = None
|
# except (IndexError, KeyError):
|
||||||
url = None
|
# data = None
|
||||||
if get_message_json(event.json()):
|
# if data:
|
||||||
try:
|
# # 转发视频
|
||||||
data = json.loads(get_message_json(event.json())[0]["data"])
|
# if data.get("desc") == "哔哩哔哩":
|
||||||
except (IndexError, KeyError):
|
# async with aiohttp.ClientSession(
|
||||||
data = None
|
# headers=get_user_agent()
|
||||||
if data:
|
# ) as session:
|
||||||
# 转发视频
|
# async with session.get(
|
||||||
if data.get("desc") == "哔哩哔哩":
|
# data["meta"]["detail_1"]["qqdocurl"],
|
||||||
async with aiohttp.ClientSession(
|
# proxy=get_local_proxy(),
|
||||||
headers=get_user_agent()
|
# timeout=7,
|
||||||
) as session:
|
# ) as response:
|
||||||
async with session.get(
|
# url = str(response.url).split("?")[0]
|
||||||
data["meta"]["detail_1"]["qqdocurl"],
|
# bvid = url.split("/")[-1]
|
||||||
proxy=get_local_proxy(),
|
# vd_info = await video.Video(bvid=bvid).get_info()
|
||||||
timeout=7,
|
# # response = await AsyncHttpx.get(
|
||||||
) as response:
|
# # data["meta"]["detail_1"]["qqdocurl"], timeout=7
|
||||||
url = str(response.url).split("?")[0]
|
# # )
|
||||||
bvid = url.split("/")[-1]
|
# # url = str(response.url).split("?")[0]
|
||||||
vd_info = await video.Video(bvid=bvid).get_info()
|
# # bvid = url.split("/")[-1]
|
||||||
# response = await AsyncHttpx.get(
|
# # vd_info = await video.Video(bvid=bvid).get_info()
|
||||||
# data["meta"]["detail_1"]["qqdocurl"], timeout=7
|
# # 转发专栏
|
||||||
# )
|
# if (
|
||||||
# url = str(response.url).split("?")[0]
|
# data.get("meta")
|
||||||
# bvid = url.split("/")[-1]
|
# and data["meta"].get("news")
|
||||||
# vd_info = await video.Video(bvid=bvid).get_info()
|
# and data["meta"]["news"].get("desc") == "哔哩哔哩专栏"
|
||||||
# 转发专栏
|
# ):
|
||||||
if (
|
# url = data["meta"]["news"]["jumpUrl"]
|
||||||
data.get("meta")
|
# page = None
|
||||||
and data["meta"].get("news")
|
# try:
|
||||||
and data["meta"]["news"].get("desc") == "哔哩哔哩专栏"
|
# browser = await get_browser()
|
||||||
):
|
# if not browser:
|
||||||
url = data["meta"]["news"]["jumpUrl"]
|
# return
|
||||||
page = None
|
# page = await browser.new_page(
|
||||||
try:
|
# user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
||||||
browser = await get_browser()
|
# " (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36"
|
||||||
if not browser:
|
# )
|
||||||
return
|
# await page.goto(url, wait_until="networkidle", timeout=10000)
|
||||||
page = await browser.new_page(
|
# await page.set_viewport_size({"width": 2560, "height": 1080})
|
||||||
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
# await page.click("#app > div")
|
||||||
" (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36"
|
# div = await page.query_selector("#app > div")
|
||||||
)
|
# await div.screenshot(
|
||||||
await page.goto(url, wait_until="networkidle", timeout=10000)
|
# path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
|
||||||
await page.set_viewport_size({"width": 2560, "height": 1080})
|
# timeout=100000,
|
||||||
await page.click("#app > div")
|
# )
|
||||||
div = await page.query_selector("#app > div")
|
# await asyncio.get_event_loop().run_in_executor(
|
||||||
await div.screenshot(
|
# None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
|
||||||
path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
|
# )
|
||||||
timeout=100000,
|
# await parse_bilibili_json.send(
|
||||||
)
|
# "[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
|
||||||
await asyncio.get_event_loop().run_in_executor(
|
# )
|
||||||
None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
|
# await page.close()
|
||||||
)
|
# logger.info(
|
||||||
await parse_bilibili_json.send(
|
# f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
|
||||||
"[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
|
# )
|
||||||
)
|
# except Exception as e:
|
||||||
await page.close()
|
# logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}")
|
||||||
logger.info(
|
# if page:
|
||||||
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
|
# await page.close()
|
||||||
)
|
# return
|
||||||
except Exception as e:
|
# # BV
|
||||||
logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}")
|
# if msg := get_message_text(event.json()):
|
||||||
if page:
|
# if "BV" in msg:
|
||||||
await page.close()
|
# index = msg.find("BV")
|
||||||
return
|
# if len(msg[index + 2 :]) >= 10:
|
||||||
# BV
|
# msg = msg[index : index + 12]
|
||||||
if msg := get_message_text(event.json()):
|
# url = f"https://www.bilibili.com/video/{msg}"
|
||||||
if "BV" in msg:
|
# vd_info = await video.Video(bvid=msg).get_info()
|
||||||
index = msg.find("BV")
|
# elif "av" in msg:
|
||||||
if len(msg[index + 2 :]) >= 10:
|
# index = msg.find("av")
|
||||||
msg = msg[index : index + 12]
|
# if len(msg[index + 2 :]) >= 9:
|
||||||
url = f"https://www.bilibili.com/video/{msg}"
|
# msg = msg[index + 2 : index + 11]
|
||||||
vd_info = await video.Video(bvid=msg).get_info()
|
# if is_number(msg):
|
||||||
elif "av" in msg:
|
# url = f"https://www.bilibili.com/video/{msg}"
|
||||||
index = msg.find("av")
|
# vd_info = await video.Video(aid=int(msg)).get_info()
|
||||||
if len(msg[index + 2 :]) >= 9:
|
# elif "https://b23.tv" in msg:
|
||||||
msg = msg[index + 2 : index + 11]
|
# url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13]
|
||||||
if is_number(msg):
|
# res = await AsyncHttpx.get(url, timeout=7)
|
||||||
url = f"https://www.bilibili.com/video/{msg}"
|
# url = str(res.url).split("?")[0]
|
||||||
vd_info = await video.Video(aid=int(msg)).get_info()
|
# bvid = url.split("/")[-1]
|
||||||
elif "https://b23.tv" in msg:
|
# vd_info = await video.Video(bvid=bvid).get_info()
|
||||||
url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13]
|
# if vd_info:
|
||||||
res = await AsyncHttpx.get(url, timeout=7)
|
# if (
|
||||||
url = str(res.url).split("?")[0]
|
# url in _tmp.keys() and time.time() - _tmp[url] > 30
|
||||||
bvid = url.split("/")[-1]
|
# ) or url not in _tmp.keys():
|
||||||
vd_info = await video.Video(bvid=bvid).get_info()
|
# _tmp[url] = time.time()
|
||||||
if vd_info:
|
# aid = vd_info["aid"]
|
||||||
if (
|
# title = vd_info["title"]
|
||||||
url in _tmp.keys() and time.time() - _tmp[url] > 30
|
# author = vd_info["owner"]["name"]
|
||||||
) or url not in _tmp.keys():
|
# reply = vd_info["stat"]["reply"] # 回复
|
||||||
_tmp[url] = time.time()
|
# favorite = vd_info["stat"]["favorite"] # 收藏
|
||||||
aid = vd_info["aid"]
|
# coin = vd_info["stat"]["coin"] # 投币
|
||||||
title = vd_info["title"]
|
# # like = vd_info['stat']['like'] # 点赞
|
||||||
author = vd_info["owner"]["name"]
|
# # danmu = vd_info['stat']['danmaku'] # 弹幕
|
||||||
reply = vd_info["stat"]["reply"] # 回复
|
# date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
|
||||||
favorite = vd_info["stat"]["favorite"] # 收藏
|
# try:
|
||||||
coin = vd_info["stat"]["coin"] # 投币
|
# await parse_bilibili_json.send(
|
||||||
# like = vd_info['stat']['like'] # 点赞
|
# "[[_task|bilibili_parse]]" +
|
||||||
# danmu = vd_info['stat']['danmaku'] # 弹幕
|
# image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
|
||||||
date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
|
# f"UP:{author}\n"
|
||||||
try:
|
# f"上传日期:{date}\n"
|
||||||
await parse_bilibili_json.send(
|
# f"回复:{reply},收藏:{favorite},投币:{coin}\n"
|
||||||
"[[_task|bilibili_parse]]" +
|
# f"{url}"
|
||||||
image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
|
# )
|
||||||
f"UP:{author}\n"
|
# except ActionFailed:
|
||||||
f"上传日期:{date}\n"
|
# logger.warning(f"{event.group_id} 发送bilibili解析失败")
|
||||||
f"回复:{reply},收藏:{favorite},投币:{coin}\n"
|
# else:
|
||||||
f"{url}"
|
# logger.info(
|
||||||
)
|
# f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
|
||||||
except ActionFailed:
|
# )
|
||||||
logger.warning(f"{event.group_id} 发送bilibili解析失败")
|
#
|
||||||
else:
|
#
|
||||||
logger.info(
|
# def resize(path: str):
|
||||||
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
|
# A = BuildImage(0, 0, background=path, ratio=0.5)
|
||||||
)
|
# A.save(path)
|
||||||
|
|
||||||
|
|
||||||
def resize(path: str):
|
|
||||||
A = BuildImage(0, 0, background=path, ratio=0.5)
|
|
||||||
A.save(path)
|
|
||||||
|
|||||||
+117
-100
@@ -1,100 +1,117 @@
|
|||||||
from asyncio.exceptions import TimeoutError
|
from nonebot import on_command
|
||||||
from nonebot import on_command
|
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
|
||||||
from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent
|
from nonebot.typing import T_State
|
||||||
from nonebot.typing import T_State
|
|
||||||
from configs.path_config import TEMP_PATH
|
from configs.config import Config
|
||||||
from services.log import logger
|
from utils.utils import is_number, change_pixiv_image_links
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from utils.utils import is_number
|
from services.log import logger
|
||||||
from utils.manager import withdraw_message_manager
|
from asyncio.exceptions import TimeoutError
|
||||||
from utils.http_utils import AsyncHttpx
|
from configs.path_config import IMAGE_PATH
|
||||||
from nonebot.params import CommandArg, Arg
|
from utils.manager import withdraw_message_manager
|
||||||
|
from utils.http_utils import AsyncHttpx
|
||||||
try:
|
from nonebot.params import CommandArg, Arg
|
||||||
import ujson as json
|
|
||||||
except ModuleNotFoundError:
|
|
||||||
import json
|
__zx_plugin_name__ = "pid搜索"
|
||||||
|
__plugin_usage__ = """
|
||||||
|
usage:
|
||||||
__zx_plugin_name__ = "pid搜索"
|
通过 pid 搜索图片
|
||||||
__plugin_usage__ = """
|
指令:
|
||||||
usage:
|
p搜 [pid]
|
||||||
通过 pid 搜索图片
|
""".strip()
|
||||||
指令:
|
__plugin_des__ = "通过 pid 搜索图片"
|
||||||
p搜 [pid]
|
__plugin_cmd__ = ["p搜 [pid]"]
|
||||||
""".strip()
|
__plugin_version__ = 0.1
|
||||||
__plugin_des__ = "通过 pid 搜索图片"
|
__plugin_author__ = "HibiKier"
|
||||||
__plugin_cmd__ = ["p搜 [pid]"]
|
__plugin_settings__ = {
|
||||||
__plugin_version__ = 0.1
|
"level": 5,
|
||||||
__plugin_author__ = "HibiKier"
|
"default_status": True,
|
||||||
__plugin_settings__ = {
|
"limit_superuser": False,
|
||||||
"level": 5,
|
"cmd": ["p搜"],
|
||||||
"default_status": True,
|
}
|
||||||
"limit_superuser": False,
|
|
||||||
"cmd": ["p搜"],
|
pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block=True)
|
||||||
}
|
|
||||||
|
|
||||||
pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block=True)
|
@pid_search.handle()
|
||||||
|
async def _h(event: MessageEvent, state: T_State, arg: Message = CommandArg()):
|
||||||
url = "https://api.fantasyzone.cc/tu/search.php"
|
pid = arg.extract_plain_text().strip()
|
||||||
|
if pid:
|
||||||
|
state["pid"] = pid
|
||||||
@pid_search.handle()
|
|
||||||
async def _(state: T_State, arg: Message = CommandArg()):
|
|
||||||
pid = arg.extract_plain_text().strip()
|
headers = {
|
||||||
if pid:
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
|
||||||
state["pid"] = pid
|
" rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
|
||||||
|
"Referer": "https://www.pixiv.net",
|
||||||
|
}
|
||||||
@pid_search.got("pid", prompt="需要查询的图片PID是?")
|
|
||||||
async def _(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
|
|
||||||
if pid in ["取消", "算了"]:
|
@pid_search.got("pid", prompt="需要查询的图片PID是?")
|
||||||
await pid_search.finish("已取消操作...")
|
async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
|
||||||
if is_number(pid):
|
url = Config.get_config("hibiapi", "HIBIAPI") + "/api/pixiv/"
|
||||||
await pid_search.reject_arg("pid", "笨蛋,重新输入数!字!")
|
if pid in ["取消", "算了"]:
|
||||||
params = {
|
await pid_search.finish("已取消操作...")
|
||||||
"id": pid,
|
if not is_number(pid):
|
||||||
"p": 1,
|
await pid_search.reject_arg("pid", "笨蛋,重新输入数!字!")
|
||||||
}
|
for _ in range(3):
|
||||||
for _ in range(3):
|
try:
|
||||||
try:
|
data = (
|
||||||
data = (await AsyncHttpx.get(url, params=params, timeout=5)).json()
|
await AsyncHttpx.get(
|
||||||
except TimeoutError:
|
url,
|
||||||
pass
|
params={"id": pid},
|
||||||
except Exception as e:
|
timeout=5,
|
||||||
await pid_search.finish(f"发生了一些错误..{type(e)}:{e}")
|
)
|
||||||
else:
|
).json()
|
||||||
if not data["width"] and not data["height"]:
|
except TimeoutError:
|
||||||
await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True)
|
pass
|
||||||
pid = data["id"]
|
except Exception as e:
|
||||||
title = data["title"]
|
await pid_search.finish(f"发生了一些错误..{type(e)}:{e}")
|
||||||
author = data["userName"]
|
else:
|
||||||
author_id = data["userId"]
|
if data.get("error"):
|
||||||
img_url = data["url"]
|
await pid_search.finish(data["error"]["user_message"], at_sender=True)
|
||||||
if not await AsyncHttpx.download_file(
|
data = data["illust"]
|
||||||
img_url, TEMP_PATH / f"pid_search_{event.user_id}.png"
|
if not data["width"] and not data["height"]:
|
||||||
):
|
await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True)
|
||||||
await pid_search.finish("图片下载失败了....", at_sender=True)
|
pid = data["id"]
|
||||||
tmp = ""
|
title = data["title"]
|
||||||
if isinstance(event, GroupMessageEvent):
|
author = data["user"]["name"]
|
||||||
tmp = "\n【注】将在30后撤回......"
|
author_id = data["user"]["id"]
|
||||||
msg_id = await pid_search.send(
|
image_list = []
|
||||||
Message(
|
try:
|
||||||
f"title:{title}\n"
|
image_list.append(data["meta_single_page"]["original_image_url"])
|
||||||
f"pid:{pid}\n"
|
except KeyError:
|
||||||
f"author:{author}\n"
|
for image_url in data["meta_pages"]:
|
||||||
f"author_id:{author_id}\n"
|
image_list.append(image_url["image_urls"]["original"])
|
||||||
f'{image(TEMP_PATH / f"pid_search_{event.user_id}.png")}'
|
for i, img_url in enumerate(image_list):
|
||||||
f"{tmp}"
|
img_url = change_pixiv_image_links(img_url)
|
||||||
)
|
if not await AsyncHttpx.download_file(
|
||||||
)
|
img_url,
|
||||||
logger.info(
|
IMAGE_PATH / "temp" / f"pid_search_{event.user_id}_{i}.png",
|
||||||
f"(USER {event.user_id}, "
|
headers=headers,
|
||||||
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
):
|
||||||
f" 查询图片 PID:{pid}"
|
await pid_search.send("图片下载失败了....", at_sender=True)
|
||||||
)
|
tmp = ""
|
||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
withdraw_message_manager.append((msg_id, 30))
|
tmp = "\n【注】将在30后撤回......"
|
||||||
break
|
msg_id = await pid_search.send(
|
||||||
else:
|
Message(
|
||||||
await pid_search.finish("图片下载失败了....", at_sender=True)
|
f"title:{title}\n"
|
||||||
|
f"pid:{pid}\n"
|
||||||
|
f"author:{author}\n"
|
||||||
|
f"author_id:{author_id}\n"
|
||||||
|
f'{image(f"pid_search_{event.user_id}_{i}.png", "temp")}'
|
||||||
|
f"{tmp}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
f"(USER {event.user_id}, "
|
||||||
|
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
|
f" 查询图片 PID:{pid}"
|
||||||
|
)
|
||||||
|
if isinstance(event, GroupMessageEvent):
|
||||||
|
withdraw_message_manager.append((msg_id, 30))
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
await pid_search.finish("图片下载失败了....", at_sender=True)
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ try:
|
|||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
import json
|
import json
|
||||||
|
|
||||||
if str(platform.system()).lower() == "windows":
|
# if str(platform.system()).lower() == "windows":
|
||||||
policy = asyncio.WindowsSelectorEventLoopPolicy()
|
# policy = asyncio.WindowsSelectorEventLoopPolicy()
|
||||||
asyncio.set_event_loop_policy(policy)
|
# asyncio.set_event_loop_policy(policy)
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
|
||||||
|
|||||||
@@ -139,15 +139,14 @@ class OmegaPixivIllusts(db.Model):
|
|||||||
data = await cls.select('pid').gino.all()
|
data = await cls.select('pid').gino.all()
|
||||||
return [x[0] for x in data]
|
return [x[0] for x in data]
|
||||||
|
|
||||||
@classmethod
|
# async def test(cls, nsfw_tag: int = 1):
|
||||||
async def test(cls, nsfw_tag: int = 1):
|
# if nsfw_tag is not None:
|
||||||
if nsfw_tag is not None:
|
# query = cls.query.where(cls.nsfw_tag == nsfw_tag)
|
||||||
query = cls.query.where(cls.nsfw_tag == nsfw_tag)
|
# else:
|
||||||
else:
|
# query = cls.query
|
||||||
query = cls.query
|
# query = query.where((cls.width - cls.height) < 50)
|
||||||
query = query.where((cls.width - cls.height) < 50)
|
# for x in await query.gino.all():
|
||||||
for x in await query.gino.all():
|
# print(x.pid)
|
||||||
print(x.pid)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ usage:
|
|||||||
查看 pix 好康图库
|
查看 pix 好康图库
|
||||||
指令:
|
指令:
|
||||||
pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取
|
pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取
|
||||||
|
pid [uid]: 通过uid获取图片
|
||||||
pix pid[pid]: 查看图库中指定pid图片
|
pix pid[pid]: 查看图库中指定pid图片
|
||||||
""".strip()
|
""".strip()
|
||||||
__plugin_superuser_usage__ = """
|
__plugin_superuser_usage__ = """
|
||||||
@@ -49,7 +50,9 @@ __plugin_configs__ = {
|
|||||||
"value": None,
|
"value": None,
|
||||||
"help": "单次发送的图片数量达到指定值时转发为合并消息",
|
"help": "单次发送的图片数量达到指定值时转发为合并消息",
|
||||||
"default_value": None,
|
"default_value": None,
|
||||||
}
|
},
|
||||||
|
"ALLOW_GROUP_SETU": {"value": False, "help": "允许非超级用户使用-s参数", "default_value": False},
|
||||||
|
"ALLOW_GROUP_R18": {"value": False, "help": "允许非超级用户使用-r参数", "default_value": False},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -80,10 +83,13 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
|||||||
nsfw_tag = 2
|
nsfw_tag = 2
|
||||||
else:
|
else:
|
||||||
nsfw_tag = 0
|
nsfw_tag = 0
|
||||||
if nsfw_tag != 0 and str(event.user_id) not in bot.config.superusers:
|
if str(event.user_id) not in bot.config.superusers:
|
||||||
await pix.finish("你不能看这些噢,这些都是是留给管理员看的...")
|
if (nsfw_tag == 1 and not Config.get_config("pix", "ALLOW_GROUP_SETU")) or (
|
||||||
if n := len(x) == 1 and is_number(x[0]):
|
nsfw_tag == 2 and not Config.get_config("pix", "ALLOW_GROUP_R18")
|
||||||
num = int(x[-1])
|
):
|
||||||
|
await pix.finish("你不能看这些噢,这些都是是留给管理员看的...")
|
||||||
|
if n := len(x) == 1 and is_number(x[0]) and int(x[0]) < 100:
|
||||||
|
num = int(x[0])
|
||||||
keyword = ""
|
keyword = ""
|
||||||
elif n > 1:
|
elif n > 1:
|
||||||
if is_number(x[-1]):
|
if is_number(x[-1]):
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ usage:
|
|||||||
搜图 樱岛麻衣
|
搜图 樱岛麻衣
|
||||||
搜图 樱岛麻衣 5
|
搜图 樱岛麻衣 5
|
||||||
搜图 樱岛麻衣 5 r18
|
搜图 樱岛麻衣 5 r18
|
||||||
|
搜图 樱岛麻衣#1000users 5
|
||||||
|
【多个关键词用#分割】
|
||||||
【默认为 热度排序】
|
【默认为 热度排序】
|
||||||
【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】
|
【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】
|
||||||
""".strip()
|
""".strip()
|
||||||
@@ -69,6 +71,11 @@ __plugin_configs__ = {
|
|||||||
"value": 20,
|
"value": 20,
|
||||||
"help": "作品最大页数限制,超过的作品会被略过",
|
"help": "作品最大页数限制,超过的作品会被略过",
|
||||||
"default_value": 20
|
"default_value": 20
|
||||||
|
},
|
||||||
|
"ALLOW_GROUP_R18": {
|
||||||
|
"value": False,
|
||||||
|
"help": "允许群聊中使用 r18 参数",
|
||||||
|
"default_value": False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Config.add_plugin_config(
|
Config.add_plugin_config(
|
||||||
@@ -152,7 +159,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
|||||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||||
msg = arg.extract_plain_text().strip()
|
msg = arg.extract_plain_text().strip()
|
||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
if "r18" in msg.lower():
|
if "r18" in msg.lower() and not Config.get_config("pixiv_rank_search", "ALLOW_GROUP_R18"):
|
||||||
await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True)
|
await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True)
|
||||||
r18 = 0 if "r18" in msg else 1
|
r18 = 0 if "r18" in msg else 1
|
||||||
msg = msg.replace("r18", "").strip().split()
|
msg = msg.replace("r18", "").strip().split()
|
||||||
@@ -161,8 +168,8 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
|||||||
info_list = None
|
info_list = None
|
||||||
num = 10
|
num = 10
|
||||||
page = 1
|
page = 1
|
||||||
if (n := len(msg)) == 1:
|
if (n := len(msg)) > 0:
|
||||||
keyword = msg[0]
|
keyword = msg[0].replace("#"," ")
|
||||||
if n > 1:
|
if n > 1:
|
||||||
if not is_number(msg[1]):
|
if not is_number(msg[1]):
|
||||||
await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True)
|
await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True)
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ from services.log import logger
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
if platform.system() == "Windows":
|
# if platform.system() == "Windows":
|
||||||
import asyncio
|
# import asyncio
|
||||||
|
#
|
||||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||||
|
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
|
|||||||
@@ -62,12 +62,12 @@ async def _poke_event(event: PokeNotifyEvent):
|
|||||||
rst = "气死我了!"
|
rst = "气死我了!"
|
||||||
await poke_.finish(rst + random.choice(poke__reply), at_sender=True)
|
await poke_.finish(rst + random.choice(poke__reply), at_sender=True)
|
||||||
rand = random.random()
|
rand = random.random()
|
||||||
if rand <= 0.3:
|
path = random.choice(["luoli", "meitu"])
|
||||||
path = random.choice(["luoli", "meitu"])
|
if rand <= 0.3 and len(os.listdir(IMAGE_PATH / "image_management" / path)) > 0:
|
||||||
index = random.randint(0, len(os.listdir(IMAGE_PATH / "image_management" / path)))
|
index = random.randint(0, len(os.listdir(IMAGE_PATH / "image_management" / path)))
|
||||||
result = f"id:{index}" + image(f"{index}.jpg", "image_management/" + path)
|
result = f"id:{index}" + image(f"{index}.jpg", "image_management/" + path)
|
||||||
await poke_.send(result)
|
await poke_.send(result)
|
||||||
logger.info(f"USER {event.user_id} 戳了戳我 回复: {result} \n {result}")
|
logger.info(f"USER {event.user_id} 戳了戳我 回复: {result} {result}")
|
||||||
elif 0.3 < rand < 0.6:
|
elif 0.3 < rand < 0.6:
|
||||||
voice = random.choice(os.listdir(RECORD_PATH / "dinggong"))
|
voice = random.choice(os.listdir(RECORD_PATH / "dinggong"))
|
||||||
result = record(voice, "dinggong")
|
result = record(voice, "dinggong")
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State, key_word: str = ArgSt
|
|||||||
Config.get_config("search_anime", "SEARCH_ANIME_MAX_INFO"),
|
Config.get_config("search_anime", "SEARCH_ANIME_MAX_INFO"),
|
||||||
)
|
)
|
||||||
if anime_report:
|
if anime_report:
|
||||||
|
if isinstance(anime_report, str):
|
||||||
|
await search_anime.finish(anime_report)
|
||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
mes_list = custom_forward_msg(anime_report, bot.self_id)
|
mes_list = custom_forward_msg(anime_report, bot.self_id)
|
||||||
await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
|
await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
|
||||||
|
|||||||
@@ -3,18 +3,18 @@ import feedparser
|
|||||||
from urllib import parse
|
from urllib import parse
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
from typing import List
|
from typing import List, Union
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
async def from_anime_get_info(key_word: str, max_: int) -> List[str]:
|
async def from_anime_get_info(key_word: str, max_: int) -> Union[str, List[str]]:
|
||||||
s_time = time.time()
|
s_time = time.time()
|
||||||
repass = ""
|
|
||||||
url = "https://share.dmhy.org/topics/rss/rss.xml?keyword=" + parse.quote(key_word)
|
url = "https://share.dmhy.org/topics/rss/rss.xml?keyword=" + parse.quote(key_word)
|
||||||
try:
|
try:
|
||||||
repass = await get_repass(url, max_)
|
repass = await get_repass(url, max_)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Timeout! {}".format(e))
|
logger.error(f"发生了一些错误 {type(e)}:{e}")
|
||||||
|
return "发生了一些错误!"
|
||||||
repass.insert(0, f"搜索 {key_word} 结果(耗时 {int(time.time() - s_time)} 秒):\n")
|
repass.insert(0, f"搜索 {key_word} 结果(耗时 {int(time.time() - s_time)} 秒):\n")
|
||||||
return repass
|
return repass
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ async def get_saucenao_image(url: str) -> Union[str, List[str]]:
|
|||||||
}
|
}
|
||||||
data = (await AsyncHttpx.post(API_URL_SAUCENAO, params=params)).json()
|
data = (await AsyncHttpx.post(API_URL_SAUCENAO, params=params)).json()
|
||||||
if data["header"]["status"] != 0:
|
if data["header"]["status"] != 0:
|
||||||
return "Saucenao识图失败.."
|
return f"Saucenao识图失败..status:{data['header']['status']}"
|
||||||
data = data["results"]
|
data = data["results"]
|
||||||
data = (
|
data = (
|
||||||
data
|
data
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from services.log import logger
|
|||||||
from models.sign_group_user import SignGroupUser
|
from models.sign_group_user import SignGroupUser
|
||||||
from nonebot.message import run_postprocessor
|
from nonebot.message import run_postprocessor
|
||||||
from nonebot.matcher import Matcher
|
from nonebot.matcher import Matcher
|
||||||
from typing import Optional, Type
|
from typing import Optional, Type, Any
|
||||||
from gino.exceptions import UninitializedError
|
from gino.exceptions import UninitializedError
|
||||||
from utils.utils import (
|
from utils.utils import (
|
||||||
is_number,
|
is_number,
|
||||||
@@ -33,7 +33,7 @@ from .data_source import (
|
|||||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||||
from configs.config import Config, NICKNAME
|
from configs.config import Config, NICKNAME
|
||||||
from utils.manager import withdraw_message_manager
|
from utils.manager import withdraw_message_manager
|
||||||
from nonebot.params import CommandArg, Command
|
from nonebot.params import CommandArg, Command, RegexGroup
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -97,6 +97,7 @@ __plugin_configs__ = {
|
|||||||
},
|
},
|
||||||
"TIMEOUT": {"value": 10, "help": "色图下载超时限制(秒)", "default_value": 10},
|
"TIMEOUT": {"value": 10, "help": "色图下载超时限制(秒)", "default_value": 10},
|
||||||
"SHOW_INFO": {"value": True, "help": "是否显示色图的基本信息,如PID等", "default_value": True},
|
"SHOW_INFO": {"value": True, "help": "是否显示色图的基本信息,如PID等", "default_value": True},
|
||||||
|
"ALLOW_GROUP_R18": {"value": False, "help": "在群聊中启用R18权限", "default_value": False},
|
||||||
}
|
}
|
||||||
Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pixiv.re", help_="Pixiv反向代理")
|
Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pixiv.re", help_="Pixiv反向代理")
|
||||||
|
|
||||||
@@ -148,10 +149,16 @@ async def _(
|
|||||||
if cmd[0] == "色图r" and isinstance(event, PrivateMessageEvent):
|
if cmd[0] == "色图r" and isinstance(event, PrivateMessageEvent):
|
||||||
r18 = 1
|
r18 = 1
|
||||||
num = 10
|
num = 10
|
||||||
elif cmd[0] == "色图r" and isinstance(event, GroupMessageEvent):
|
elif (
|
||||||
await setu.finish(
|
cmd[0] == "色图r"
|
||||||
random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
|
and isinstance(event, GroupMessageEvent)
|
||||||
)
|
):
|
||||||
|
if not Config.get_config("send_setu", "ALLOW_GROUP_R18"):
|
||||||
|
await setu.finish(
|
||||||
|
random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
r18 = 1
|
||||||
# 有 数字 的话先尝试本地色图id
|
# 有 数字 的话先尝试本地色图id
|
||||||
if msg and is_number(msg):
|
if msg and is_number(msg):
|
||||||
setu_list, code = await get_setu_list(int(msg), r18=r18)
|
setu_list, code = await get_setu_list(int(msg), r18=r18)
|
||||||
@@ -190,7 +197,7 @@ num_key = {
|
|||||||
|
|
||||||
|
|
||||||
@setu_reg.handle()
|
@setu_reg.handle()
|
||||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||||
if isinstance(event, GroupMessageEvent):
|
if isinstance(event, GroupMessageEvent):
|
||||||
impression = (
|
impression = (
|
||||||
await SignGroupUser.ensure(event.user_id, event.group_id)
|
await SignGroupUser.ensure(event.user_id, event.group_id)
|
||||||
@@ -198,28 +205,15 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
|
|||||||
luox = get_luoxiang(impression)
|
luox = get_luoxiang(impression)
|
||||||
if luox:
|
if luox:
|
||||||
await setu.finish(luox, at_sender=True)
|
await setu.finish(luox, at_sender=True)
|
||||||
msg = arg.extract_plain_text().strip()
|
num, tags = reg_group
|
||||||
num = 1
|
num = num or 1
|
||||||
msg = re.search(r"(.*)[份发张个次点](.*)[瑟涩色]图", msg)
|
tags = tags[:-1] if tags and tags[-1] == "的" else tags
|
||||||
# 解析 tags 以及 num
|
if num_key.get(num):
|
||||||
if msg:
|
num = num_key[num]
|
||||||
num = msg.group(1)
|
try:
|
||||||
tags = msg.group(2)
|
num = int(num)
|
||||||
if tags:
|
except ValueError:
|
||||||
tags = tags[:-1] if tags[-1] == "的" else tags
|
num = 1
|
||||||
if num:
|
|
||||||
num = num[-1]
|
|
||||||
if num_key.get(num):
|
|
||||||
num = num_key[num]
|
|
||||||
elif is_number(num):
|
|
||||||
try:
|
|
||||||
num = int(num)
|
|
||||||
except ValueError:
|
|
||||||
num = 1
|
|
||||||
else:
|
|
||||||
num = 1
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
await send_setu_handle(setu_reg, event, "色图", tags, num, 0)
|
await send_setu_handle(setu_reg, event, "色图", tags, num, 0)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+17
-21
@@ -24,6 +24,8 @@ from io import BytesIO
|
|||||||
import asyncio
|
import asyncio
|
||||||
import random
|
import random
|
||||||
import nonebot
|
import nonebot
|
||||||
|
import time
|
||||||
|
import locale
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
@@ -55,13 +57,10 @@ async def get_card(
|
|||||||
date = datetime.now().date()
|
date = datetime.now().date()
|
||||||
_type = "view" if is_card_view else "sign"
|
_type = "view" if is_card_view else "sign"
|
||||||
card_file = (
|
card_file = (
|
||||||
Path(SIGN_TODAY_CARD_PATH)
|
Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.group_id}_{_type}_{date}.png"
|
||||||
/ f"{user_id}_{user.group_id}_{_type}_{date}.png"
|
|
||||||
)
|
)
|
||||||
if card_file.exists():
|
if card_file.exists():
|
||||||
return image(
|
return image(f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card")
|
||||||
f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
if add_impression == -1:
|
if add_impression == -1:
|
||||||
card_file = (
|
card_file = (
|
||||||
@@ -75,9 +74,7 @@ async def get_card(
|
|||||||
)
|
)
|
||||||
is_card_view = True
|
is_card_view = True
|
||||||
ava = BytesIO(await get_user_avatar(user_id))
|
ava = BytesIO(await get_user_avatar(user_id))
|
||||||
uid = await GroupInfoUser.get_group_member_uid(
|
uid = await GroupInfoUser.get_group_member_uid(user.user_qq, user.group_id)
|
||||||
user.user_qq, user.group_id
|
|
||||||
)
|
|
||||||
impression_list = None
|
impression_list = None
|
||||||
if is_card_view:
|
if is_card_view:
|
||||||
_, impression_list, _ = await SignGroupUser.get_all_impression(
|
_, impression_list, _ = await SignGroupUser.get_all_impression(
|
||||||
@@ -128,9 +125,13 @@ def _generate_card(
|
|||||||
level, next_impression, previous_impression = get_level_and_next_impression(
|
level, next_impression, previous_impression = get_level_and_next_impression(
|
||||||
user.impression
|
user.impression
|
||||||
)
|
)
|
||||||
|
interpolation = next_impression - user.impression
|
||||||
|
if level == "9":
|
||||||
|
level = "8"
|
||||||
|
interpolation = 0
|
||||||
info_img.text((0, 0), f"· 好感度等级:{level} [{lik2relation[level]}]")
|
info_img.text((0, 0), f"· 好感度等级:{level} [{lik2relation[level]}]")
|
||||||
info_img.text((0, 20), f"· {NICKNAME}对你的态度:{level2attitude[level]}")
|
info_img.text((0, 20), f"· {NICKNAME}对你的态度:{level2attitude[level]}")
|
||||||
info_img.text((0, 40), f"· 距离升级还差 {next_impression - user.impression:.2f} 好感度")
|
info_img.text((0, 40), f"· 距离升级还差 {interpolation:.2f} 好感度")
|
||||||
|
|
||||||
bar_bk = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png")
|
bar_bk = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png")
|
||||||
bar = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar.png")
|
bar = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar.png")
|
||||||
@@ -240,7 +241,9 @@ def _generate_card(
|
|||||||
f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}",
|
f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}",
|
||||||
)
|
)
|
||||||
today_data.text((0, 25), f"总金币:{gold}")
|
today_data.text((0, 25), f"总金币:{gold}")
|
||||||
default_setu_prob = Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100
|
default_setu_prob = (
|
||||||
|
Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100
|
||||||
|
)
|
||||||
today_data.text(
|
today_data.text(
|
||||||
(0, 50),
|
(0, 50),
|
||||||
f"色图概率:{(default_setu_prob + user.impression if user.impression < 100 else 100):.2f}%",
|
f"色图概率:{(default_setu_prob + user.impression if user.impression < 100 else 100):.2f}%",
|
||||||
@@ -259,15 +262,12 @@ def _generate_card(
|
|||||||
today_data.text((0, 25), f"金币 + {gold}")
|
today_data.text((0, 25), f"金币 + {gold}")
|
||||||
_type = "sign"
|
_type = "sign"
|
||||||
current_date = datetime.now()
|
current_date = datetime.now()
|
||||||
week = current_date.isoweekday()
|
current_datetime_str = current_date.strftime("%Y-%m-%d %a %H:%M:%S")
|
||||||
data = current_date.date()
|
data = current_date.date()
|
||||||
hour = current_date.hour
|
|
||||||
minute = current_date.minute
|
|
||||||
second = current_date.second
|
|
||||||
data_img = BuildImage(
|
data_img = BuildImage(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
plain_text=f"时间:{data} {weekdays[week]} {hour}:{minute}:{second}",
|
plain_text=f"时间:{current_datetime_str}",
|
||||||
color=(255, 255, 255, 0),
|
color=(255, 255, 255, 0),
|
||||||
font_size=20,
|
font_size=20,
|
||||||
)
|
)
|
||||||
@@ -286,12 +286,8 @@ def _generate_card(
|
|||||||
bk.paste(today_sign_text_img, (550, 180), True)
|
bk.paste(today_sign_text_img, (550, 180), True)
|
||||||
bk.paste(today_data, (580, 220), True)
|
bk.paste(today_data, (580, 220), True)
|
||||||
bk.paste(watermark, (15, 400), True)
|
bk.paste(watermark, (15, 400), True)
|
||||||
bk.save(
|
bk.save(SIGN_TODAY_CARD_PATH / f"{user_id}_{user.group_id}_{_type}_{data}.png")
|
||||||
SIGN_TODAY_CARD_PATH / f"{user_id}_{user.group_id}_{_type}_{data}.png"
|
return image(f"{user_id}_{user.group_id}_{_type}_{data}.png", "sign/today_card")
|
||||||
)
|
|
||||||
return image(
|
|
||||||
f"{user_id}_{user.group_id}_{_type}_{data}.png", "sign/today_card"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def generate_progress_bar_pic():
|
def generate_progress_bar_pic():
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ async def _(
|
|||||||
global _prefix_count_dict
|
global _prefix_count_dict
|
||||||
if (
|
if (
|
||||||
matcher.type == "message"
|
matcher.type == "message"
|
||||||
and matcher.priority not in [1, 9]
|
and matcher.priority not in [1, 999]
|
||||||
and matcher.plugin_name not in ["update_info", "statistics_handle"]
|
and matcher.plugin_name not in ["update_info", "statistics_handle"]
|
||||||
):
|
):
|
||||||
module = matcher.plugin_name
|
module = matcher.plugin_name
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ async def translate_msg(language_type, msg):
|
|||||||
}
|
}
|
||||||
data = (await AsyncHttpx.post(url, data=data)).json()
|
data = (await AsyncHttpx.post(url, data=data)).json()
|
||||||
if data["errorCode"] == 0:
|
if data["errorCode"] == 0:
|
||||||
return f'原文:{msg}\n翻译{data["translateResult"][0][0]["tgt"]}'
|
return f'原文:{msg}\n翻译:{data["translateResult"][0][0]["tgt"]}'
|
||||||
return "翻译惜败.."
|
return "翻译惜败.."
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import asyncio
|
|||||||
import platform
|
import platform
|
||||||
import os
|
import os
|
||||||
|
|
||||||
if platform.system() == "Windows":
|
# if platform.system() == "Windows":
|
||||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||||
|
|
||||||
|
|
||||||
url = "https://github.com/Mrs4s/go-cqhttp/releases"
|
url = "https://github.com/Mrs4s/go-cqhttp/releases"
|
||||||
|
|||||||
Executable → Regular
+78
-70
@@ -1,70 +1,78 @@
|
|||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
|
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
|
||||||
from nonebot.params import CommandArg
|
from nonebot.params import CommandArg
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from ._data_source import get_data, gen_wbtop_pic
|
from .data_source import gen_wbtop_pic,get_wbtop
|
||||||
from utils.utils import is_number
|
from utils.utils import is_number
|
||||||
from configs.path_config import IMAGE_PATH
|
from configs.path_config import IMAGE_PATH
|
||||||
from utils.http_utils import AsyncPlaywright
|
from utils.http_utils import AsyncPlaywright
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import datetime
|
||||||
__zx_plugin_name__ = "微博热搜"
|
__zx_plugin_name__ = "微博热搜"
|
||||||
__plugin_usage__ = """
|
__plugin_usage__ = """
|
||||||
usage:
|
usage:
|
||||||
在QQ上吃个瓜
|
在QQ上吃个瓜
|
||||||
指令:
|
指令:
|
||||||
微博热搜:发送实时热搜
|
微博热搜:发送实时热搜
|
||||||
微博热搜 [id]:截图该热搜页面
|
微博热搜 [id]:截图该热搜页面
|
||||||
示例:微博热搜 5
|
示例:微博热搜 5
|
||||||
""".strip()
|
""".strip()
|
||||||
__plugin_des__ = "刚买完瓜,在吃瓜现场"
|
__plugin_des__ = "刚买完瓜,在吃瓜现场"
|
||||||
__plugin_cmd__ = ["微博热搜", "微博热搜 [id]"]
|
__plugin_cmd__ = ["微博热搜", "微博热搜 [id]"]
|
||||||
__plugin_version__ = 0.1
|
__plugin_version__ = 0.2
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier & yajiwa"
|
||||||
__plugin_settings__ = {
|
__plugin_settings__ = {
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"default_status": True,
|
"default_status": True,
|
||||||
"limit_superuser": False,
|
"limit_superuser": False,
|
||||||
"cmd": ["微博热搜"],
|
"cmd": ["微博热搜"],
|
||||||
}
|
}
|
||||||
|
|
||||||
wbtop = on_command("wbtop", aliases={"微博热搜"}, priority=5, block=True)
|
wbtop = on_command("wbtop", aliases={"微博热搜"}, priority=5, block=True)
|
||||||
|
|
||||||
|
|
||||||
wbtop_url = "https://v2.alapi.cn/api/new/wbtop"
|
wbtop_url = "https://weibo.com/ajax/side/hotSearch"
|
||||||
|
|
||||||
wbtop_data = []
|
wbtop_data = []
|
||||||
|
|
||||||
|
|
||||||
@wbtop.handle()
|
@wbtop.handle()
|
||||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||||
global wbtop_data
|
global wbtop_data
|
||||||
msg = arg.extract_plain_text().strip()
|
msg = arg.extract_plain_text().strip()
|
||||||
if not wbtop_data or not msg:
|
if not wbtop_data or not msg:
|
||||||
data, code = await get_data(wbtop_url)
|
if wbtop_data:
|
||||||
if code != 200:
|
now_time = datetime.datetime.now()
|
||||||
await wbtop.finish(data, at_sender=True)
|
if now_time > wbtop_data["time"] + datetime.timedelta(minutes=5):
|
||||||
wbtop_data = data["data"]
|
data, code = await get_wbtop(wbtop_url)
|
||||||
if not msg:
|
if code != 200:
|
||||||
img = await asyncio.get_event_loop().run_in_executor(
|
await wbtop.finish(data, at_sender=True)
|
||||||
None, gen_wbtop_pic, wbtop_data
|
wbtop_data = data
|
||||||
)
|
else:
|
||||||
await wbtop.send(img)
|
data, code = await get_wbtop(wbtop_url)
|
||||||
logger.info(
|
if code != 200:
|
||||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
await wbtop.finish(data, at_sender=True)
|
||||||
f" 查询微博热搜"
|
wbtop_data = data
|
||||||
)
|
if not msg:
|
||||||
if is_number(msg) and 0 < int(msg) <= 50:
|
img = await asyncio.get_event_loop().run_in_executor(
|
||||||
url = wbtop_data[int(msg) - 1]["url"]
|
None, gen_wbtop_pic, wbtop_data["data"]
|
||||||
await wbtop.send("开始截取数据...")
|
)
|
||||||
img = await AsyncPlaywright.screenshot(
|
await wbtop.send(img)
|
||||||
url,
|
logger.info(
|
||||||
f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png",
|
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
"#pl_feedlist_index",
|
f" 查询微博热搜"
|
||||||
wait_time=5
|
)
|
||||||
)
|
if is_number(msg) and 0 < int(msg) <= 50:
|
||||||
if img:
|
url = wbtop_data["data"][int(msg) - 1]["url"]
|
||||||
await wbtop.send(img)
|
await wbtop.send("开始截取数据...")
|
||||||
else:
|
img = await AsyncPlaywright.screenshot(
|
||||||
await wbtop.send("发生了一些错误.....")
|
url,
|
||||||
|
f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png",
|
||||||
|
"#pl_feed_main",
|
||||||
|
wait_time=12
|
||||||
|
)
|
||||||
|
if img:
|
||||||
|
await wbtop.send(img)
|
||||||
|
else:
|
||||||
|
await wbtop.send("发生了一些错误.....")
|
||||||
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
from nonebot.adapters.onebot.v11 import MessageSegment
|
||||||
|
from utils.image_utils import BuildImage
|
||||||
|
from utils.message_builder import image
|
||||||
|
from configs.path_config import IMAGE_PATH
|
||||||
|
from typing import Tuple, Union
|
||||||
|
from utils.http_utils import AsyncHttpx
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
async def get_wbtop(url: str) -> Tuple[Union[dict, str], int]:
|
||||||
|
"""
|
||||||
|
:param url: 请求链接
|
||||||
|
"""
|
||||||
|
n = 0
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
data = []
|
||||||
|
get_response = (await AsyncHttpx.get(url, timeout=20))
|
||||||
|
if get_response.status_code == 200:
|
||||||
|
data_json = get_response.json()['data']['realtime']
|
||||||
|
for data_item in data_json:
|
||||||
|
# 如果是广告,则不添加
|
||||||
|
if 'is_ad' in data_item:
|
||||||
|
continue
|
||||||
|
dic = {
|
||||||
|
'hot_word': data_item['note'],
|
||||||
|
'hot_word_num': str(data_item['num']),
|
||||||
|
'url': 'https://s.weibo.com/weibo?q=%23' + data_item['word'] + '%23',
|
||||||
|
}
|
||||||
|
data.append(dic)
|
||||||
|
if not data:
|
||||||
|
return "没有搜索到...", 997
|
||||||
|
return {'data': data, 'time': datetime.datetime.now()}, 200
|
||||||
|
else:
|
||||||
|
if n > 2:
|
||||||
|
return f'获取失败,请十分钟后再试', 999
|
||||||
|
else:
|
||||||
|
n += 1
|
||||||
|
continue
|
||||||
|
except TimeoutError:
|
||||||
|
return "超时了....", 998
|
||||||
|
|
||||||
|
|
||||||
|
def gen_wbtop_pic(data: dict) -> MessageSegment:
|
||||||
|
"""
|
||||||
|
生成微博热搜图片
|
||||||
|
:param data: 微博热搜数据
|
||||||
|
"""
|
||||||
|
bk = BuildImage(700, 32 * 50 + 280, 700, 32, color="#797979")
|
||||||
|
wbtop_bk = BuildImage(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
|
||||||
|
bk.paste(wbtop_bk)
|
||||||
|
text_bk = BuildImage(700, 32 * 50, 700, 32, color="#797979")
|
||||||
|
for i, data in enumerate(data):
|
||||||
|
title = f"{i + 1}. {data['hot_word']}"
|
||||||
|
hot = str(data["hot_word_num"])
|
||||||
|
img = BuildImage(700, 30, font_size=20)
|
||||||
|
w, h = img.getsize(title)
|
||||||
|
img.text((10, int((30 - h) / 2)), title)
|
||||||
|
img.text((580, int((30 - h) / 2)), hot)
|
||||||
|
text_bk.paste(img)
|
||||||
|
bk.paste(text_bk, (0, 280))
|
||||||
|
return image(b64=bk.pic2bs4())
|
||||||
@@ -12,7 +12,7 @@ __plugin_usage__ = """
|
|||||||
usage:
|
usage:
|
||||||
普普通通的查天气吧
|
普普通通的查天气吧
|
||||||
指令:
|
指令:
|
||||||
[城市]天气/天气[城市]
|
[城市]天气
|
||||||
""".strip()
|
""".strip()
|
||||||
__plugin_des__ = "出门要看看天气,不要忘了带伞"
|
__plugin_des__ = "出门要看看天气,不要忘了带伞"
|
||||||
__plugin_cmd__ = ["[城市]天气/天气[城市]"]
|
__plugin_cmd__ = ["[城市]天气/天气[城市]"]
|
||||||
@@ -27,13 +27,13 @@ __plugin_settings__ = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
weather = on_regex(r".{0,10}?(.*)的?天气.*?.{0,10}", priority=5, block=True)
|
weather = on_regex(r".{0,10}?(.*)的?天气.{0,10}", priority=5, block=True)
|
||||||
|
|
||||||
|
|
||||||
@weather.handle()
|
@weather.handle()
|
||||||
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||||
msg = reg_group[0]
|
msg = reg_group[0]
|
||||||
if msg[-1] != "市":
|
if msg and msg[-1] != "市":
|
||||||
msg += "市"
|
msg += "市"
|
||||||
city = ""
|
city = ""
|
||||||
if msg:
|
if msg:
|
||||||
|
|||||||
@@ -127,6 +127,8 @@ def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result:
|
|||||||
else:
|
else:
|
||||||
if plugin.plugin_settings:
|
if plugin.plugin_settings:
|
||||||
for key, value in plugin.plugin_settings:
|
for key, value in plugin.plugin_settings:
|
||||||
|
if plugin.plugin_settings.cmd:
|
||||||
|
plugin.plugin_settings.cmd = plugin.plugin_settings.cmd.split(',')
|
||||||
plugins2settings_manager.set_module_data(plugin.model, key, value)
|
plugins2settings_manager.set_module_data(plugin.model, key, value)
|
||||||
if plugin.plugin_manager:
|
if plugin.plugin_manager:
|
||||||
for key, value in plugin.plugin_manager:
|
for key, value in plugin.plugin_manager:
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class CountLimit(BaseModel):
|
|||||||
"""
|
"""
|
||||||
max_count: int
|
max_count: int
|
||||||
status: bool
|
status: bool
|
||||||
limit_type: bool
|
limit_type: str
|
||||||
rst: Optional[str]
|
rst: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message, Bot
|
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message, Bot
|
||||||
|
from nonebot.internal.params import ArgStr, Arg
|
||||||
|
from nonebot.params import CommandArg
|
||||||
|
|
||||||
from .data_source import get_anime
|
from .data_source import get_anime
|
||||||
from nonebot import on_command
|
from nonebot import on_command
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from nonebot.params import Arg
|
|
||||||
from utils.utils import get_message_img
|
from utils.utils import get_message_img
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
|
|
||||||
@@ -31,10 +33,10 @@ what_anime = on_command("识番", priority=5, block=True)
|
|||||||
|
|
||||||
|
|
||||||
@what_anime.handle()
|
@what_anime.handle()
|
||||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
async def _(bot: Bot, event: MessageEvent, state: T_State, args: Message = CommandArg()):
|
||||||
img_url = get_message_img(event.json())
|
img_url = get_message_img(event.json())
|
||||||
if img_url:
|
if img_url:
|
||||||
state["img_url"] = img_url[0]
|
state["img_url"] = args
|
||||||
|
|
||||||
|
|
||||||
@what_anime.got("img_url", prompt="虚空识番?来图来图GKD")
|
@what_anime.got("img_url", prompt="虚空识番?来图来图GKD")
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ class WordBankBuilder:
|
|||||||
def __init__(self, user_id: int, group_id: int, problem: str):
|
def __init__(self, user_id: int, group_id: int, problem: str):
|
||||||
self._data = {
|
self._data = {
|
||||||
"user_id": user_id,
|
"user_id": user_id,
|
||||||
"group_id": group_id,
|
"group_id": group_id}
|
||||||
"problem": problem
|
self.problem = problem
|
||||||
}
|
|
||||||
|
|
||||||
def set_placeholder(self, id_: int, placeholder: Union[str, int]):
|
def set_placeholder(self, id_: int, placeholder: Union[str, int]):
|
||||||
"""
|
"""
|
||||||
@@ -28,13 +27,20 @@ class WordBankBuilder:
|
|||||||
"""
|
"""
|
||||||
self._data["answer"] = answer
|
self._data["answer"] = answer
|
||||||
|
|
||||||
async def save(self,search_type):
|
def set_problem(self, problem: str):
|
||||||
|
"""
|
||||||
|
设置问题
|
||||||
|
:param problem: 问题
|
||||||
|
"""
|
||||||
|
self._data["problem"] = problem
|
||||||
|
|
||||||
|
async def save(self, search_type):
|
||||||
user_id = self._data["user_id"]
|
user_id = self._data["user_id"]
|
||||||
group_id = self._data["group_id"]
|
group_id = self._data["group_id"]
|
||||||
problem = self._data["problem"]
|
problem = self._data["problem"]
|
||||||
answer = self._data["answer"]
|
answer = self._data["answer"]
|
||||||
placeholder = self._data.get("placeholder")
|
placeholder = self._data.get("placeholder")
|
||||||
return await WordBank.add_problem_answer(user_id, group_id, search_type,problem, answer, placeholder)
|
return await WordBank.add_problem_answer(user_id, group_id, search_type, problem, answer, placeholder)
|
||||||
|
|
||||||
async def update(self, index):
|
async def update(self, index):
|
||||||
user_id = self._data["user_id"]
|
user_id = self._data["user_id"]
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Event
|
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Event
|
||||||
from utils.utils import get_message_text
|
from utils.utils import get_message_img_file
|
||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
from .model import WordBank
|
from .model import WordBank
|
||||||
|
|
||||||
|
|
||||||
async def check(bot: Bot, event: Event, state: T_State) -> bool:
|
async def check(bot: Bot, event: Event, state: T_State) -> bool:
|
||||||
if isinstance(event, GroupMessageEvent):
|
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*]")
|
||||||
|
msg = strinfo.sub(f'{img_file}]', msg)
|
||||||
return bool(
|
return bool(
|
||||||
await WordBank.check(event.group_id, get_message_text(event.json()), event.is_tome())
|
await WordBank.check(event.group_id, msg, event.is_tome())
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ from ._rule import check
|
|||||||
from .model import WordBank
|
from .model import WordBank
|
||||||
from configs.path_config import DATA_PATH
|
from configs.path_config import DATA_PATH
|
||||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||||
from utils.utils import get_message_text
|
from utils.utils import get_message_at, get_message_img
|
||||||
from nonebot import on_message
|
from nonebot import on_message
|
||||||
from models.group_member_info import GroupInfoUser
|
from models.group_member_info import GroupInfoUser
|
||||||
|
from utils.utils import get_message_img_file, is_number
|
||||||
|
import re
|
||||||
|
|
||||||
__zx_plugin_name__ = "词库问答回复操作 [Hidden]"
|
__zx_plugin_name__ = "词库问答回复操作 [Hidden]"
|
||||||
|
|
||||||
@@ -17,8 +19,14 @@ message_handle = on_message(priority=6, block=True, rule=check)
|
|||||||
|
|
||||||
@message_handle.handle()
|
@message_handle.handle()
|
||||||
async def _(event: GroupMessageEvent):
|
async def _(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*]")
|
||||||
|
msg = strinfo.sub(f'{img_file}]', msg)
|
||||||
q = await WordBank.check(
|
q = await WordBank.check(
|
||||||
event.group_id, get_message_text(event.json()), event.is_tome()
|
event.group_id, msg, event.is_tome()
|
||||||
)
|
)
|
||||||
await message_handle.send(await get_one_answer(event, q.format, q.answer))
|
await message_handle.send(await get_one_answer(event, q.format, q.answer))
|
||||||
|
|
||||||
@@ -54,3 +62,68 @@ async def get_one_answer(event, format, _answer, all=1):
|
|||||||
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + "@" + q.user_name
|
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + "@" + q.user_name
|
||||||
_a = _a[_a.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):]
|
_a = _a[_a.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):]
|
||||||
return answer + _a
|
return answer + _a
|
||||||
|
|
||||||
|
|
||||||
|
# 处理单条问题
|
||||||
|
async def get_one_problem(event, problem):
|
||||||
|
strinfo = re.compile(f",subType=\d")
|
||||||
|
problem = strinfo.sub('', problem)
|
||||||
|
_problem = problem
|
||||||
|
_p = problem
|
||||||
|
problem = ''
|
||||||
|
for img in get_message_img(event.json()):
|
||||||
|
_x = img.split("?")[0]
|
||||||
|
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", _p)
|
||||||
|
if r:
|
||||||
|
_problem = _problem.replace(
|
||||||
|
rf",url={img}",
|
||||||
|
f"",
|
||||||
|
)
|
||||||
|
problem += _p[: _p.find(f"[CQ:image,file={r.group(1)},url={img}]")] + image(img)
|
||||||
|
_p = _p[
|
||||||
|
_p.find(f"[CQ:image,file={r.group(1)},url={img}]") + len(f"[CQ:image,file={r.group(1)},url={img}]"):]
|
||||||
|
for at_ in get_message_at(event.json()):
|
||||||
|
r = re.search(rf"\[CQ:at,qq={at_}]", problem)
|
||||||
|
if r:
|
||||||
|
q = await GroupInfoUser.get_member_info(
|
||||||
|
int(at_), event.group_id)
|
||||||
|
problem += _p[: _p.find(f"[CQ:at,qq={at_}]")] + "@" + q.user_name
|
||||||
|
_p = _p[_p.find(f"[CQ:at,qq={at_}]") + len(f"[CQ:at,qq={at_}]"):]
|
||||||
|
return _problem, problem + _p
|
||||||
|
|
||||||
|
|
||||||
|
# 显示单条数据库问题
|
||||||
|
async def get_one_image_problem(event, problem):
|
||||||
|
path = data_dir / f"{event.group_id}" / "problem"
|
||||||
|
placeholder_list = []
|
||||||
|
idx = 0
|
||||||
|
img_list = re.findall(rf"\[CQ:image,file=(.*?)]", problem)
|
||||||
|
at_list = re.findall(rf"\[CQ:at,qq=(.*?)]", problem)
|
||||||
|
if img_list:
|
||||||
|
for img in img_list:
|
||||||
|
problem = problem.replace(f'[CQ:image,file={img}]', f'[__placeholder_{idx}]', 1)
|
||||||
|
placeholder_list.append([idx, img])
|
||||||
|
idx += 1
|
||||||
|
if at_list:
|
||||||
|
for ats in at_list:
|
||||||
|
problem = problem.replace(f'[CQ:at,qq={ats}]', f'[__placeholder_{idx}]', 1)
|
||||||
|
placeholder_list.append([idx, ats])
|
||||||
|
idx += 1
|
||||||
|
_p = problem
|
||||||
|
problem = ''
|
||||||
|
if not placeholder_list:
|
||||||
|
problem = _p
|
||||||
|
return problem
|
||||||
|
else:
|
||||||
|
for idx, placeholder in placeholder_list:
|
||||||
|
if is_number(placeholder):
|
||||||
|
q = await GroupInfoUser.get_member_info(
|
||||||
|
int(placeholder), event.group_id)
|
||||||
|
problem += _p[: _p.find(f"[__placeholder_{idx}]")] + "@" + q.user_name
|
||||||
|
else:
|
||||||
|
problem += _p[: _p.find(f"[__placeholder_{idx}]")] + image(
|
||||||
|
path / f"{placeholder}.jpg"
|
||||||
|
)
|
||||||
|
_p = _p[_p.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):]
|
||||||
|
|
||||||
|
return problem + _p
|
||||||
|
|||||||
@@ -108,11 +108,6 @@ class WordBank(db.Model):
|
|||||||
:param group_id: 群号
|
:param group_id: 群号
|
||||||
:param problem: 问题
|
:param problem: 问题
|
||||||
"""
|
"""
|
||||||
if problem.startswith("id:"):
|
|
||||||
problem_index = int(problem.split(":")[-1])
|
|
||||||
q = await cls.get_group_all_problem(group_id)
|
|
||||||
if len(q) > problem_index:
|
|
||||||
problem = q[problem_index]
|
|
||||||
q = await cls.query.where(
|
q = await cls.query.where(
|
||||||
(cls.group_id == group_id) & (cls.problem == problem)
|
(cls.group_id == group_id) & (cls.problem == problem)
|
||||||
).gino.all()
|
).gino.all()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from utils.http_utils import AsyncHttpx
|
|||||||
from ._data_source import WordBankBuilder
|
from ._data_source import WordBankBuilder
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from utils.image_utils import text2image
|
from utils.image_utils import text2image
|
||||||
from .message_handle import get_one_answer
|
from .message_handle import get_one_answer, get_one_problem, get_one_image_problem
|
||||||
from .model import WordBank
|
from .model import WordBank
|
||||||
from nonebot.adapters.onebot.v11 import (
|
from nonebot.adapters.onebot.v11 import (
|
||||||
Bot,
|
Bot,
|
||||||
@@ -19,6 +19,7 @@ import random
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from configs.config import NICKNAME, Config
|
from configs.config import NICKNAME, Config
|
||||||
|
from models.group_member_info import GroupInfoUser
|
||||||
|
|
||||||
__zx_plugin_name__ = "词库问答 [Admin]"
|
__zx_plugin_name__ = "词库问答 [Admin]"
|
||||||
__plugin_usage__ = """
|
__plugin_usage__ = """
|
||||||
@@ -26,7 +27,7 @@ usage:
|
|||||||
对指定问题的随机回答,对相同问题可以设置多个不同回答
|
对指定问题的随机回答,对相同问题可以设置多个不同回答
|
||||||
删除词条后每个词条的id可能会变化,请查看后再删除
|
删除词条后每个词条的id可能会变化,请查看后再删除
|
||||||
指令:
|
指令:
|
||||||
添加词条 ?[模糊/关键字]...答...:添加问答词条,可重复添加相同问题的不同回答
|
添加词条 ?[模糊/关键字|词]...答...:添加问答词条,可重复添加相同问题的不同回答
|
||||||
删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答
|
删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答
|
||||||
修改词条 [问题/下标] ?[下标/新回答] [新回答]:修改指定词条指定回答默认修改为第一条
|
修改词条 [问题/下标] ?[下标/新回答] [新回答]:修改指定词条指定回答默认修改为第一条
|
||||||
查看词条 ?[问题/下标]:查看全部词条或对应词条回答
|
查看词条 ?[问题/下标]:查看全部词条或对应词条回答
|
||||||
@@ -48,8 +49,8 @@ __plugin_cmd__ = [
|
|||||||
"修改词条 [问题/下标] ?[下标/新回答] [新回答]",
|
"修改词条 [问题/下标] ?[下标/新回答] [新回答]",
|
||||||
"查看词条 ?[问题/下标]",
|
"查看词条 ?[问题/下标]",
|
||||||
]
|
]
|
||||||
__plugin_version__ = 0.2
|
__plugin_version__ = 0.3
|
||||||
__plugin_author__ = "HibiKier"
|
__plugin_author__ = "HibiKier & yajiwa"
|
||||||
__plugin_settings__ = {
|
__plugin_settings__ = {
|
||||||
"admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL [LEVEL]"),
|
"admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL [LEVEL]"),
|
||||||
"cmd": ["词库问答", "添加词条", "删除词条", "修改词条", "查看词条"],
|
"cmd": ["词库问答", "添加词条", "删除词条", "修改词条", "查看词条"],
|
||||||
@@ -87,21 +88,21 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = C
|
|||||||
else:
|
else:
|
||||||
_problem = problem
|
_problem = problem
|
||||||
search_type = 0
|
search_type = 0
|
||||||
if re.search("^关键字(.*)", msg):
|
if re.search("^关键字|词(.*)", msg):
|
||||||
search_type = 1
|
search_type = 1
|
||||||
elif re.search("^模糊(.*)", msg):
|
elif re.search("^模糊(.*)", msg):
|
||||||
search_type = 2
|
search_type = 2
|
||||||
_builder = await get__builder(event, _problem, answer, idx)
|
_builder = await get__builder(event, _problem, answer, idx)
|
||||||
if await _builder.save(search_type):
|
if await _builder.save(search_type):
|
||||||
logger.info(f"已保存词条 问:{problem} 答:{msg}")
|
logger.info(f"已保存词条 问:{_builder.problem} 答:{msg}")
|
||||||
await add_word.send(f"已保存词条:{problem}")
|
await add_word.send("已保存词条:" + _builder.problem)
|
||||||
else:
|
else:
|
||||||
await delete_word.send("保存失败,可能是回答重复")
|
await delete_word.send("保存失败,可能是回答重复")
|
||||||
|
|
||||||
|
|
||||||
@delete_word.handle()
|
@delete_word.handle()
|
||||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||||
msg = arg.extract_plain_text().strip()
|
msg = str(arg).strip()
|
||||||
if not msg:
|
if not msg:
|
||||||
await delete_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
|
await delete_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
|
||||||
index = None
|
index = None
|
||||||
@@ -119,17 +120,18 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
|||||||
if p:
|
if p:
|
||||||
problem = p[int(x)]
|
problem = p[int(x)]
|
||||||
try:
|
try:
|
||||||
|
_problem, problem = await get_one_problem(event, problem)
|
||||||
if answer := await WordBank.delete_problem_answer(
|
if answer := await WordBank.delete_problem_answer(
|
||||||
event.user_id, event.group_id, problem, index
|
event.user_id, event.group_id, _problem, index
|
||||||
):
|
):
|
||||||
await delete_word.send(f"删除词条成功:{problem}\n回答:\n{answer}")
|
await delete_word.send("删除词条成功:" + problem + f"\n回答:\n{answer}")
|
||||||
logger.info(
|
logger.info(
|
||||||
f"(USER {event.user_id}, GROUP "
|
f"(USER {event.user_id}, GROUP "
|
||||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
f" 删除词条: {problem}"
|
f" 删除词条: {problem}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await delete_word.send(f"删除词条:{problem} 失败,可能该词条不存在")
|
await delete_word.send("删除词条:" + problem + "失败,可能该词条不存在")
|
||||||
except IndexError:
|
except IndexError:
|
||||||
await delete_word.send("指定下标错误...请通过查看词条来确定..")
|
await delete_word.send("指定下标错误...请通过查看词条来确定..")
|
||||||
|
|
||||||
@@ -165,21 +167,21 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if await _builder.update(index):
|
if await _builder.update(index):
|
||||||
await update_word.send(f"修改词条成功:{problem}")
|
await update_word.send(f"修改词条成功:" + _builder.problem)
|
||||||
logger.info(
|
logger.info(
|
||||||
f"(USER {event.user_id}, GROUP "
|
f"(USER {event.user_id}, GROUP "
|
||||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
f" 修改词条: {problem}"
|
f" 修改词条: {problem}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await update_word.send(f"修改词条:{problem} 失败,可能该词条不存在")
|
await update_word.send(f"修改词条:" + _builder.problem + f"失败,可能该词条不存在")
|
||||||
except IndexError:
|
except IndexError:
|
||||||
await update_word.send("指定下标错误...请通过查看词条来确定..")
|
await update_word.send("指定下标错误...请通过查看词条来确定..")
|
||||||
|
|
||||||
|
|
||||||
@show_word.handle()
|
@show_word.handle()
|
||||||
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||||
msg = arg.extract_plain_text().strip()
|
msg = str(arg).strip()
|
||||||
if not msg:
|
if not msg:
|
||||||
_problem_list = await WordBank.get_group_all_problem(event.group_id)
|
_problem_list = await WordBank.get_group_all_problem(event.group_id)
|
||||||
if not _problem_list:
|
if not _problem_list:
|
||||||
@@ -225,17 +227,28 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
_answer_list = await WordBank.get_group_all_answer(event.group_id, msg)
|
_answer_list = []
|
||||||
|
if msg.startswith("id:"):
|
||||||
|
x = msg.split(":")[-1]
|
||||||
|
if not is_number(x) or int(x) < 0:
|
||||||
|
return await delete_word.finish("id必须为数字且符合规范!")
|
||||||
|
p = await WordBank.get_group_all_problem(event.group_id)
|
||||||
|
if p:
|
||||||
|
_problem = p[int(x)]
|
||||||
|
_answer_list = await WordBank.get_group_all_answer(event.group_id, _problem)
|
||||||
|
msg += '问' + await get_one_image_problem(event, _problem)
|
||||||
|
else:
|
||||||
|
_problem, msg = await get_one_problem(event, msg)
|
||||||
|
_answer_list = await WordBank.get_group_all_answer(event.group_id, _problem)
|
||||||
if not _answer_list:
|
if not _answer_list:
|
||||||
await show_word.send("未收录该词条...")
|
await show_word.send("未收录该词条...")
|
||||||
|
|
||||||
else:
|
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, 0) for answer, format in _answer_list]
|
||||||
word_nu = len(_answer_img_nu_list)
|
word_nu = len(_answer_img_nu_list)
|
||||||
img_nu = 0
|
img_nu = 0
|
||||||
answer = f"词条 {msg} 回答:"
|
answer = "词条" + msg + "回答:"
|
||||||
for i, x, in enumerate(_answer_img_nu_list):
|
for i, x, in enumerate(_answer_img_nu_list):
|
||||||
r = re.findall(rf"\[CQ:image,file=", str(x))
|
r = re.findall(rf"\[CQ:image,file=", str(x))
|
||||||
if r:
|
if r:
|
||||||
@@ -254,15 +267,25 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
|||||||
|
|
||||||
async def get__builder(event, _problem, answer, idx):
|
async def get__builder(event, _problem, answer, idx):
|
||||||
(data_dir / f"{event.group_id}").mkdir(exist_ok=True, parents=True)
|
(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)
|
_builder = WordBankBuilder(event.user_id, event.group_id, _problem)
|
||||||
|
problem = ''
|
||||||
|
_p = _problem
|
||||||
for at_ in get_message_at(event.json()):
|
for at_ in get_message_at(event.json()):
|
||||||
r = re.search(rf"\[CQ:at,qq={at_}]", answer)
|
r = re.search(rf"\[CQ:at,qq={at_}]", answer)
|
||||||
if r:
|
if r:
|
||||||
answer = answer.replace(f"[CQ:at,qq={at_}]", f"[__placeholder_{idx}]", 1)
|
answer = answer.replace(f"[CQ:at,qq={at_}]", f"[__placeholder_{idx}]", 1)
|
||||||
_builder.set_placeholder(idx, at_)
|
_builder.set_placeholder(idx, at_)
|
||||||
idx += 1
|
idx += 1
|
||||||
|
r_problem = re.search(rf"\[CQ:at,qq={at_}]", _problem)
|
||||||
|
if r_problem:
|
||||||
|
q = await GroupInfoUser.get_member_info(
|
||||||
|
int(at_), event.group_id)
|
||||||
|
problem += _p[: _p.find(f"[CQ:at,qq={at_}]")] + "@" + q.user_name
|
||||||
|
_p = _p[_p.find(f"[CQ:at,qq={at_}]") + len(f"[CQ:at,qq={at_}]"):]
|
||||||
for img in get_message_img(event.json()):
|
for img in get_message_img(event.json()):
|
||||||
_x = img.split("?")[0]
|
_x = img.split("?")[0]
|
||||||
|
_x_list = img.split("?")
|
||||||
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", answer)
|
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", answer)
|
||||||
if r:
|
if r:
|
||||||
rand = random.randint(1, 10000) + random.randint(1, 114514)
|
rand = random.randint(1, 10000) + random.randint(1, 114514)
|
||||||
@@ -270,16 +293,26 @@ async def get__builder(event, _problem, answer, idx):
|
|||||||
if f"__placeholder_{rand}_{idx}.jpg" not in os.listdir(data_dir / f"{event.group_id}"):
|
if f"__placeholder_{rand}_{idx}.jpg" not in os.listdir(data_dir / f"{event.group_id}"):
|
||||||
break
|
break
|
||||||
rand = random.randint(1, 10000) + random.randint(1, 114514)
|
rand = random.randint(1, 10000) + random.randint(1, 114514)
|
||||||
for i in range(3):
|
strinfo = re.compile(f"\[CQ:image,file={r.group(1)},url={_x_list[0]}\?{_x_list[1]},subType=\d*?]")
|
||||||
answer = answer.replace(f",subType={i}", "")
|
answer = strinfo.sub(f"[__placeholder_{idx}]", answer)
|
||||||
answer = answer.replace(
|
|
||||||
rf"[CQ:image,file={r.group(1)},url={img}]",
|
|
||||||
f"[__placeholder_{idx}]",
|
|
||||||
)
|
|
||||||
await AsyncHttpx.download_file(
|
await AsyncHttpx.download_file(
|
||||||
img, data_dir / f"{event.group_id}" / f"__placeholder_{rand}_{idx}.jpg"
|
img, data_dir / f"{event.group_id}" / f"__placeholder_{rand}_{idx}.jpg"
|
||||||
)
|
)
|
||||||
_builder.set_placeholder(idx, f"__placeholder_{rand}_{idx}.jpg")
|
_builder.set_placeholder(idx, f"__placeholder_{rand}_{idx}.jpg")
|
||||||
idx += 1
|
idx += 1
|
||||||
|
r_problem = re.search(rf"\[CQ:image,file=(.*?),url={_x}.*?]", _p)
|
||||||
|
if r_problem:
|
||||||
|
strinfo = re.compile(f",url={_x_list[0]}\?{_x_list[1]},subType=\d*?]")
|
||||||
|
_problem = strinfo.sub(f"]", _problem)
|
||||||
|
_p = strinfo.sub(f"]", _p)
|
||||||
|
problem += _p[: _p.find(f"[CQ:image,file={r_problem.group(1)}]")] + image(img)
|
||||||
|
_p = _p[_p.find(f"[CQ:image,file={r_problem.group(1)}]") + len(f"[CQ:image,file={r_problem.group(1)}]"):]
|
||||||
|
problem_img = r_problem.group(1)
|
||||||
|
if f"{problem_img}.jpg" not in os.listdir(data_dir / f"{event.group_id}" / f"problem"):
|
||||||
|
await AsyncHttpx.download_file(
|
||||||
|
img, data_dir / f"{event.group_id}" / f"problem" / f"{problem_img}.jpg"
|
||||||
|
)
|
||||||
_builder.set_answer(answer)
|
_builder.set_answer(answer)
|
||||||
|
_builder.set_problem(_problem)
|
||||||
|
_builder.problem = problem + _p
|
||||||
return _builder
|
return _builder
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
import re
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import Tuple, Union
|
||||||
|
import pytz
|
||||||
|
from nonebot import on_command, get_driver
|
||||||
|
from nonebot.adapters.onebot.v11 import Message, MessageSegment
|
||||||
|
from nonebot.adapters.onebot.v11.event import GroupMessageEvent
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import Arg, Command, CommandArg, Depends
|
||||||
|
from nonebot.typing import T_State
|
||||||
|
from .data_source import draw_word_cloud, get_list_msg
|
||||||
|
from configs.config import Config
|
||||||
|
|
||||||
|
__zx_plugin_name__ = "词云"
|
||||||
|
|
||||||
|
__plugin_usage__ = """
|
||||||
|
usage:
|
||||||
|
词云
|
||||||
|
指令:
|
||||||
|
今日词云:获取今天的词云
|
||||||
|
昨日词云:获取昨天的词云
|
||||||
|
本周词云:获取本周词云
|
||||||
|
本月词云:获取本月词云
|
||||||
|
年度词云:获取年度词云
|
||||||
|
|
||||||
|
历史词云(支持 ISO8601 格式的日期与时间,如 2022-02-22T22:22:22)
|
||||||
|
获取某日的词云
|
||||||
|
历史词云 2022-01-01
|
||||||
|
获取指定时间段的词云
|
||||||
|
历史词云
|
||||||
|
示例:历史词云 2022-01-01~2022-02-22
|
||||||
|
示例:历史词云 2022-02-22T11:11:11~2022-02-22T22:22:22
|
||||||
|
|
||||||
|
如果想要获取自己的发言,可在命令前添加 我的
|
||||||
|
示例:我的今日词云
|
||||||
|
""".strip()
|
||||||
|
__plugin_des__ = "词云"
|
||||||
|
__plugin_cmd__ = ["今日词云", "昨日词云", "本周词云"]
|
||||||
|
__plugin_version__ = 0.1
|
||||||
|
__plugin_author__ = "yajiwa"
|
||||||
|
__plugin_settings__ = {
|
||||||
|
"level": 5,
|
||||||
|
"default_status": True,
|
||||||
|
"limit_superuser": False,
|
||||||
|
"cmd": __plugin_cmd__,
|
||||||
|
}
|
||||||
|
wordcloud_cmd = on_command(
|
||||||
|
"wordcloud",
|
||||||
|
aliases={
|
||||||
|
"词云",
|
||||||
|
"今日词云",
|
||||||
|
"昨日词云",
|
||||||
|
"本周词云",
|
||||||
|
"本月词云",
|
||||||
|
"年度词云",
|
||||||
|
"历史词云",
|
||||||
|
"我的今日词云",
|
||||||
|
"我的昨日词云",
|
||||||
|
"我的本周词云",
|
||||||
|
"我的本月词云",
|
||||||
|
"我的年度词云",
|
||||||
|
"我的历史词云",
|
||||||
|
}, block=True, priority=5
|
||||||
|
)
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"word_clouds",
|
||||||
|
"WORD_CLOUDS_TEMPLATE",
|
||||||
|
1,
|
||||||
|
help_="词云模板 参1:图片生成,默认使用真寻图片,可在项目路径resources/image/wordcloud下配置图片,多张则随机 | 参2/其他:黑底图片"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_datetime(key: str):
|
||||||
|
"""解析数字,并将结果存入 state 中"""
|
||||||
|
|
||||||
|
async def _key_parser(
|
||||||
|
matcher: Matcher,
|
||||||
|
state: T_State,
|
||||||
|
input_: Union[datetime, Message] = Arg(key),
|
||||||
|
):
|
||||||
|
if isinstance(input_, datetime):
|
||||||
|
return
|
||||||
|
|
||||||
|
plaintext = input_.extract_plain_text()
|
||||||
|
try:
|
||||||
|
state[key] = get_datetime_fromisoformat_with_timezone(plaintext)
|
||||||
|
except ValueError:
|
||||||
|
await matcher.reject_arg(key, "请输入正确的日期,不然我没法理解呢!")
|
||||||
|
|
||||||
|
return _key_parser
|
||||||
|
|
||||||
|
|
||||||
|
def get_datetime_now_with_timezone() -> datetime:
|
||||||
|
"""获取当前时间,并包含时区信息"""
|
||||||
|
return datetime.now().astimezone()
|
||||||
|
|
||||||
|
|
||||||
|
def get_datetime_fromisoformat_with_timezone(date_string: str) -> datetime:
|
||||||
|
"""从 iso8601 格式字符串中获取时间,并包含时区信息"""
|
||||||
|
return datetime.fromisoformat(date_string).astimezone()
|
||||||
|
|
||||||
|
|
||||||
|
@wordcloud_cmd.handle()
|
||||||
|
async def handle_first_receive(
|
||||||
|
event: GroupMessageEvent,
|
||||||
|
state: T_State,
|
||||||
|
commands: Tuple[str, ...] = Command(),
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
|
command = commands[0]
|
||||||
|
|
||||||
|
if command.startswith("我的"):
|
||||||
|
state["my"] = True
|
||||||
|
command = command[2:]
|
||||||
|
else:
|
||||||
|
state["my"] = False
|
||||||
|
|
||||||
|
if command == "今日词云":
|
||||||
|
dt = get_datetime_now_with_timezone()
|
||||||
|
state["start"] = dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
state["stop"] = dt
|
||||||
|
elif command == "昨日词云":
|
||||||
|
dt = get_datetime_now_with_timezone()
|
||||||
|
state["stop"] = dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
state["start"] = state["stop"] - timedelta(days=1)
|
||||||
|
elif command == "本周词云":
|
||||||
|
dt = get_datetime_now_with_timezone()
|
||||||
|
state["start"] = dt.replace(
|
||||||
|
hour=0, minute=0, second=0, microsecond=0
|
||||||
|
) - timedelta(days=dt.weekday())
|
||||||
|
state["stop"] = dt
|
||||||
|
elif command == "本月词云":
|
||||||
|
dt = get_datetime_now_with_timezone()
|
||||||
|
state["start"] = dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
state["stop"] = dt
|
||||||
|
elif command == "年度词云":
|
||||||
|
dt = get_datetime_now_with_timezone()
|
||||||
|
state["start"] = dt.replace(
|
||||||
|
month=1, day=1, hour=0, minute=0, second=0, microsecond=0
|
||||||
|
)
|
||||||
|
state["stop"] = dt
|
||||||
|
elif command == "历史词云":
|
||||||
|
plaintext = args.extract_plain_text().strip()
|
||||||
|
match = re.match(r"^(.+?)(?:~(.+))?$", plaintext)
|
||||||
|
if match:
|
||||||
|
start = match.group(1)
|
||||||
|
stop = match.group(2)
|
||||||
|
try:
|
||||||
|
state["start"] = get_datetime_fromisoformat_with_timezone(start)
|
||||||
|
if stop:
|
||||||
|
state["stop"] = get_datetime_fromisoformat_with_timezone(stop)
|
||||||
|
else:
|
||||||
|
# 如果没有指定结束日期,则认为是指查询这一天的词云
|
||||||
|
state["start"] = state["start"].replace(
|
||||||
|
hour=0, minute=0, second=0, microsecond=0
|
||||||
|
)
|
||||||
|
state["stop"] = state["start"] + timedelta(days=1)
|
||||||
|
except ValueError:
|
||||||
|
await wordcloud_cmd.finish("请输入正确的日期,不然我没法理解呢!")
|
||||||
|
else:
|
||||||
|
await wordcloud_cmd.finish()
|
||||||
|
|
||||||
|
|
||||||
|
@wordcloud_cmd.got(
|
||||||
|
"start",
|
||||||
|
prompt="请输入你要查询的起始日期(如 2022-01-01)",
|
||||||
|
parameterless=[Depends(parse_datetime("start"))],
|
||||||
|
)
|
||||||
|
@wordcloud_cmd.got(
|
||||||
|
"stop",
|
||||||
|
prompt="请输入你要查询的结束日期(如 2022-02-22)",
|
||||||
|
parameterless=[Depends(parse_datetime("stop"))],
|
||||||
|
)
|
||||||
|
async def handle_message(
|
||||||
|
event: GroupMessageEvent,
|
||||||
|
start: datetime = Arg(),
|
||||||
|
stop: datetime = Arg(),
|
||||||
|
my: bool = Arg(),
|
||||||
|
):
|
||||||
|
# 是否只查询自己的记录
|
||||||
|
if my:
|
||||||
|
user_id = int(event.user_id)
|
||||||
|
else:
|
||||||
|
user_id = None
|
||||||
|
# 将时间转换到 东八 时区
|
||||||
|
messages = await get_list_msg(user_id, int(event.group_id),
|
||||||
|
days=(start.astimezone(pytz.timezone("Asia/Shanghai")),
|
||||||
|
stop.astimezone(pytz.timezone("Asia/Shanghai"))))
|
||||||
|
if messages:
|
||||||
|
image_bytes = await draw_word_cloud(messages, get_driver().config)
|
||||||
|
if image_bytes:
|
||||||
|
await wordcloud_cmd.finish(MessageSegment.image(image_bytes), at_sender=my)
|
||||||
|
else:
|
||||||
|
await wordcloud_cmd.finish("生成词云失败", at_sender=my)
|
||||||
|
else:
|
||||||
|
await wordcloud_cmd.finish("没有获取到词云数据", at_sender=my)
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import jieba.analyse
|
||||||
|
import re
|
||||||
|
from typing import List
|
||||||
|
from PIL import Image as IMG
|
||||||
|
import jieba
|
||||||
|
from emoji import replace_emoji # type: ignore
|
||||||
|
from wordcloud import WordCloud, ImageColorGenerator
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from io import BytesIO
|
||||||
|
from configs.path_config import IMAGE_PATH, FONT_PATH
|
||||||
|
from services import logger
|
||||||
|
from utils.http_utils import AsyncHttpx
|
||||||
|
from models.chat_history import ChatHistory
|
||||||
|
from configs.config import Config
|
||||||
|
|
||||||
|
|
||||||
|
async def pre_precess(msg: List[str], config) -> str:
|
||||||
|
return await asyncio.get_event_loop().run_in_executor(
|
||||||
|
None, _pre_precess, msg, config
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _pre_precess(msg: List[str], config) -> str:
|
||||||
|
"""对消息进行预处理"""
|
||||||
|
# 过滤掉命令
|
||||||
|
command_start = tuple([i for i in config.command_start if i])
|
||||||
|
msg = " ".join([m for m in msg if not m.startswith(command_start)])
|
||||||
|
|
||||||
|
# 去除网址
|
||||||
|
msg = re.sub(r"https?://[\w/:%#\$&\?\(\)~\.=\+\-]+", "", msg)
|
||||||
|
|
||||||
|
# 去除 \u200b
|
||||||
|
msg = re.sub(r"[\u200b]", "", msg)
|
||||||
|
|
||||||
|
# 去除cq码
|
||||||
|
msg = re.sub(r"\[CQ:.*?]", "", msg)
|
||||||
|
|
||||||
|
# 去除[]
|
||||||
|
msg = re.sub("[	(1|3);]", "", msg)
|
||||||
|
|
||||||
|
# 去除 emoji
|
||||||
|
# https://github.com/carpedm20/emoji
|
||||||
|
msg = replace_emoji(msg)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
async def draw_word_cloud(messages, config):
|
||||||
|
wordcloud_dir = IMAGE_PATH / "wordcloud"
|
||||||
|
wordcloud_dir.mkdir(exist_ok=True, parents=True)
|
||||||
|
# 默认用真寻图片
|
||||||
|
zx_logo_path = wordcloud_dir / "default.png"
|
||||||
|
wordcloud_ttf = FONT_PATH / "STKAITI.TTF"
|
||||||
|
if not os.listdir(wordcloud_dir):
|
||||||
|
url = "https://ghproxy.com/https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/resources/image/wordcloud/default.png"
|
||||||
|
try:
|
||||||
|
await AsyncHttpx.download_file(url, zx_logo_path)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"词云图片资源下载发生错误 {type(e)}:{e}")
|
||||||
|
return False
|
||||||
|
if not wordcloud_ttf.exists():
|
||||||
|
ttf_url = "https://ghproxy.com/https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/resources/font/STKAITI.TTF"
|
||||||
|
try:
|
||||||
|
await AsyncHttpx.download_file(ttf_url, wordcloud_ttf)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"词云字体资源下载发生错误 {type(e)}:{e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
topK = min(int(len(messages)), 100000)
|
||||||
|
read_name = jieba.analyse.extract_tags(
|
||||||
|
await pre_precess(messages, config), topK=topK, withWeight=True, allowPOS=()
|
||||||
|
)
|
||||||
|
name = []
|
||||||
|
value = []
|
||||||
|
for t in read_name:
|
||||||
|
name.append(t[0])
|
||||||
|
value.append(t[1])
|
||||||
|
for i in range(len(name)):
|
||||||
|
name[i] = str(name[i])
|
||||||
|
dic = dict(zip(name, value))
|
||||||
|
if Config.get_config("word_clouds", "WORD_CLOUDS_TEMPLATE") == 1:
|
||||||
|
|
||||||
|
def random_pic(base_path: str) -> str:
|
||||||
|
path_dir = os.listdir(base_path)
|
||||||
|
path = random.sample(path_dir, 1)[0]
|
||||||
|
return str(base_path) + "/" + str(path)
|
||||||
|
|
||||||
|
mask = np.array(IMG.open(random_pic(wordcloud_dir)))
|
||||||
|
wc = WordCloud(
|
||||||
|
font_path=f"{wordcloud_ttf}",
|
||||||
|
background_color="white",
|
||||||
|
max_font_size=100,
|
||||||
|
width=1920,
|
||||||
|
height=1080,
|
||||||
|
mask=mask,
|
||||||
|
)
|
||||||
|
wc.generate_from_frequencies(dic)
|
||||||
|
image_colors = ImageColorGenerator(mask, default_color=(255, 255, 255))
|
||||||
|
wc.recolor(color_func=image_colors)
|
||||||
|
plt.imshow(wc.recolor(color_func=image_colors), interpolation="bilinear")
|
||||||
|
plt.axis("off")
|
||||||
|
else:
|
||||||
|
wc = WordCloud(
|
||||||
|
font_path=str(wordcloud_ttf),
|
||||||
|
width=1920,
|
||||||
|
height=1200,
|
||||||
|
background_color="black",
|
||||||
|
)
|
||||||
|
wc.generate_from_frequencies(dic)
|
||||||
|
bytes_io = BytesIO()
|
||||||
|
img = wc.to_image()
|
||||||
|
img.save(bytes_io, format="PNG")
|
||||||
|
return bytes_io.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
async def get_list_msg(user_id, group_id, days):
|
||||||
|
messages_list = (
|
||||||
|
await ChatHistory()
|
||||||
|
._get_msg(uid=user_id, gid=group_id, type_="group", days=days)
|
||||||
|
.gino.all()
|
||||||
|
)
|
||||||
|
if messages_list:
|
||||||
|
messages = [i.text for i in messages_list]
|
||||||
|
return messages
|
||||||
|
else:
|
||||||
|
return False
|
||||||
@@ -11,7 +11,7 @@ china_city = TEXT_PATH / "china_city.json"
|
|||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
|
|
||||||
url = "https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5"
|
url = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=diseaseh5Shelf"
|
||||||
|
|
||||||
|
|
||||||
async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
|
async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
|
||||||
@@ -37,7 +37,7 @@ async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
|
|||||||
if area in data[p]:
|
if area in data[p]:
|
||||||
province = p
|
province = p
|
||||||
city = area
|
city = area
|
||||||
epidemic_data = json.loads((await AsyncHttpx.get(url)).json()["data"])
|
epidemic_data = (await AsyncHttpx.get(url)).json()["data"]["diseaseh5Shelf"]
|
||||||
last_update_time = epidemic_data["lastUpdateTime"]
|
last_update_time = epidemic_data["lastUpdateTime"]
|
||||||
if area == "中国":
|
if area == "中国":
|
||||||
data_ = epidemic_data["areaTree"][0]
|
data_ = epidemic_data["areaTree"][0]
|
||||||
@@ -59,12 +59,12 @@ async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
|
|||||||
add_confirm = data_["today"]["confirm"] # 新增确诊
|
add_confirm = data_["today"]["confirm"] # 新增确诊
|
||||||
grade = ""
|
grade = ""
|
||||||
_grade_color = ""
|
_grade_color = ""
|
||||||
if data_["total"].get("grade"):
|
# if data_["total"].get("grade"):
|
||||||
grade = data_["total"]["grade"]
|
# grade = data_["total"]["grade"]
|
||||||
if "中风险" in grade:
|
# if "中风险" in grade:
|
||||||
_grade_color = "#fa9424"
|
# _grade_color = "#fa9424"
|
||||||
else:
|
# else:
|
||||||
_grade_color = "red"
|
# _grade_color = "red"
|
||||||
|
|
||||||
dead_rate = f"{dead / confirm * 100:.2f}" # 死亡率
|
dead_rate = f"{dead / confirm * 100:.2f}" # 死亡率
|
||||||
heal_rate = f"{heal / confirm * 100:.2f}" # 治愈率
|
heal_rate = f"{heal / confirm * 100:.2f}" # 治愈率
|
||||||
|
|||||||
Generated
+630
-1082
File diff suppressed because it is too large
Load Diff
+6
-3
@@ -6,15 +6,14 @@ authors = ["HibiKier <775757368@qq.com>"]
|
|||||||
license = "AGPL"
|
license = "AGPL"
|
||||||
|
|
||||||
[[tool.poetry.source]]
|
[[tool.poetry.source]]
|
||||||
name = "tsinghua"
|
name = "ali"
|
||||||
default = true
|
default = true
|
||||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
url = "https://mirrors.aliyun.com/pypi/simple/"
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.8"
|
python = "^3.8"
|
||||||
nonebot2 = "^2.0.0-beta.2"
|
nonebot2 = "^2.0.0-beta.2"
|
||||||
nonebot-adapter-onebot = "^2.0.0-beta.1"
|
nonebot-adapter-onebot = "^2.0.0-beta.1"
|
||||||
bilibili-api = "^9.1.0"
|
|
||||||
aiofiles = "^0.8.0"
|
aiofiles = "^0.8.0"
|
||||||
aiohttp = "3.7.4.post0"
|
aiohttp = "3.7.4.post0"
|
||||||
beautifulsoup4 = "4.9.3"
|
beautifulsoup4 = "4.9.3"
|
||||||
@@ -40,6 +39,10 @@ dateparser = "^1.1.0"
|
|||||||
cn2an = "^0.5.16"
|
cn2an = "^0.5.16"
|
||||||
python-jose = "^3.3.0"
|
python-jose = "^3.3.0"
|
||||||
python-multipart = "^0.0.5"
|
python-multipart = "^0.0.5"
|
||||||
|
bilireq = "^0.1.2"
|
||||||
|
emoji = "^1.7.0"
|
||||||
|
wordcloud = "^1.8.1"
|
||||||
|
rich = "^12.4.3"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 728 KiB |
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
from gino import Gino
|
from gino import Gino
|
||||||
from .log import logger
|
from .log import logger
|
||||||
|
from utils.text_utils import prompt2cn
|
||||||
from configs.config import bind, sql_name, user, password, address, port, database
|
from configs.config import bind, sql_name, user, password, address, port, database
|
||||||
|
|
||||||
|
|
||||||
@@ -9,6 +10,8 @@ db = Gino()
|
|||||||
|
|
||||||
|
|
||||||
async def init():
|
async def init():
|
||||||
|
if not bind and (not user and not password and not address and not port and not database):
|
||||||
|
raise ValueError("\n" + prompt2cn("数据库配置未填写", 28))
|
||||||
i_bind = bind
|
i_bind = bind
|
||||||
if not i_bind:
|
if not i_bind:
|
||||||
i_bind = f"{sql_name}://{user}:{password}@{address}:{port}/{database}"
|
i_bind = f"{sql_name}://{user}:{password}@{address}:{port}/{database}"
|
||||||
|
|||||||
+2
-1
@@ -9,7 +9,8 @@
|
|||||||
"configs/utils",
|
"configs/utils",
|
||||||
"poetry.lock",
|
"poetry.lock",
|
||||||
"pyproject.toml",
|
"pyproject.toml",
|
||||||
"resources/font"
|
"resources/font",
|
||||||
|
"bot.py"
|
||||||
],
|
],
|
||||||
"add_file": [],
|
"add_file": [],
|
||||||
"delete_file": []
|
"delete_file": []
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ _browser: Optional[Browser] = None
|
|||||||
|
|
||||||
async def init(**kwargs) -> Optional[Browser]:
|
async def init(**kwargs) -> Optional[Browser]:
|
||||||
global _browser
|
global _browser
|
||||||
if platform.system() == "Windows":
|
|
||||||
return None
|
|
||||||
try:
|
try:
|
||||||
browser = await async_playwright().start()
|
browser = await async_playwright().start()
|
||||||
_browser = await browser.chromium.launch(**kwargs)
|
_browser = await browser.chromium.launch(**kwargs)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+22
-6
@@ -17,13 +17,15 @@ class ShopRegister(dict):
|
|||||||
name: Tuple[str, ...],
|
name: Tuple[str, ...],
|
||||||
price: Tuple[float, ...],
|
price: Tuple[float, ...],
|
||||||
des: Tuple[str, ...],
|
des: Tuple[str, ...],
|
||||||
|
discount: Tuple[float, ...],
|
||||||
|
limit_time: Tuple[int, ...],
|
||||||
load_status: Tuple[bool, ...],
|
load_status: Tuple[bool, ...],
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
def add_register_item(func: Callable):
|
def add_register_item(func: Callable):
|
||||||
if name in self._data.keys():
|
if name in self._data.keys():
|
||||||
raise ValueError("该商品已注册,请替换其他名称!")
|
raise ValueError("该商品已注册,请替换其他名称!")
|
||||||
for n, p, d, s in zip(name, price, des, load_status):
|
for n, p, d, dd, l, s in zip(name, price, des, discount, limit_time, load_status):
|
||||||
if s:
|
if s:
|
||||||
_temp_kwargs = {}
|
_temp_kwargs = {}
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
@@ -32,6 +34,8 @@ class ShopRegister(dict):
|
|||||||
self._data[n] = {
|
self._data[n] = {
|
||||||
"price": p,
|
"price": p,
|
||||||
"des": d,
|
"des": d,
|
||||||
|
"discount": dd,
|
||||||
|
"limit_time": l,
|
||||||
"func": func,
|
"func": func,
|
||||||
"kwargs": _temp_kwargs,
|
"kwargs": _temp_kwargs,
|
||||||
}
|
}
|
||||||
@@ -46,7 +50,7 @@ class ShopRegister(dict):
|
|||||||
self._flag = False
|
self._flag = False
|
||||||
for name in self._data.keys():
|
for name in self._data.keys():
|
||||||
await shop.register_goods(
|
await shop.register_goods(
|
||||||
name, self._data[name]["price"], self._data[name]["des"]
|
name, self._data[name]["price"], self._data[name]["des"], self._data[name]["discount"], self._data[name]["limit_time"]
|
||||||
)
|
)
|
||||||
use.register_use(
|
use.register_use(
|
||||||
name, self._data[name]["func"], **self._data[name]["kwargs"]
|
name, self._data[name]["func"], **self._data[name]["kwargs"]
|
||||||
@@ -57,24 +61,36 @@ class ShopRegister(dict):
|
|||||||
name: Union[str, Tuple[str, ...]],
|
name: Union[str, Tuple[str, ...]],
|
||||||
price: Union[float, Tuple[float, ...]],
|
price: Union[float, Tuple[float, ...]],
|
||||||
des: Union[str, Tuple[str, ...]],
|
des: Union[str, Tuple[str, ...]],
|
||||||
|
discount: Union[float, Tuple[float, ...]] = 1,
|
||||||
|
limit_time: Union[int, Tuple[int, ...]] = 0,
|
||||||
load_status: Union[bool, Tuple[bool, ...]] = True,
|
load_status: Union[bool, Tuple[bool, ...]] = True,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
_tuple_list = []
|
_tuple_list = []
|
||||||
_current_len = -1
|
_current_len = -1
|
||||||
for x in [name, price, des, load_status]:
|
for x in [name, price, des, discount, limit_time, load_status]:
|
||||||
if isinstance(x, tuple):
|
if isinstance(x, tuple):
|
||||||
if _current_len == -1:
|
if _current_len == -1:
|
||||||
_current_len = len(x)
|
_current_len = len(x)
|
||||||
if _current_len != len(x):
|
if _current_len != len(x):
|
||||||
raise ValueError(f"注册商品 {name} 中 name,price,des,load_status 数量不符!")
|
raise ValueError(f"注册商品 {name} 中 name,price,des,discount,limit_time,load_status 数量不符!")
|
||||||
_current_len = _current_len if _current_len > -1 else 1
|
_current_len = _current_len if _current_len > -1 else 1
|
||||||
_name = name if isinstance(name, tuple) else tuple(name)
|
_name = name if isinstance(name, tuple) else (name,)
|
||||||
_price = (
|
_price = (
|
||||||
price
|
price
|
||||||
if isinstance(price, tuple)
|
if isinstance(price, tuple)
|
||||||
else tuple([price for _ in range(_current_len)])
|
else tuple([price for _ in range(_current_len)])
|
||||||
)
|
)
|
||||||
|
_discount = (
|
||||||
|
discount
|
||||||
|
if isinstance(discount, tuple)
|
||||||
|
else tuple([discount for _ in range(_current_len)])
|
||||||
|
)
|
||||||
|
_limit_time = (
|
||||||
|
limit_time
|
||||||
|
if isinstance(limit_time, tuple)
|
||||||
|
else tuple([limit_time for _ in range(_current_len)])
|
||||||
|
)
|
||||||
_des = (
|
_des = (
|
||||||
des if isinstance(des, tuple) else tuple([des for _ in range(_current_len)])
|
des if isinstance(des, tuple) else tuple([des for _ in range(_current_len)])
|
||||||
)
|
)
|
||||||
@@ -83,7 +99,7 @@ class ShopRegister(dict):
|
|||||||
if isinstance(load_status, tuple)
|
if isinstance(load_status, tuple)
|
||||||
else tuple([load_status for _ in range(_current_len)])
|
else tuple([load_status for _ in range(_current_len)])
|
||||||
)
|
)
|
||||||
return self.register(_name, _price, _des, _load_status, **kwargs)
|
return self.register(_name, _price, _des, _discount, _limit_time, _load_status, **kwargs)
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
self._data[key] = value
|
self._data[key] = value
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user