mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-09-29 16:50:02 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ce4537605 | ||
|
|
701812ed9d | ||
|
|
8d9e81827b | ||
|
|
f51a2816b4 | ||
|
|
3d4a7950c5 | ||
|
|
ba6668f144 | ||
|
|
e1f7a77d15 | ||
|
|
64e2c512d3 | ||
|
|
6082e68a1f | ||
|
|
f135d48e55 | ||
|
|
751fc8fdb4 | ||
|
|
df73e79ee4 | ||
|
|
fa6cfdb609 | ||
|
|
b057a05520 | ||
|
|
cb0938721c | ||
|
|
4f3f8de734 | ||
|
|
5ba303aada | ||
|
|
bd42fefe4e | ||
|
|
d24c081973 | ||
|
|
1b9eddd905 | ||
|
|
0bfe398dc4 | ||
|
|
e9216a472f | ||
|
|
8b93ec0df6 | ||
|
|
7497706a0d | ||
|
|
6e41cb0630 | ||
|
|
62d99e7e90 | ||
|
|
43cddb3580 | ||
|
|
c9c1beda75 | ||
|
|
3ee9ae5fb8 | ||
|
|
ea6344fae1 | ||
|
|
6f54e91f5c | ||
|
|
27fb3aaa19 | ||
|
|
86d736745d | ||
|
|
821fe21c2b | ||
|
|
7f4aa518dc | ||
|
|
8cf589e433 | ||
|
|
105a29cd70 | ||
|
|
cb6a5e81e7 | ||
|
|
9c073383ad | ||
|
|
5e0756825d | ||
|
|
933523ae6d | ||
|
|
ed6b05605c | ||
|
|
71a9c34620 | ||
|
|
e29f2cb920 | ||
|
|
d47dd88d6c | ||
|
|
fb34bbce7a | ||
|
|
100236da83 | ||
|
|
a45a3002d5 | ||
|
|
9214a4c978 | ||
|
|
70761dc222 | ||
|
|
32e8136f71 | ||
|
|
8b20d99b2c | ||
|
|
1174b5cc7f | ||
|
|
ec448cfdfb | ||
|
|
f3e44b1baf | ||
|
|
0ea740aa7c | ||
|
|
5f118471cb | ||
|
|
504f78dd49 | ||
|
|
72723c7d1f | ||
|
|
6a74053853 | ||
|
|
af0b4987a4 | ||
|
|
775140cf79 | ||
|
|
6a8a796add | ||
|
|
8e4bda3760 | ||
|
|
a36e8145a8 | ||
|
|
3cbd899daa | ||
|
|
30f356a2c7 | ||
|
|
1138a115ce | ||
|
|
c397da75e7 | ||
|
|
1d141c9313 | ||
|
|
a4cc365af8 | ||
|
|
4e551bec0d | ||
|
|
e03086062d | ||
|
|
270a5a5e20 | ||
|
|
bda9133ed6 | ||
|
|
749f475f2c | ||
|
|
e38394948c | ||
|
|
51fc4cbb6a | ||
|
|
9a976cda37 | ||
|
|
e42521f0a3 | ||
|
|
0756d39ac5 | ||
|
|
4595bdcee4 | ||
|
|
38160065cc | ||
|
|
3d04f013cd | ||
|
|
8e1a416be3 | ||
|
|
a98bc42f1a | ||
|
|
6c93769838 | ||
|
|
d2dccfebc5 | ||
|
|
82fe59e469 | ||
|
|
afc05e1731 | ||
|
|
0206b0a522 | ||
|
|
0e1e5a5ebe | ||
|
|
9ad088ed6a | ||
|
|
34da04bba5 | ||
|
|
09ce812faf | ||
|
|
1dc8cb2a98 | ||
|
|
e73c509823 | ||
|
|
e70a85400f | ||
|
|
f7aecf8eed | ||
|
|
cc2645aa9d | ||
|
|
52d23c4a8d | ||
|
|
1e57ddb9ee | ||
|
|
7ae883d921 | ||
|
|
27e97214bd | ||
|
|
6321a9e7e0 | ||
|
|
a9eadca46c | ||
|
|
76bef8a725 | ||
|
|
308b76dc7d | ||
|
|
31d4d29f3e | ||
|
|
016a7e87ea | ||
|
|
4ce88c7bfc | ||
|
|
f570bffcf7 | ||
|
|
3bb9aaf637 | ||
|
|
cf7a64c934 | ||
|
|
c466603193 | ||
|
|
bc53f329a9 | ||
|
|
4a5cc5153f | ||
|
|
8697670fe1 | ||
|
|
64d8543af9 | ||
|
|
482cc242cb | ||
|
|
2051e8183c | ||
|
|
d183903917 | ||
|
|
5c695899a1 | ||
|
|
708e912069 | ||
|
|
db1f4b2b52 | ||
|
|
1508782f49 | ||
|
|
445b830683 | ||
|
|
1a17e88142 | ||
|
|
c0ec2e7856 | ||
|
|
9e962bd0d1 | ||
|
|
7efcff13bb | ||
|
|
e70d0df949 | ||
|
|
fcaa469edd | ||
|
|
51508182ef | ||
|
|
27e78c1626 | ||
|
|
0b4d37a0b6 | ||
|
|
ddbebba6f1 | ||
|
|
7f296348e4 | ||
|
|
ca78e32d97 | ||
|
|
4efc561f4d | ||
|
|
40fed798a1 | ||
|
|
0876afc08c | ||
|
|
ba4c4d06ff | ||
|
|
f64c30af48 | ||
|
|
bb0cea2dd3 | ||
|
|
3c120ce602 | ||
|
|
6151dfb161 | ||
|
|
f05d4ec931 | ||
|
|
e16afc3fc2 | ||
|
|
1b8753fead | ||
|
|
ba960d1ced | ||
|
|
41b60b6152 | ||
|
|
70ddce713c | ||
|
|
e15622748b | ||
|
|
96687021ff | ||
|
|
3c0a7ef510 | ||
|
|
4d84c9fb3f | ||
|
|
aa35a16610 | ||
|
|
a380fcb680 | ||
|
|
e544afe475 | ||
|
|
c089388323 | ||
|
|
e97a043031 | ||
|
|
d1b6dfe577 | ||
|
|
9189fd411e | ||
|
|
432eba80a9 | ||
|
|
db39612c54 | ||
|
|
5794c82a2d | ||
|
|
acf875a886 | ||
|
|
79185bd90f | ||
|
|
d695c30988 | ||
|
|
a1308fbdc9 | ||
|
|
e4f2b761d6 | ||
|
|
6ff6009a70 | ||
|
|
dadeb4006e | ||
|
|
ee0ff762e5 | ||
|
|
1f01ba1d10 | ||
|
|
62965fe1df | ||
|
|
e29eb4cce5 | ||
|
|
699791e318 | ||
|
|
946fbbec3c | ||
|
|
d2aae0103d | ||
|
|
ab06e38b7c | ||
|
|
bd531c85b1 | ||
|
|
8a0ca3c2e5 | ||
|
|
97317ed2c6 | ||
|
|
cda9aae8a3 | ||
|
|
a33e785043 | ||
|
|
833e266a1f | ||
|
|
1bb9b2cb3f | ||
|
|
7ba129b3bf | ||
|
|
1e2c9ca28a | ||
|
|
c6f37fd05f | ||
|
|
b6b569fff9 | ||
|
|
ac57c016a6 | ||
|
|
28fdd9de95 | ||
|
|
1ec946aaa9 |
@@ -1,38 +0,0 @@
|
||||
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 }}
|
||||
+17
-1
@@ -138,10 +138,26 @@ dmypy.json
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
demo.py
|
||||
test.py
|
||||
server_ip.py
|
||||
game_utils.py
|
||||
member_activity_handle.py
|
||||
Yu-Gi-Oh/
|
||||
csgo/
|
||||
fantasy_card/
|
||||
data/
|
||||
log/
|
||||
backup/
|
||||
extensive_plugin/
|
||||
test/
|
||||
bot.py
|
||||
data/
|
||||
.env
|
||||
.env.dev
|
||||
resources/
|
||||
!/configs/config.py
|
||||
!/configs/config.yaml
|
||||
!/.env
|
||||
!/.env.dev
|
||||
!/plugins/csgo_server/
|
||||
!/plugins/activity/
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
|
||||
如果该项目的图片等等侵犯猫豆腐老师权益请联系我删除!
|
||||
|
||||
如果希望有个地方讨论绪山真寻Bot,或者有问题或建议,可以发送issues或加入[ <strong>[是真寻酱哒](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>]
|
||||
是新手!希望有个地方讨论绪山真寻Bot,或者有问题或建议,可以发送issues或加入[ <strong>[是真寻酱哒(萌新版)](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>]
|
||||
|
||||
[//]: # (是老手!讨论插件开发,nonebot2开发,可以加入[ <strong>[真寻酱的技术群](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ) </strong>])
|
||||
|
||||
## 声明
|
||||
此项目仅用于学习交流,请勿用于非法用途
|
||||
@@ -128,7 +130,7 @@
|
||||
- [x] 移动图片 (同上)
|
||||
- [x] 删除图片 (同上)
|
||||
- [x] 群内B站订阅
|
||||
- [x] 群词条
|
||||
- [x] 词条设置
|
||||
- [x] 休息吧/醒来
|
||||
|
||||
### 已实现的超级用户功能
|
||||
@@ -235,458 +237,196 @@ python bot.py
|
||||
|
||||
|
||||
## 使用Docker
|
||||
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
||||
#### GitHub:[Sakuracio/zhenxun_bot_docker](https://github.com/Sakuracio/zhenxun_bot_docker)
|
||||
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
|
||||
__Docker 单机版(仅真寻Bot)__
|
||||
**点击下方的 GitHub 徽标查看教程**
|
||||
[](https://github.com/Sakuracio/zhenxun_bot_docker)
|
||||
[](https://hub.docker.com/r/hibikier/zhenxun_bot)
|
||||
__Docker 全量版(包含 真寻Bot PostgreSQL数据库 go-cqhttp webui等)__
|
||||
[](https://github.com/SinKy-Yan/zhenxunbot-docker)
|
||||
[](https://hub.docker.com/r/jyishit/zhenxun_bot)
|
||||
**点击上方的 GitHub 徽标查看教程**
|
||||
PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能无法正常启动全量版容器**
|
||||
|
||||
## [爱发电](https://afdian.net/@HibiKier)
|
||||
<details>
|
||||
<summary>爱发电 以及 感谢投喂 </summary>
|
||||
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
|
||||
|
||||
### 感谢名单
|
||||
(可以告诉我你的 __github__ 地址,我偷偷换掉0v|)
|
||||
[Yui](https://afdian.net/u/870dc10a3cd311ed828852540025c377)
|
||||
[本喵无敌哒](https://afdian.net/u/dffaa9005bc911ebb69b52540025c377)
|
||||
[椎名冬羽](https://afdian.net/u/ca1ebd64395e11ed81b452540025c377)
|
||||
[kaito](https://afdian.net/u/a055e20a498811eab1f052540025c377)
|
||||
[笑柒XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377)
|
||||
[请问一份爱多少钱](https://afdian.net/u/f57ef6602dbd11ed977f52540025c377)
|
||||
[咸鱼鱼鱼鱼](https://afdian.net/u/8e39b9a400e011ed9f4a52540025c377)
|
||||
[Kafka](https://afdian.net/u/41d66798ef6911ecbc5952540025c377)
|
||||
[墨然](https://afdian.net/u/8aa5874a644d11eb8a6752540025c377)
|
||||
[爱发电用户_T9e4](https://afdian.net/u/2ad1bb82f3a711eca22852540025c377)
|
||||
[笑柒XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377)
|
||||
[noahzark](https://afdian.net/a/noahzark)
|
||||
[腊条](https://afdian.net/u/f739c4d69eca11eba94b52540025c377)
|
||||
[ze roller](https://afdian.net/u/0e599e96257211ed805152540025c377)
|
||||
[爱发电用户_4jrf](https://afdian.net/u/6b2cdcc817c611ed949152540025c377)
|
||||
[爱发电用户_TBsd](https://afdian.net/u/db638b60217911ed9efd52540025c377)
|
||||
[烟寒若雨](https://afdian.net/u/067bd2161eec11eda62b52540025c377)
|
||||
[ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377)
|
||||
[爱发电用户_b9S4](https://afdian.net/u/3d8f30581a2911edba6d52540025c377)
|
||||
[爱发电用户_c58s](https://afdian.net/u/a6ad8dda195e11ed9a4152540025c377)
|
||||
[爱发电用户_eNr9](https://afdian.net/u/05fdb41c0c9a11ed814952540025c377)
|
||||
[MangataAkihi](https://github.com/Sakuracio)
|
||||
[炀](https://afdian.net/u/69b76e9ec77b11ec874f52540025c377)
|
||||
[爱发电用户_Bc6j](https://afdian.net/u/8546be24f44111eca64052540025c377)
|
||||
[大魔王](https://github.com/xipesoy)
|
||||
[CopilotLaLaLa](https://github.com/CopilotLaLaLa)
|
||||
[嘿小欧](https://afdian.net/u/daa4bec4f24911ec82e552540025c377)
|
||||
[回忆的秋千](https://afdian.net/u/e315d9c6f14f11ecbeef52540025c377)
|
||||
[十年くん](https://github.com/shinianj)
|
||||
[哇](https://afdian.net/u/9b266244f23911eca19052540025c377)
|
||||
[yajiwa](https://github.com/yajiwa)
|
||||
[爆金币](https://afdian.net/u/0d78879ef23711ecb22452540025c377)
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## 更新
|
||||
|
||||
### 2022/7/3
|
||||
### 2022/10/16 \[v0.1.6.4]
|
||||
|
||||
* BagUser提供方法`check_props`方法,用于判断用户是否含有该道具并是否使用
|
||||
* 优化商品显示图片,提供限制,限购,折扣提示
|
||||
* 修复图库内图片无法被连续删除的问题 [@pull/879](https://github.com/HibiKier/zhenxun_bot/pull/879)
|
||||
* 色图提供配置项`MAX_ONCE_NUM2FORWARD`:群聊中单次发送图片数量达到指定时使用合并转发
|
||||
* 优化修复了商品修改命令
|
||||
* B站订阅UP动态改为详情页截图
|
||||
* 修改商店道具icon可以为空
|
||||
|
||||
### 2022/6/28
|
||||
### 2022/10/15
|
||||
|
||||
* 修复色图插件api修改无法搜索图片 [@pull/866](https://github.com/HibiKier/zhenxun_bot/pull/866)
|
||||
* nonebot2版本更新为rc1
|
||||
* 我的道具改为图片形式
|
||||
* 商品添加图标与是否为被动道具(被动道具无法被主动使用)
|
||||
* 商品添加使用前方法和使用后方法(类似hook),使用方法具体查看文档或签到商品文件中注册的例子
|
||||
* 新增用户使用道具,花费金币(包括插件)及用途记录
|
||||
* 更细致的金币使用依赖注入
|
||||
* 更多的依赖注入(包含图片获取等等..
|
||||
* 修复我的道具仅有被动或主动道具时图片显示错误
|
||||
* 色图插件p站反向代理失效 [@pull/1139](https://github.com/HibiKier/zhenxun_bot/pull/1139)
|
||||
|
||||
### 2022/6/26
|
||||
### 2022/10/9
|
||||
|
||||
* 替换了bt URL
|
||||
* PIX当使用pid查询图片时,会发送该pid下所有图片
|
||||
* 商店提供了每日购买次数限制
|
||||
* 修复碧蓝档案角色获取问题,换源 [@pull/1124](https://github.com/HibiKier/zhenxun_bot/pull/1124)
|
||||
|
||||
### 2022/6/24
|
||||
### 2022/10/7
|
||||
|
||||
* 对WSL虚拟机 代理 添加写法 [@pull/847](https://github.com/HibiKier/zhenxun_bot/pull/847)
|
||||
* 修复 B 站请求返回 -401 错误 [@pull/1119](https://github.com/HibiKier/zhenxun_bot/pull/1119)
|
||||
* 关闭功能与被动时不再区分大小写,同名时仅被动关闭操作生效
|
||||
|
||||
### 2022/6/21
|
||||
### 2022/9/30
|
||||
|
||||
* update parse_bilibili [@pull/840](https://github.com/HibiKier/zhenxun_bot/pull/840)
|
||||
* 修改重置开箱的使用权限 [@pull/1118](https://github.com/HibiKier/zhenxun_bot/pull/1118)
|
||||
|
||||
### 2022/6/19 \[v0.1.6.0]
|
||||
### 2022/9/27
|
||||
|
||||
* 暂时使用hook修复webui中plugins2setting修改时会改变plugins2setting.cmd为字符串
|
||||
* 修复原神树脂重复提醒的bug [@pull/828](https://github.com/HibiKier/zhenxun_bot/pull/828)
|
||||
* 词条优化问题展示,修改含机器人昵称和@逻辑 [@pull/835](https://github.com/HibiKier/zhenxun_bot/pull/835)
|
||||
* 更新b站转发解析 [@pull/1117](https://github.com/HibiKier/zhenxun_bot/pull/1117)
|
||||
|
||||
### 2022/6/18
|
||||
### 2022/9/24
|
||||
|
||||
* 修复昵称系统`BLACK_WORD`为空时造成报错
|
||||
* 修复特殊头像时背景透明化出错
|
||||
* 修复text2image纯文本时换行时颜色不统一
|
||||
* 优化webUI,当有插件出错时不会影响其他插件显示
|
||||
* 优化Config类型注释 [@pull/830](https://github.com/HibiKier/zhenxun_bot/pull/830)
|
||||
* 优化browser
|
||||
* 修复b站订阅 [@pull/1112](https://github.com/HibiKier/zhenxun_bot/pull/1112)
|
||||
* fix: 重载赛马娘卡池失败 [@pull/1114](https://github.com/HibiKier/zhenxun_bot/pull/1114)
|
||||
|
||||
### 2022/6/17
|
||||
### 2022/9/19
|
||||
|
||||
* 修复wordbank的一些小问题 @pull/820
|
||||
* 更换bilibili_sub获取用户昵称用的API&尝试修了一下get_video() [@pull/1097](https://github.com/HibiKier/zhenxun_bot/pull/1097)
|
||||
* 修复csgo每日开箱可以多开一次
|
||||
|
||||
### 2022/6/14
|
||||
### 2022/9/18
|
||||
|
||||
* AsyncHttpx提供可关闭 ssl 验证参数 [@pull/812](https://github.com/HibiKier/zhenxun_bot/pull/812)
|
||||
* fix: 自动更新群组 [@pull/810](https://github.com/HibiKier/zhenxun_bot/pull/810)
|
||||
* fix: 修复添加词条时对answer中图片的处理 [@pull/806](https://github.com/HibiKier/zhenxun_bot/pull/806)
|
||||
* 修复pix中指定num无法生效
|
||||
* 替换了bt URL
|
||||
* 修复 bilireq 版本过低导致 B 站视频解析错误 [@pull/1090](https://github.com/HibiKier/zhenxun_bot/pull/1096)
|
||||
|
||||
### 2022/6/13
|
||||
### 2022/9/16
|
||||
|
||||
* Windows 重启适配 [@pull/804](https://github.com/HibiKier/zhenxun_bot/pull/804)
|
||||
* 色图等提供修改md5方法 [@pull/800](https://github.com/HibiKier/zhenxun_bot/pull/800)
|
||||
* webui中token.json文件写入补充 [@pull/798](https://github.com/HibiKier/zhenxun_bot/pull/798)
|
||||
* 修复识图某些图片可能会出错
|
||||
* fix: bilibili_sub, azur_draw_card [@pull/1090](https://github.com/HibiKier/zhenxun_bot/pull/1090)
|
||||
* 修复原神资源查询查询完毕后图片存储错误
|
||||
* b站订阅发送 与 b站订阅 使用相同开关,即:关闭b站订阅
|
||||
|
||||
### 2022/6/11
|
||||
### 2022/9/10
|
||||
|
||||
* pix当只有一个tag时且为数字时可以通过添加'#'防止判定为数量
|
||||
* 自定义群欢迎消息参数不完全时提示报错
|
||||
* 修改bt插件的url地址 [@pull/1067](https://github.com/HibiKier/zhenxun_bot/pull/1067)
|
||||
|
||||
### 2022/6/9
|
||||
### 2022/9/8
|
||||
|
||||
* 修复b站订阅同群二人以上相同订阅时发送多次信息
|
||||
* 修复超级用户帮助中缺少了 ‘插件商店’ 相关帮助
|
||||
* 昵称系统提供了详细帮助
|
||||
* 添加插件数据初始化判断
|
||||
|
||||
### 2022/6/5 \[v0.1.5.9]
|
||||
### 2022/9/4
|
||||
|
||||
* webui修复plugin2setting中cmd从list转变为str
|
||||
* 当命令`我的金币`被风控时将以图片形式发送
|
||||
* fix gold_redbag [@pull/763](https://github.com/HibiKier/zhenxun_bot/pull/763)
|
||||
* 金币红包功能增加更多封面 [@pull/764](https://github.com/HibiKier/zhenxun_bot/pull/764)
|
||||
* 旧词条提供图片迁移(需要重新获取old_model文件,并将数据库中user_qq为0的数据删除)
|
||||
|
||||
### 2022/6/3
|
||||
### 2022/9/3
|
||||
|
||||
* 插件仓库在已安装插件边上会提示\[已安装]
|
||||
* 修复ShopRegister kwargs某些字段无效
|
||||
* 调整了一下查看所有请求中的年龄绘制 [@pull/745](https://github.com/HibiKier/zhenxun_bot/pull/745)
|
||||
* 修复原神树脂提醒bug [@pull/756](https://github.com/HibiKier/zhenxun_bot/pull/756)
|
||||
* 原神玩家查询增加须弥地区 [@pull/1053](https://github.com/HibiKier/zhenxun_bot/pull/1053)
|
||||
* av号覆盖全面,且修复av号链接 [@pull/1033](https://github.com/HibiKier/zhenxun_bot/pull/1033)
|
||||
* 修复词条含有CQ回答的模糊匹配无法被解析
|
||||
* 禁言检测图片在内存中获取图片hash
|
||||
* B站订阅在群里中任意群管理员可以统一管理(原来为管理员1无法删除管理员2的订阅)
|
||||
* 修复原神资源查询地图api数据变更导致更新的地图不完全
|
||||
|
||||
### 2022/5/31
|
||||
### 2022/8/27
|
||||
|
||||
* 修复开启/关闭全部功能时帮助图片未重绘 [@pull/721](https://github.com/HibiKier/zhenxun_bot/pull/721)
|
||||
* bot_friend_group将group_handle.修改为friend_handle. [@pull/711](https://github.com/HibiKier/zhenxun_bot/pull/711)
|
||||
* 修复发红包图片背景未透明化;修复原神树脂提醒参数错误 [@pull/712](https://github.com/HibiKier/zhenxun_bot/pull/712)
|
||||
* 修复抽卡插件:方舟更新UP池信息时,若公告的第一个池子过期会导致无法更新UP池信息 [@pull/707](https://github.com/HibiKier/zhenxun_bot/pull/707)
|
||||
* 商店插件判断是否有requirements.txt文件 [@pull/705](https://github.com/HibiKier/zhenxun_bot/pull/705)
|
||||
* 删除原神玩家查询api返回变更的多余键值
|
||||
* 优化了text2image方法
|
||||
* 修复签到积分双倍后,日志记录获得积分变4倍问题 [@pull/1044](https://github.com/HibiKier/zhenxun_bot/pull/1044)
|
||||
|
||||
### 2022/5/29 \[v0.1.5.8]
|
||||
### 2022/8/26
|
||||
|
||||
* 提供了真寻适配仓库的插件 安装/卸载 操作
|
||||
* 暂时关闭了插件资源清空
|
||||
* 通过指令安装插件时会在插件目录下生成plugin_info.json记录当前插件信息
|
||||
* 修复群管理员无法添加词条
|
||||
* 修复词条关键词"问"前空格问题
|
||||
|
||||
### 2022/5/28
|
||||
### 2022/8/23
|
||||
|
||||
* 修复私聊无法添加昵称
|
||||
* 修复原神玩家查询层岩巨渊地下矿区没开时报错
|
||||
* 修复 ```休息吧``` 无法阻断戳一戳
|
||||
* 当图库无图片时,戳一戳将略过发送图片
|
||||
* 新增搜图提供配置项```ALLOW_GROUP_R18```:允许在群聊中使用r18参数
|
||||
* 新增自动更新插件```UPDATE_REMIND```:新版本提醒,原配置项```AUTO_UPDATE_ZHENXUN```改为自动更新升级
|
||||
* black_word新增当群权限为-1时不再检测该群
|
||||
* 修复非超级用户绑定原神cookie会被black_word阻拦
|
||||
* 修复微博热搜报错,发红包小bug [@pull/688](https://github.com/HibiKier/zhenxun_bot/pull/688)
|
||||
* 更多的中文提示
|
||||
* 修了下模糊匹配 issue#1026 [@pull/1026](https://github.com/HibiKier/zhenxun_bot/pull/1026)
|
||||
|
||||
### 2022/5/26
|
||||
### 2022/8/22
|
||||
|
||||
* 修复\[滴滴滴]会被转义成[滴滴滴]导致无法触发的问题
|
||||
* 将一些错误以中文提示输出
|
||||
* 更新BT搜索源地址 [@pull/668](https://github.com/HibiKier/zhenxun_bot/pull/668)
|
||||
* 更新抽卡插件 [@pull/667](https://github.com/HibiKier/zhenxun_bot/pull/667)
|
||||
* 修复首次安装时词条旧表出错(因为根本就没有这张表!)
|
||||
* 取消配置替换定时任务,统一存储
|
||||
* 对米游社cookie进行判断,整合米游社签到信息 [@pull/1014](https://github.com/HibiKier/zhenxun_bot/pull/1014)
|
||||
* 修正尘歌壶和质变仪图片获取地址 [@pull/1010](https://github.com/HibiKier/zhenxun_bot/pull/1010)
|
||||
* 修复词库问答 **很多** 问题[@pull/1012](https://github.com/HibiKier/zhenxun_bot/pull/1012)
|
||||
|
||||
### 2022/5/25
|
||||
### 2022/8/21 \[v0.1.6.3]
|
||||
|
||||
* 修复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)
|
||||
* 重构群词条,改为词库Plus,增加 精准|模糊|正则 问题匹配,问题与回答均支持at,image,face,超级用户额外提供 全局|私聊 词库设置,数据迁移目前只提供了问题和回答都是纯文本的词条
|
||||
* 修复b站转发解析av号无法解析
|
||||
* B站订阅直播订阅支持短号
|
||||
* 开箱提供重置开箱命令,重置今日所有开箱数据(重置次数,并不会删除今日已开箱记录)
|
||||
* 提供全局字典GDict,通过from utils.utils import GDict导入
|
||||
* 适配omega 13w张图的数据结构表(建议删表重导)
|
||||
* 除首次启动外将配置替换加入单次定时任务,加快启动速度
|
||||
* fix: WordBank.check() [@pull/1008](https://github.com/HibiKier/zhenxun_bot/pull/1008)
|
||||
* 改进插件 `我有一个朋友`,避免触发过于频繁 [@pull/1001](https://github.com/HibiKier/zhenxun_bot/pull/1001)
|
||||
* 原神便笺新增洞天宝钱和参量质变仪提示 [@pull/1005](https://github.com/HibiKier/zhenxun_bot/pull/1005)
|
||||
* 新增米游社签到功能,自动领取(白嫖)米游币 [@pull/991](https://github.com/HibiKier/zhenxun_bot/pull/991)
|
||||
|
||||
### 2022/5/24
|
||||
### 2022/8/14
|
||||
|
||||
* 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)
|
||||
* 修复epic未获取到时间时出错
|
||||
* 修复订阅主播时动态获取的id是直播间id
|
||||
|
||||
### 2022/5/23 \[v0.1.5.6]
|
||||
### 2022/8/8
|
||||
|
||||
* 修复"清除已删除插件数据" [@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参数
|
||||
* 修复赛马娘重载卡池失败的问题 [@pull/969](https://github.com/HibiKier/zhenxun_bot/pull/969)
|
||||
|
||||
### 2022/5/22 \[v0.1.5.4]
|
||||
### 2022/8/3
|
||||
|
||||
* 使用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有时获取新免费游戏消息时获取不到图片
|
||||
* 修复好感度满时签到出错(虽然是不可能满的
|
||||
* 修复原神资源图标下载路径错误
|
||||
* 修复自动更新群组可能失败
|
||||
* 修复 bili动态链接在投稿视频时URL和分割线连在一起 [@pull/951](https://github.com/HibiKier/zhenxun_bot/pull/961)
|
||||
* 更新 Epic 免费游戏商城链接拼接规则 [@pull/957](https://github.com/HibiKier/zhenxun_bot/pull/957)
|
||||
|
||||
### 2022/5/21
|
||||
### 2022/8/6
|
||||
|
||||
* 修复搜番无结果时报错无正确反馈
|
||||
* 解锁了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]
|
||||
|
||||
* 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数
|
||||
* 添加商品注册装饰器shop_register
|
||||
* 修复商品函数kwargs无法获取参数值
|
||||
|
||||
|
||||
### 2022/5/1
|
||||
|
||||
* 删除了`group_last_chat`插件(该功能可由`chat_history`替代
|
||||
* 新增敏感词检测(全新反击系统,是时候重拳出击了
|
||||
|
||||
### 2022/4/26
|
||||
|
||||
* 修复了群白名单无法正确添加
|
||||
* 优化了管理员帮助图片,背景图层将位于最下层
|
||||
* 修复了树脂140时不断提醒(未测试
|
||||
* 新增了消息记录的消息排行
|
||||
* WebUI新增CPU,内存,磁盘监控
|
||||
* WebUI新增资源文件夹统计可视化
|
||||
|
||||
### 2022/4/12
|
||||
|
||||
* 修复b了命令私聊出错
|
||||
|
||||
### 2022/4/10 \[v0.1.4.7]
|
||||
|
||||
* 新增消息记录模块
|
||||
* 丰富处理请求操作提示
|
||||
* web ui新增配置项修改
|
||||
|
||||
### 2022/4/9
|
||||
|
||||
* fix: 更新问题,戳一戳图片路径问题 [@pull/144](https://github.com/HibiKier/zhenxun_bot/pull/144)
|
||||
|
||||
### 2022/4/8
|
||||
|
||||
* 修复原神玩家查询
|
||||
|
||||
### 2022/4/6
|
||||
|
||||
* update search_type [@pull/143](https://github.com/HibiKier/zhenxun_bot/pull/143)
|
||||
|
||||
### 2022/4/5 \[v0.1.4.6]
|
||||
|
||||
* 修复web修改插件后帮助图片生成错误
|
||||
|
||||
### 2022/4/4 \[v0.1.4.5]
|
||||
|
||||
* 替换了bt搜索URL
|
||||
* 优化使用playwright的相关代码
|
||||
* 原神玩家查询新增层岩巨渊探索
|
||||
* 修复原神便笺角色头像黑框
|
||||
* 修复同意群聊请求错误
|
||||
* 提供webui方面的api
|
||||
* 新增web-ui(前端简易管理页面插件)插件
|
||||
|
||||
### 2022/3/21
|
||||
|
||||
* 修复statistics_handle.py乱码
|
||||
|
||||
### 2022/3/18 \[v0.1.4.4]
|
||||
|
||||
* 修复戳一戳无法功能关闭与ban禁用
|
||||
* 新增图片搜索 search_image
|
||||
|
||||
### 2022/3/7
|
||||
|
||||
* 优化增删权限插件
|
||||
|
||||
### 2022/3/6
|
||||
|
||||
* 修复树脂提醒无法开启
|
||||
* 修复p搜图片路径错误
|
||||
|
||||
### 2022/3/3 \[v0.1.4.3]
|
||||
|
||||
* 修复手动同意群聊请求依旧退出
|
||||
|
||||
### 2022/3/1 \[v0.1.4.2]
|
||||
|
||||
* 0.1.4内容
|
||||
|
||||
### 2022/2/27 \[v0.1.4.1]
|
||||
|
||||
* 优化抽卡
|
||||
|
||||
### 2022/2/25 \[v0.1.4]
|
||||
|
||||
* PIX提供配置MAX_ONCE_NUM2FORWARD:当单次发送图片超过指定张数且在群聊时,将转为合并消息
|
||||
* 修复点歌无法正确发送
|
||||
* 修复我有一个朋友有时文本会包含CQ码
|
||||
* 修复群欢消息被动控制文本未删除 [@pull/124](https://github.com/HibiKier/zhenxun_bot/pull/124)
|
||||
* message_builder.image不再提供参数:abspath
|
||||
|
||||
### 2022/2/23
|
||||
|
||||
* 插件状态将从已加载插件模块中读取
|
||||
* 修复b站订阅插件订阅失败问题
|
||||
* 修复重启命令无法使用
|
||||
|
||||
### 2022/2/21 \[v0.1.3.2]
|
||||
|
||||
* 群权限为-1时,超级用户发送的命令依旧生效
|
||||
* 当群权限为-1时,被动技能也将不会发送
|
||||
* 修复功能开关,b站转发解析,复读 ignore无法使用
|
||||
* 修复色图下载文件名与路径错误
|
||||
* 修复被动技能提醒有时无法删除控制文本
|
||||
|
||||
|
||||
### 2022/2/20 \[v0.1.3.1]
|
||||
|
||||
* 修复pix下载临时文件目录错误
|
||||
* 修复AI,天气,发送图片ignore导致无法使用
|
||||
* 修复纯文本被动技能提醒有时无法删除控制文本
|
||||
|
||||
### 2022/2/19 \[v0.1.3] (nonebot beta2!)
|
||||
|
||||
* 由于nonebot升级版本,提供更新建议(__该次升级将会导致nonebot.beta1以下的插件无法使用__
|
||||
* 保证services,utils,configs,plugins,basic_plugins,文件夹均为最新
|
||||
* 根目录有pyproject.toml与poetry.lock
|
||||
* 执行命令:
|
||||
* pip3 install poetry
|
||||
* poetry install
|
||||
* poetry shell
|
||||
* playwright install chromium
|
||||
* python3 bot.py
|
||||
|
||||
|
||||
* 适配nonebot.beta2
|
||||
* 删除图片搜索 nonebot_plugin_picsearcher
|
||||
* 替换cos api
|
||||
* 原神签到树脂提醒新增绑定群里,在某群绑定uid就会在某群发送提醒信息(有好友则私聊,需要重新绑定uid
|
||||
* 修改update_info.json
|
||||
* 修复原神资源查询下载数据失败时导致报错
|
||||
* 优化BuildImage.circle()锯齿问题 [@pull/109](https://github.com/HibiKier/zhenxun_bot/pull/109)
|
||||
* epic restful 替换 [@pull/119](https://github.com/HibiKier/zhenxun_bot/pull/119)
|
||||
* fix: 修复远古时期残留的epic推送问题 [@pull/122](https://github.com/HibiKier/zhenxun_bot/pull/122)
|
||||
|
||||
### 2022/2/11
|
||||
|
||||
* 修复pix不使用反代无法下载图片
|
||||
|
||||
### 2022/2/10 \[v0.1.1]
|
||||
|
||||
* 修复购买道具出错
|
||||
|
||||
### 2022/2/9 \[v0.1]
|
||||
|
||||
* 新增原神自动签到和手动签到
|
||||
* 新增原神树脂提醒
|
||||
* 新增手动重载Config.yaml命令以及重载配置定时任务(极少部分帮助或配置可能需要重启
|
||||
* 修改了发送本地图库的matcher,改为on_message
|
||||
* register_use可以通过返回值发送消息
|
||||
* 修复修改商品时限制时间出错
|
||||
* 修复超时商品依旧可以被购买
|
||||
|
||||
### 2022/1/16 \[v0.0.9.0]
|
||||
|
||||
* Ai提供文本敏感词过滤器
|
||||
* 疫情插件适配新版腾讯API
|
||||
* 修复/t回复带空格切分
|
||||
* 修复原神玩家查询缺少渊下宫和稻妻家园以及角色不完全
|
||||
* 修复方法 text2image 中 padding 和 font 无法对纯文本生效
|
||||
* 修复签到图片中信息并未使用配置文件中的色图概率
|
||||
* 修改原神大地图合成方式,改为先压缩再合成
|
||||
* bag_user弃用字段props(该字段会在下次更新删除),使用新字段property
|
||||
* 数据库中所有belonging_group统一修改为group_id
|
||||
* 商店将registered_use和register_goods更名为register_use何register_goods
|
||||
* 商品注册提供了kwargs参数提供:
|
||||
* bot
|
||||
* event
|
||||
* 特殊字段
|
||||
* “send_success_msg”(发送成功的交互信息->即:使用道具 {name} {num} 次成功)
|
||||
* “_max_num_limit”(该道具单次使用的最多个数,默认1)
|
||||
|
||||
### 2022/1/5 \[v0.0.8.2]
|
||||
|
||||
* 提供金币消费hook,可在plugins2settings.yaml中配置该功能需要消费的金币
|
||||
* 商店插件将作为内置插件移动至basic_plugins
|
||||
* 商店插件通过export提供了方法,不需要修改商店插件代码添加商品数据和生效方法
|
||||
* 修改了hook插件顺序,主要以auth_hook为主
|
||||
* 修改商店图片样式
|
||||
* 取消每次启动更新城市列表(首次除外),采用定时更新,加快bot启动速度
|
||||
* 取消每次启动时截取今日素材,采用调用时截取保存,加快bot启动速度
|
||||
* 更新色图时当图片404时会删除并替换
|
||||
* 疫情消息回复改为图片
|
||||
* 修复商店折扣和限时时间无法生效
|
||||
* 修复原神玩家查询尘歌壶缺少图片
|
||||
|
||||
### 2021/12/26
|
||||
|
||||
* 修复群词条问题 空格 会被录入导致不断回复
|
||||
* 修复米游社app替换api导致无法正常查询
|
||||
|
||||
### 2021/12/24
|
||||
|
||||
* 支持国际疫情数据查询 [@pull/99](https://github.com/HibiKier/zhenxun_bot/pull/99)
|
||||
|
||||
### 2021/12/20
|
||||
|
||||
* 只有发布小于存储时间的新动态/视频的时候才获取并推送 [@pull/96](https://github.com/HibiKier/zhenxun_bot/pull/96)
|
||||
|
||||
### 2021/12/16 \[v0.0.7.0]
|
||||
|
||||
* 提供了真寻群聊功能总开关和对应默认配置项,命令:休息吧 醒来
|
||||
* 新增原神玩家查询,原神便笺查询
|
||||
* 群功能管理提供全部开启/关闭命令:开启/关闭全部功能
|
||||
* 提供主要数据自动备份,且提供自定义配置项
|
||||
* 提供命令:关于,用于介绍Bot之类的
|
||||
* 新增命令exec,用于执行sql语句
|
||||
* 签到提供参数 "all",用于签到所有群聊
|
||||
* Ban提醒提供cd
|
||||
* 本地图库提供配置项SHOW_ID,用于设置发送图片时是否显示id
|
||||
* 色图和PIX提供配置项SHOW_INFO,用于设置发送图片时是否显示图片信息
|
||||
* 所有被动技能提供了进群默认状态配置项
|
||||
* 修复添加权限第二种添加形式无法正确添加正确的权限
|
||||
* 修复签到获取好感度卡时金币不会增加
|
||||
* 修复当红包数量不合法时依旧扣除金币
|
||||
* 修复金币红包再次使用塞红包时无法正确退回上次未开完的金币
|
||||
* 修复 滴滴滴- 只包含图片时不会发送至管理员
|
||||
* 修复添加权限等级错误
|
||||
* 修复群词条以bot名称为开头时无法正确触发
|
||||
* 修改了权限插件加载顺序防止小概率优先加载权限插件引起报错
|
||||
* 本地图库新图库会统一建立在resource/img/image_management文件夹下,如果该文件夹内未找到图库,会从上级目录查找(即:resource/img/)
|
||||
* 修复了原神自动签到返回invalid request的问题,新增查看我的cookie命令 [@pull/971](https://github.com/HibiKier/zhenxun_bot/pull/971)
|
||||
|
||||
<br>
|
||||
|
||||
__..... 更多更新信息请查看文档__
|
||||
|
||||
## Todo
|
||||
- [ ] web管理
|
||||
|
||||
## 爱发电
|
||||
|
||||
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
|
||||
- [x] web管理
|
||||
|
||||
## 感谢
|
||||
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__: v0.1.6.0
|
||||
__version__: v0.1.6.4
|
||||
|
||||
@@ -87,13 +87,13 @@ task_data = None
|
||||
|
||||
|
||||
async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
global task_data
|
||||
"""
|
||||
修改群功能状态
|
||||
:param cmd: 功能名称
|
||||
:param group_id: 群号
|
||||
:param is_super: 是否位超级用户,超级用户用于私聊开关功能状态
|
||||
"""
|
||||
global task_data
|
||||
if not task_data:
|
||||
task_data = group_manager.get_task_data()
|
||||
group_help_file = DATA_PATH / "group_help" / f"{group_id}.png"
|
||||
@@ -121,9 +121,9 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
return f"已 {status} 全部功能!"
|
||||
if cmd in [task_data[x] for x in task_data.keys()]:
|
||||
if cmd.lower() in [task_data[x].lower() for x in task_data.keys()]:
|
||||
type_ = "task"
|
||||
modules = [x for x in task_data.keys() if task_data[x] == cmd]
|
||||
modules = [x for x in task_data.keys() if task_data[x].lower() == cmd.lower()]
|
||||
for module in modules:
|
||||
if is_super:
|
||||
module = f"{module}:super"
|
||||
|
||||
@@ -36,11 +36,11 @@ custom_welcome = on_command(
|
||||
|
||||
@custom_welcome.handle()
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
img = get_message_img(event.json())
|
||||
if not msg and not img:
|
||||
await custom_welcome.finish(__plugin_usage__)
|
||||
try:
|
||||
msg = arg.extract_plain_text().strip()
|
||||
img = get_message_img(event.json())
|
||||
if not msg and not img:
|
||||
await custom_welcome.finish(__plugin_usage__)
|
||||
await custom_welcome.send(
|
||||
await custom_group_welcome(msg, img, event.user_id, event.group_id),
|
||||
at_sender=True,
|
||||
|
||||
@@ -41,7 +41,7 @@ Config.add_plugin_config(
|
||||
)
|
||||
|
||||
|
||||
cx = on_message(priority=9, block=False)
|
||||
cx = on_message(priority=9999, block=False, rule=lambda: False)
|
||||
|
||||
|
||||
# 早上好
|
||||
@@ -60,7 +60,7 @@ async def _():
|
||||
try:
|
||||
await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + result)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送早安")
|
||||
logger.warning(f"{g} 发送早安失败")
|
||||
except Exception as e:
|
||||
logger.error(f"早晚安错误 e:{e}")
|
||||
|
||||
@@ -83,7 +83,7 @@ async def _():
|
||||
group_id=g, message=f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + result
|
||||
)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送晚安")
|
||||
logger.warning(f"{g} 发送晚安失败")
|
||||
except Exception as e:
|
||||
logger.error(f"早晚安错误 e:{e}")
|
||||
|
||||
|
||||
@@ -16,11 +16,12 @@ __zx_plugin_name__ = "消息统计"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
发言记录统计
|
||||
regex:(周|月)?消息排行(des|DES)?(n=[0-9]{1,2})?
|
||||
regex:(周|月|日)?消息排行(des|DES)?(n=[0-9]{1,2})?
|
||||
指令:
|
||||
消息统计?(des)?(n=?)
|
||||
周消息统计?(des)?(n=?)
|
||||
月消息统计?(des)?(n=?)
|
||||
日消息统计?(des)?(n=?)
|
||||
示例:
|
||||
消息统计
|
||||
消息统计des
|
||||
@@ -31,7 +32,8 @@ __plugin_des__ = "发言消息排行"
|
||||
__plugin_cmd__ = [
|
||||
"消息统计",
|
||||
"周消息统计",
|
||||
"月消息统计"
|
||||
"月消息统计",
|
||||
"日消息统计"
|
||||
]
|
||||
__plugin_type__ = ("数据统计", 1)
|
||||
__plugin_version__ = 0.1
|
||||
@@ -42,7 +44,7 @@ __plugin_settings__ = {
|
||||
}
|
||||
|
||||
|
||||
msg_handler = on_regex(r"^(周|月)?消息统计(des|DES)?(n=[0-9]{1,2})?$", priority=5, block=True)
|
||||
msg_handler = on_regex(r"^(周|月|日)?消息统计(des|DES)?(n=[0-9]{1,2})?$", priority=5, block=True)
|
||||
|
||||
|
||||
@msg_handler.handle()
|
||||
@@ -53,10 +55,14 @@ async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup())
|
||||
num = num.split("=")[-1] if num else 10
|
||||
if num and is_number(num) and 10 < int(num) < 50:
|
||||
num = int(num)
|
||||
if date in ["周"]:
|
||||
date_scope = (datetime.now() - timedelta(days=7), datetime.now())
|
||||
time_now = datetime.now()
|
||||
zero_today = time_now - timedelta(hours=time_now.hour, minutes=time_now.minute, seconds=time_now.second)
|
||||
if date in ["日"]:
|
||||
date_scope = (zero_today, time_now)
|
||||
elif date in ["周"]:
|
||||
date_scope = (time_now - timedelta(days=7), time_now)
|
||||
elif date in ["月"]:
|
||||
date_scope = (datetime.now() - timedelta(days=30), datetime.now())
|
||||
date_scope = (time_now - timedelta(days=30), time_now)
|
||||
if rank_data := await ChatHistory.get_group_msg_rank(
|
||||
gid, num, order or "DESC", date_scope
|
||||
):
|
||||
@@ -79,7 +85,7 @@ async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup())
|
||||
pytz.timezone("Asia/Shanghai")
|
||||
).replace(microsecond=0)
|
||||
else:
|
||||
date_scope = datetime.now().replace(microsecond=0)
|
||||
date_scope = time_now.replace(microsecond=0)
|
||||
date_str = f"日期:{date_scope} - 至今"
|
||||
else:
|
||||
date_str = f"日期:{date_scope[0].replace(microsecond=0)} - {date_scope[1].replace(microsecond=0)}"
|
||||
|
||||
@@ -44,7 +44,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@simple_help.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State, arg: Message = CommandArg()):
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
is_super = False
|
||||
if msg:
|
||||
|
||||
@@ -44,7 +44,7 @@ def _create_help_img(
|
||||
:param help_image: 图片路径
|
||||
:param simple_help_image: 简易帮助图片路径
|
||||
"""
|
||||
_matchers = get_matchers()
|
||||
_matchers = get_matchers(True)
|
||||
width = 0
|
||||
matchers_data = {}
|
||||
_des_tmp = {}
|
||||
@@ -55,15 +55,16 @@ def _create_help_img(
|
||||
# 插件分类
|
||||
for matcher in _matchers:
|
||||
plugin_name = None
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_plugin = matcher.plugin
|
||||
if not _plugin:
|
||||
logger.warning(f"获取 功能:{matcher.plugin_name} 失败...")
|
||||
continue
|
||||
metadata = _plugin.metadata
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
plugin_name = metadata.name if metadata else _module.__getattribute__("__zx_plugin_name__")
|
||||
try:
|
||||
plugin_des = _module.__getattribute__("__plugin_des__")
|
||||
plugin_des = metadata.description if metadata else _module.__getattribute__("__plugin_des__")
|
||||
except AttributeError:
|
||||
plugin_des = "_"
|
||||
if (
|
||||
@@ -343,13 +344,14 @@ def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
|
||||
if module:
|
||||
try:
|
||||
plugin = nonebot.plugin.get_plugin(module)
|
||||
metadata = plugin.metadata
|
||||
if plugin:
|
||||
if is_super:
|
||||
result = plugin.module.__getattribute__(
|
||||
"__plugin_superuser_usage__"
|
||||
)
|
||||
else:
|
||||
result = plugin.module.__getattribute__("__plugin_usage__")
|
||||
result = metadata.usage if metadata else plugin.module.__getattribute__("__plugin_usage__")
|
||||
if result:
|
||||
width = 0
|
||||
for x in result.split("\n"):
|
||||
|
||||
@@ -3,6 +3,7 @@ from nonebot.message import run_preprocessor, run_postprocessor, IgnoredExceptio
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.bag_user import BagUser
|
||||
from models.user_shop_gold_log import UserShopGoldLog
|
||||
from utils.manager import (
|
||||
plugins2settings_manager,
|
||||
admin_manager,
|
||||
@@ -59,6 +60,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
||||
if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
|
||||
await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
|
||||
raise IgnoredException(f"{module} 金币限制...")
|
||||
await UserShopGoldLog.add_shop_log(event.user_id, event.group_id, 2, matcher.plugin_name, cost_gold, 1)
|
||||
# 当插件不阻塞超级用户时,超级用户提前扣除金币
|
||||
if (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
|
||||
@@ -2,15 +2,12 @@ from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.typing import T_State
|
||||
from ._utils import status_message_manager
|
||||
from utils.image_utils import text2image
|
||||
from typing import Dict, Any
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
PrivateMessageEvent,
|
||||
GroupMessageEvent,
|
||||
)
|
||||
import re
|
||||
|
||||
|
||||
# 为什么AI会自己和自己聊天
|
||||
@@ -41,11 +38,6 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
status_message_manager.delete(event.user_id)
|
||||
raise IgnoredException("有命令就别说话了")
|
||||
|
||||
# @Bot.on_calling_api
|
||||
# async def handle_api_call(bot: Bot, api: str, data: Dict[str, Any]):
|
||||
# if api in ["send_msg", "send_group_msg", "send_private_msg"]:
|
||||
# msg = str(data["message"])
|
||||
# if (r := re.search("\[\[To_Img\|?(.*?)]]", msg)) or (r := re.search("[[To_Img\|?(.*?)[[")):
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import re
|
||||
|
||||
|
||||
@Bot.on_calling_api
|
||||
async def handle_api_call(bot: Bot, api: str, data: Dict[str, Any]):
|
||||
async def _(bot: Bot, api: str, data: Dict[str, Any]):
|
||||
r = None
|
||||
if (
|
||||
(
|
||||
|
||||
@@ -14,7 +14,6 @@ from .check_plugin_status import check_plugin_status
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from configs.path_config import DATA_PATH
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
from nonebot import Driver
|
||||
import nonebot
|
||||
|
||||
@@ -28,7 +27,7 @@ driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
def _():
|
||||
async def _():
|
||||
"""
|
||||
初始化数据
|
||||
"""
|
||||
|
||||
@@ -5,7 +5,6 @@ from utils.manager import (
|
||||
plugins2settings_manager,
|
||||
plugins2block_manager,
|
||||
plugins_manager,
|
||||
resources_manager
|
||||
)
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import asyncio
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
|
||||
from utils.manager import admin_manager, plugins_manager
|
||||
@@ -5,8 +7,8 @@ from configs.config import Config
|
||||
from services.log import logger
|
||||
from utils.text_utils import prompt2cn
|
||||
from utils.utils import get_matchers
|
||||
from utils.utils import scheduler
|
||||
from ruamel import yaml
|
||||
import nonebot
|
||||
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
@@ -21,23 +23,39 @@ def init_plugins_config(data_path):
|
||||
_data = {}
|
||||
if plugins2config_file.exists():
|
||||
_data = _yaml.load(open(plugins2config_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers()
|
||||
_matchers = get_matchers(True)
|
||||
# 优先使用 metadata 数据
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_plugin = matcher.plugin
|
||||
if not _plugin:
|
||||
continue
|
||||
metadata = _plugin.metadata
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
continue
|
||||
try:
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
except AttributeError:
|
||||
plugin_version = None
|
||||
try:
|
||||
plugin_configs = _module.__getattribute__("__plugin_configs__")
|
||||
except AttributeError:
|
||||
continue
|
||||
# 插件配置版本更新或为Version为None或不在存储配置内
|
||||
if (
|
||||
plugin_version = None
|
||||
if metadata:
|
||||
plugin_version = metadata.extra.get("version")
|
||||
if not plugin_version:
|
||||
try:
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
except AttributeError:
|
||||
pass
|
||||
if metadata and metadata.config:
|
||||
plugin_configs = {}
|
||||
for key, value in metadata.config.__fields__.items():
|
||||
plugin_configs[key.upper()] = {
|
||||
"value": value.default,
|
||||
"default_value": value.default
|
||||
}
|
||||
else:
|
||||
try:
|
||||
plugin_configs = _module.__getattribute__("__plugin_configs__")
|
||||
except AttributeError:
|
||||
continue
|
||||
# 插件配置版本更新或为Version为None或不在存储配置内,当使用metadata时,必定更新
|
||||
if isinstance(plugin_version, str) or (
|
||||
plugin_version is None
|
||||
or (
|
||||
_data.get(matcher.plugin_name)
|
||||
@@ -91,78 +109,96 @@ def init_plugins_config(data_path):
|
||||
round_trip_dump(
|
||||
_data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
# 再开始读取用户配置
|
||||
user_config_file = Path() / "configs" / "config.yaml"
|
||||
_data = {}
|
||||
_tmp_data = {}
|
||||
if user_config_file.exists():
|
||||
with open(user_config_file, "r", encoding="utf8") as f:
|
||||
_data = _yaml.load(f)
|
||||
# 数据替换
|
||||
for plugin in Config.keys():
|
||||
_tmp_data[plugin] = {}
|
||||
for k in Config[plugin].keys():
|
||||
try:
|
||||
if _data.get(plugin) and k in _data[plugin].keys():
|
||||
Config.set_config(plugin, k, _data[plugin][k])
|
||||
if level2module := Config.get_level2module(plugin, k):
|
||||
try:
|
||||
admin_manager.set_admin_level(
|
||||
level2module, _data[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()
|
||||
temp_file = Path() / "configs" / "temp_config.yaml"
|
||||
try:
|
||||
with open(temp_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(
|
||||
_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
with open(temp_file, "r", encoding="utf8") as rf:
|
||||
_data = round_trip_load(rf)
|
||||
# 添加注释
|
||||
for plugin in _data.keys():
|
||||
rst = ""
|
||||
plugin_name = None
|
||||
try:
|
||||
plugin_data = Config.get(plugin)
|
||||
for x in list(Config.get(plugin).keys()):
|
||||
user_config_file = Path() / "configs" / "config.yaml"
|
||||
# if not user_config_file.exists():
|
||||
_replace_config()
|
||||
# else:
|
||||
# logger.info('五分钟后将进行配置数据替换,请注意...')
|
||||
# scheduler.add_job(
|
||||
# _replace_config,
|
||||
# "date",
|
||||
# run_date=datetime.now() + timedelta(minutes=5),
|
||||
# id=f"_replace_config"
|
||||
# )
|
||||
|
||||
|
||||
def _replace_config():
|
||||
"""
|
||||
说明:
|
||||
定时任务加载的配置读取替换
|
||||
"""
|
||||
# 再开始读取用户配置
|
||||
user_config_file = Path() / "configs" / "config.yaml"
|
||||
_data = {}
|
||||
_tmp_data = {}
|
||||
if user_config_file.exists():
|
||||
with open(user_config_file, "r", encoding="utf8") as f:
|
||||
_data = _yaml.load(f)
|
||||
# 数据替换
|
||||
for plugin in Config.keys():
|
||||
_tmp_data[plugin] = {}
|
||||
for k in Config[plugin].keys():
|
||||
try:
|
||||
if _data.get(plugin) and k in _data[plugin].keys():
|
||||
Config.set_config(plugin, k, _data[plugin][k])
|
||||
if level2module := Config.get_level2module(plugin, k):
|
||||
try:
|
||||
_x = plugin_data[x].get("name")
|
||||
if _x:
|
||||
plugin_name = _x
|
||||
except AttributeError:
|
||||
pass
|
||||
except (KeyError, AttributeError):
|
||||
plugin_name = None
|
||||
if not plugin_name:
|
||||
admin_manager.set_admin_level(
|
||||
level2module, _data[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()
|
||||
temp_file = Path() / "configs" / "temp_config.yaml"
|
||||
try:
|
||||
with open(temp_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(
|
||||
_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
with open(temp_file, "r", encoding="utf8") as rf:
|
||||
_data = round_trip_load(rf)
|
||||
# 添加注释
|
||||
for plugin in _data.keys():
|
||||
rst = ""
|
||||
plugin_name = None
|
||||
try:
|
||||
plugin_data = Config.get(plugin)
|
||||
for x in list(Config.get(plugin).keys()):
|
||||
try:
|
||||
plugin_name = plugins_manager.get(plugin)["plugin_name"]
|
||||
except (AttributeError, TypeError):
|
||||
plugin_name = plugin
|
||||
plugin_name = (
|
||||
plugin_name.replace("[Hidden]", "")
|
||||
.replace("[Superuser]", "")
|
||||
.replace("[Admin]", "")
|
||||
.strip()
|
||||
)
|
||||
rst += plugin_name + "\n"
|
||||
for k in _data[plugin].keys():
|
||||
rst += f'{k}: {Config[plugin][k]["help"]}' + "\n"
|
||||
_data[plugin].yaml_set_start_comment(rst[:-1], indent=2)
|
||||
with open(Path() / "configs" / "config.yaml", "w", encoding="utf8") as wf:
|
||||
round_trip_dump(
|
||||
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"生成简易配置注释错误 {type(e)}:{e}")
|
||||
if temp_file.exists():
|
||||
temp_file.unlink()
|
||||
_x = plugin_data[x].get("name")
|
||||
if _x:
|
||||
plugin_name = _x
|
||||
except AttributeError:
|
||||
pass
|
||||
except (KeyError, AttributeError):
|
||||
plugin_name = None
|
||||
if not plugin_name:
|
||||
try:
|
||||
plugin_name = plugins_manager.get(plugin)["plugin_name"]
|
||||
except (AttributeError, TypeError):
|
||||
plugin_name = plugin
|
||||
plugin_name = (
|
||||
plugin_name.replace("[Hidden]", "")
|
||||
.replace("[Superuser]", "")
|
||||
.replace("[Admin]", "")
|
||||
.strip()
|
||||
)
|
||||
rst += plugin_name + "\n"
|
||||
for k in _data[plugin].keys():
|
||||
rst += f'{k}: {Config[plugin][k]["help"]}' + "\n"
|
||||
_data[plugin].yaml_set_start_comment(rst[:-1], indent=2)
|
||||
with open(Path() / "configs" / "config.yaml", "w", encoding="utf8") as wf:
|
||||
round_trip_dump(
|
||||
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"生成简易配置注释错误 {type(e)}:{e}")
|
||||
if temp_file.exists():
|
||||
temp_file.unlink()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from pathlib import Path
|
||||
|
||||
from ruamel.yaml import YAML
|
||||
from utils.manager import plugins_manager
|
||||
from utils.utils import get_matchers
|
||||
import nonebot
|
||||
from services.log import logger
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
@@ -22,9 +22,12 @@ def init_plugins_data(data_path):
|
||||
_data = {}
|
||||
if plugin2data_file.exists():
|
||||
_data = json.load(open(plugin2data_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers()
|
||||
_matchers = get_matchers(True)
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_plugin = matcher.plugin
|
||||
if not _plugin:
|
||||
continue
|
||||
metadata = _plugin.metadata
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
@@ -41,42 +44,56 @@ def init_plugins_data(data_path):
|
||||
)
|
||||
else:
|
||||
try:
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
except AttributeError:
|
||||
plugin_version = None
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
except AttributeError:
|
||||
plugin_name = matcher.plugin_name
|
||||
try:
|
||||
plugin_author = _module.__getattribute__("__plugin_author__")
|
||||
except AttributeError:
|
||||
if metadata:
|
||||
plugin_version = metadata.extra.get("version")
|
||||
if not plugin_version:
|
||||
try:
|
||||
plugin_version = _module.__getattribute__("__plugin_version__")
|
||||
except AttributeError:
|
||||
pass
|
||||
if metadata:
|
||||
plugin_name = metadata.name
|
||||
else:
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
except AttributeError:
|
||||
plugin_name = matcher.plugin_name
|
||||
plugin_author = None
|
||||
if matcher.plugin_name in plugins_manager.keys():
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "error", False)
|
||||
if matcher.plugin_name not in plugins_manager.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.plugin_name,
|
||||
plugin_name=plugin_name,
|
||||
author=plugin_author,
|
||||
version=plugin_version,
|
||||
)
|
||||
elif plugins_manager[matcher.plugin_name]["version"] is None or (
|
||||
plugin_version is not None
|
||||
and plugin_version > plugins_manager[matcher.plugin_name]["version"]
|
||||
):
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "plugin_name", plugin_name
|
||||
)
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "author", plugin_author)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "version", plugin_version
|
||||
)
|
||||
if matcher.plugin_name in _data.keys():
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
|
||||
)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
|
||||
)
|
||||
if metadata:
|
||||
plugin_author = metadata.extra.get('author')
|
||||
try:
|
||||
plugin_author = _module.__getattribute__("__plugin_author__")
|
||||
except AttributeError:
|
||||
pass
|
||||
if matcher.plugin_name in plugins_manager.keys():
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "error", False)
|
||||
if matcher.plugin_name not in plugins_manager.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.plugin_name,
|
||||
plugin_name=plugin_name,
|
||||
author=plugin_author,
|
||||
version=plugin_version,
|
||||
)
|
||||
# metadata不检测version
|
||||
elif isinstance(plugin_version, str) or plugins_manager[matcher.plugin_name]["version"] is None or (
|
||||
plugin_version is not None
|
||||
and plugin_version > float(plugins_manager[matcher.plugin_name]["version"])
|
||||
):
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "plugin_name", plugin_name
|
||||
)
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "author", plugin_author)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "version", plugin_version
|
||||
)
|
||||
if matcher.plugin_name in _data.keys():
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
|
||||
)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"插件数据 {matcher.plugin_name} 加载发生错误 {type(e)}:{e}")
|
||||
plugins_manager.save()
|
||||
|
||||
@@ -26,18 +26,8 @@ def init_plugins_resources():
|
||||
else:
|
||||
path = Path(_module.__getattribute__("__file__")).parent
|
||||
for resource in resources.keys():
|
||||
resources_manager.add_resource(matcher.plugin_name, path / resource, resources[resource])
|
||||
resources_manager.add_resource(
|
||||
matcher.plugin_name, path / resource, resources[resource]
|
||||
)
|
||||
resources_manager.save()
|
||||
resources_manager.start_move()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -16,63 +16,77 @@ def init_plugins_settings(data_path: str):
|
||||
"""
|
||||
plugins2settings_file = data_path / "configs" / "plugins2settings.yaml"
|
||||
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_matchers = get_matchers()
|
||||
_matchers = get_matchers(True)
|
||||
_tmp_module = {}
|
||||
_tmp = []
|
||||
for x in plugins2settings_manager.keys():
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(x)
|
||||
_module = _plugin.module
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
metadata = _plugin.metadata
|
||||
plugin_name = (
|
||||
metadata.name
|
||||
if metadata
|
||||
else _module.__getattribute__("__zx_plugin_name__")
|
||||
)
|
||||
_tmp_module[x] = plugin_name
|
||||
except (KeyError, AttributeError) as e:
|
||||
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
|
||||
_tmp_module[x] = ""
|
||||
for matcher in _matchers:
|
||||
if matcher.plugin_name not in plugins2settings_manager.keys():
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
|
||||
else:
|
||||
try:
|
||||
if matcher.plugin_name not in plugins2settings_manager.keys():
|
||||
_plugin = matcher.plugin
|
||||
if not _plugin:
|
||||
continue
|
||||
metadata = _plugin.metadata
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if "[admin]" in plugin_name.lower():
|
||||
try:
|
||||
admin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
level = admin_settings["admin_level"]
|
||||
cmd = admin_settings.get("cmd")
|
||||
except (AttributeError, KeyError):
|
||||
level = 5
|
||||
cmd = None
|
||||
if level is None:
|
||||
level = 5
|
||||
admin_manager.add_admin_plugin_settings(
|
||||
matcher.plugin_name, cmd, level
|
||||
)
|
||||
if (
|
||||
"[hidden]" in plugin_name.lower()
|
||||
or "[admin]" in plugin_name.lower()
|
||||
or "[superuser]" in plugin_name.lower()
|
||||
or matcher.plugin_name in plugins2settings_manager.keys()
|
||||
):
|
||||
continue
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
if matcher.plugin_name not in _tmp:
|
||||
logger.warning(
|
||||
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||
)
|
||||
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
|
||||
else:
|
||||
try:
|
||||
if metadata:
|
||||
plugin_name = metadata.name
|
||||
else:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if "[admin]" in plugin_name.lower():
|
||||
try:
|
||||
admin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
level = admin_settings["admin_level"]
|
||||
cmd = admin_settings.get("cmd")
|
||||
except (AttributeError, KeyError):
|
||||
level = 5
|
||||
cmd = None
|
||||
if level is None:
|
||||
level = 5
|
||||
admin_manager.add_admin_plugin_settings(
|
||||
matcher.plugin_name, cmd, level
|
||||
)
|
||||
if (
|
||||
"[hidden]" in plugin_name.lower()
|
||||
or "[admin]" in plugin_name.lower()
|
||||
or "[superuser]" in plugin_name.lower()
|
||||
or matcher.plugin_name in plugins2settings_manager.keys()
|
||||
):
|
||||
continue
|
||||
except AttributeError:
|
||||
if matcher.plugin_name not in _tmp:
|
||||
logger.warning(
|
||||
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||
)
|
||||
else:
|
||||
_tmp_module[matcher.plugin_name] = plugin_name
|
||||
plugin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
if plugin_settings.get('cost_gold') is None:
|
||||
plugin_settings['cost_gold'] = 0
|
||||
try:
|
||||
plugin_settings = _module.__getattribute__(
|
||||
"__plugin_settings__"
|
||||
)
|
||||
except AttributeError:
|
||||
plugin_settings = {"cmd": [matcher.plugin_name, plugin_name]}
|
||||
if not plugin_settings.get("cost_gold"):
|
||||
plugin_settings["cost_gold"] = 0
|
||||
if (
|
||||
plugin_settings.get("cmd") is not None
|
||||
and plugin_name not in plugin_settings["cmd"]
|
||||
@@ -90,9 +104,7 @@ def init_plugins_settings(data_path: str):
|
||||
)
|
||||
else:
|
||||
try:
|
||||
plugin_type = _module.__getattribute__(
|
||||
"__plugin_type__"
|
||||
)
|
||||
plugin_type = _module.__getattribute__("__plugin_type__")
|
||||
except AttributeError:
|
||||
plugin_type = ("normal",)
|
||||
if plugin_settings and matcher.plugin_name:
|
||||
@@ -101,8 +113,8 @@ def init_plugins_settings(data_path: str):
|
||||
plugin_type=plugin_type,
|
||||
**plugin_settings,
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.error(f'{matcher.plugin_name} 初始化 plugin_settings 发生错误 {type(e)}:{e}')
|
||||
_tmp.append(matcher.plugin_name)
|
||||
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
|
||||
with open(plugins2settings_file, "w", encoding="utf8") as wf:
|
||||
|
||||
@@ -25,7 +25,7 @@ __plugin_configs__ = {
|
||||
|
||||
friend_req = on_request(priority=5, block=True)
|
||||
group_req = on_request(priority=5, block=True)
|
||||
x = on_message(priority=999, block=False)
|
||||
x = on_message(priority=999, block=False, rule=lambda: False)
|
||||
|
||||
exists_data = {"private": {}, "group": {}}
|
||||
|
||||
|
||||
+21
-26
@@ -1,3 +1,5 @@
|
||||
import random
|
||||
|
||||
from asyncpg.exceptions import (
|
||||
DuplicateColumnError,
|
||||
UndefinedColumnError,
|
||||
@@ -13,6 +15,7 @@ from configs.path_config import TEXT_PATH
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from typing import List
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.utils import GDict
|
||||
from utils.utils import scheduler
|
||||
import nonebot
|
||||
|
||||
@@ -108,6 +111,18 @@ async def _():
|
||||
"ALTER TABLE genshin ADD bind_group Integer;",
|
||||
"genshin"
|
||||
), # 新增原神群号绑定字段
|
||||
(
|
||||
"ALTER TABLE genshin ADD login_ticket VARCHAR(255) DEFAULT '';",
|
||||
"genshin"
|
||||
), # 新增米游社login_ticket绑定字段
|
||||
(
|
||||
"ALTER TABLE genshin ADD stuid VARCHAR(255) DEFAULT '';",
|
||||
"genshin"
|
||||
), # 新增米游社stuid绑定字段
|
||||
(
|
||||
"ALTER TABLE genshin ADD stoken VARCHAR(255) DEFAULT '';",
|
||||
"genshin"
|
||||
), # 新增米游社stoken绑定字段
|
||||
(
|
||||
"ALTER TABLE chat_history ADD plain_text Text;",
|
||||
"chat_history"
|
||||
@@ -121,10 +136,13 @@ async def _():
|
||||
"goods_info"
|
||||
), # 新增纯文本
|
||||
]
|
||||
for sql in sql_str:
|
||||
for sql in sql_str + GDict.get('run_sql', []):
|
||||
try:
|
||||
flag = sql[1]
|
||||
sql = sql[0]
|
||||
if isinstance(sql, str):
|
||||
flag = f'{random.randint(1, 10000)}'
|
||||
else:
|
||||
flag = sql[1]
|
||||
sql = sql[0]
|
||||
query = db.text(sql)
|
||||
await db.first(query)
|
||||
logger.info(f"完成sql操作:{sql}")
|
||||
@@ -136,29 +154,6 @@ async def _():
|
||||
# bag_user 将文本转为字典格式
|
||||
await __database_script(_flag)
|
||||
|
||||
# 完成后
|
||||
end_sql_str = [
|
||||
# "ALTER TABLE bag_users DROP COLUMN props;" # 删除 bag_users 的 props 字段(还不到时候)
|
||||
]
|
||||
for sql in end_sql_str:
|
||||
try:
|
||||
query = db.text(sql)
|
||||
await db.first(query)
|
||||
logger.info(f"完成执行sql操作:{sql}")
|
||||
except (DuplicateColumnError, UndefinedColumnError):
|
||||
pass
|
||||
except PostgresSyntaxError:
|
||||
logger.error(f"语法错误:执行sql失败:{sql}")
|
||||
|
||||
# str2json_sql = ["alter table bag_users alter COLUMN props type json USING props::json;"] # 字段类型替换
|
||||
# rename_sql = 'alter table {} rename {} to {};' # 字段更名
|
||||
# for sql in str2json_sql:
|
||||
# try:
|
||||
# query = db.text(sql)
|
||||
# await db.first(query)
|
||||
# except DuplicateColumnError:
|
||||
# pass
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _(bot: Bot):
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from nonebot import on_command
|
||||
|
||||
from models.user_shop_gold_log import UserShopGoldLog
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
@@ -46,10 +48,7 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
for x in await GoodsInfo.get_all_goods()
|
||||
if x.goods_limit_time > time.time() or x.goods_limit_time == 0
|
||||
]
|
||||
goods_name_list = [
|
||||
x.goods_name
|
||||
for x in goods_list
|
||||
]
|
||||
goods_name_list = [x.goods_name for x in goods_list]
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
@@ -77,11 +76,15 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num * goods.goods_discount:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
flag, n = await GoodsInfo.check_user_daily_purchase(goods, event.user_id, event.group_id, num)
|
||||
flag, n = await GoodsInfo.check_user_daily_purchase(
|
||||
goods, event.user_id, event.group_id, num
|
||||
)
|
||||
if flag:
|
||||
await buy.finish(f"该次购买将超过每日次数限制,目前该道具还可以购买{n}次哦", at_sender=True)
|
||||
if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
|
||||
await GoodsInfo.add_user_daily_purchase(goods, event.user_id, event.group_id, num)
|
||||
await GoodsInfo.add_user_daily_purchase(
|
||||
goods, event.user_id, event.group_id, num
|
||||
)
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
@@ -90,6 +93,14 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
f"USER {event.user_id} GROUP {event.group_id} "
|
||||
f"花费 {goods.goods_price*num} 金币购买 {goods.goods_name} ×{num} 成功!"
|
||||
)
|
||||
await UserShopGoldLog.add_shop_log(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
0,
|
||||
goods.goods_name,
|
||||
num,
|
||||
goods.goods_price * num * goods.goods_discount,
|
||||
)
|
||||
else:
|
||||
await buy.send(f"{goods.goods_name} 购买失败!", at_sender=True)
|
||||
logger.info(
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
from nonebot import on_command
|
||||
|
||||
from utils.message_builder import image
|
||||
from ._data_source import create_bag_image
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from models.bag_user import BagUser
|
||||
@@ -32,10 +35,11 @@ my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
async def _(event: GroupMessageEvent):
|
||||
props = await BagUser.get_property(event.user_id, event.group_id)
|
||||
if props:
|
||||
rst = ""
|
||||
for i, p in enumerate(props.keys()):
|
||||
rst += f"{i+1}.{p}\t×{props[p]}\n"
|
||||
await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
await my_props.send(image(b64=await create_bag_image(props)))
|
||||
# rst = ""
|
||||
# for i, p in enumerate(props.keys()):
|
||||
# rst += f"{i+1}.{p}\t×{props[p]}\n"
|
||||
# await my_props.send("\n" + rst[:-1], at_sender=True)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具")
|
||||
else:
|
||||
await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True)
|
||||
@@ -0,0 +1,121 @@
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from models.bag_user import BagUser
|
||||
from models.goods_info import GoodsInfo
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
|
||||
|
||||
icon_path = IMAGE_PATH / "shop_icon"
|
||||
|
||||
|
||||
async def create_bag_image(props: Dict[str, int]):
|
||||
"""
|
||||
说明:
|
||||
创建背包道具图片
|
||||
参数:
|
||||
:param props: 道具仓库字典
|
||||
"""
|
||||
goods_list = await GoodsInfo.get_all_goods()
|
||||
active_props = await _init_prop(props, [x for x in goods_list if not x.is_passive])
|
||||
passive_props = await _init_prop(props, [x for x in goods_list if x.is_passive])
|
||||
active_w = 0
|
||||
active_h = 0
|
||||
passive_w = 0
|
||||
passive_h = 0
|
||||
if active_props:
|
||||
img = BuildImage(
|
||||
active_props.w,
|
||||
active_props.h + 70,
|
||||
font="CJGaoDeGuo.otf",
|
||||
font_size=30,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
await img.apaste(active_props, (0, 70))
|
||||
await img.atext((0, 30), "主动道具")
|
||||
active_props = img
|
||||
active_w = img.w
|
||||
active_h = img.h
|
||||
if passive_props:
|
||||
img = BuildImage(
|
||||
passive_props.w,
|
||||
passive_props.h + 70,
|
||||
font="CJGaoDeGuo.otf",
|
||||
font_size=30,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
await img.apaste(passive_props, (0, 70))
|
||||
await img.atext((0, 30), "被动道具")
|
||||
passive_props = img
|
||||
passive_w = img.w
|
||||
passive_h = img.h
|
||||
A = BuildImage(
|
||||
active_w + passive_w + 100,
|
||||
max(active_h, passive_h) + 60,
|
||||
font="CJGaoDeGuo.otf",
|
||||
font_size=30,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
curr_w = 50
|
||||
if active_props:
|
||||
await A.apaste(active_props, (curr_w, 0))
|
||||
curr_w += active_props.w + 10
|
||||
if passive_props:
|
||||
await A.apaste(passive_props, (curr_w, 0))
|
||||
if active_props and passive_props:
|
||||
await A.aline(
|
||||
(active_props.w + 45, 70, active_props.w + 45, A.h - 20), fill=(0, 0, 0)
|
||||
)
|
||||
return A.pic2bs4()
|
||||
|
||||
|
||||
async def _init_prop(
|
||||
props: Dict[str, int], _props: List[GoodsInfo]
|
||||
) -> Optional[BuildImage]:
|
||||
"""
|
||||
说明:
|
||||
构造道具列表图片
|
||||
参数:
|
||||
:param props: 道具仓库字典
|
||||
:param _props: 道具列表
|
||||
"""
|
||||
active_name = [x.goods_name for x in _props]
|
||||
name_list = [x for x in props.keys() if x in active_name]
|
||||
if not name_list:
|
||||
return None
|
||||
temp_img = BuildImage(0, 0, font_size=20)
|
||||
image_list = []
|
||||
num_list = []
|
||||
for i, name in enumerate(name_list):
|
||||
img = BuildImage(
|
||||
temp_img.getsize(name)[0] + 50,
|
||||
30,
|
||||
font="msyh.ttf",
|
||||
font_size=20,
|
||||
color="#f9f6f2",
|
||||
)
|
||||
await img.atext((30, 5), f"{i + 1}.{name}")
|
||||
goods = [x for x in _props if x.goods_name == name][0]
|
||||
if goods.icon and (icon_path / goods.icon).exists():
|
||||
icon = BuildImage(30, 30, background=icon_path / goods.icon)
|
||||
await img.apaste(icon, alpha=True)
|
||||
image_list.append(img)
|
||||
num_list.append(
|
||||
BuildImage(
|
||||
30, 30, font_size=20, font="msyh.ttf", plain_text=f"×{props[name]}"
|
||||
)
|
||||
)
|
||||
max_w = 0
|
||||
num_max_w = 0
|
||||
h = 0
|
||||
for img, num in zip(image_list, num_list):
|
||||
h += img.h
|
||||
max_w = max_w if max_w > img.w else img.w
|
||||
num_max_w = num_max_w if num_max_w > num.w else num.w
|
||||
A = BuildImage(max_w + num_max_w + 30, h, color="#f9f6f2")
|
||||
curr_h = 0
|
||||
for img, num in zip(image_list, num_list):
|
||||
await A.apaste(img, (0, curr_h))
|
||||
await A.apaste(num, (max_w + 20, curr_h + 5), True)
|
||||
curr_h += img.h
|
||||
return A
|
||||
@@ -6,7 +6,6 @@ from utils.message_builder import image
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import is_number, scheduler
|
||||
from nonebot.params import CommandArg
|
||||
from nonebot.plugin import export
|
||||
from services.log import logger
|
||||
import os
|
||||
|
||||
@@ -51,11 +50,6 @@ __plugin_block_limit__ = {
|
||||
"limit_type": "group"
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.register_goods = register_goods
|
||||
export.delete_goods = delete_goods
|
||||
export.update_goods = update_goods
|
||||
|
||||
shop_help = on_command("商店", priority=5, block=True)
|
||||
|
||||
|
||||
@@ -2,49 +2,17 @@ from PIL import Image
|
||||
|
||||
from models.goods_info import GoodsInfo
|
||||
from utils.image_utils import BuildImage
|
||||
from models.sign_group_user import SignGroupUser
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional, Union, Tuple
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
from nonebot.plugin import require
|
||||
from utils.decorator.shop import shop_register
|
||||
import nonebot
|
||||
from utils.utils import GDict
|
||||
import time
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
icon_path = IMAGE_PATH / 'shop_icon'
|
||||
|
||||
|
||||
use = require("use")
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def init_default_shop_goods():
|
||||
"""
|
||||
导入内置的三个商品
|
||||
"""
|
||||
|
||||
@shop_register(
|
||||
name=("好感度双倍加持卡Ⅰ", "好感度双倍加持卡Ⅱ", "好感度双倍加持卡Ⅲ"),
|
||||
price=(30, 150, 250),
|
||||
des=(
|
||||
"下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
|
||||
"下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)",
|
||||
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
|
||||
),
|
||||
load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
|
||||
daily_limit=(10, 20, 30),
|
||||
** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
|
||||
)
|
||||
async def sign_card(user_id: int, group_id: int, prob: float):
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=prob).apply()
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _():
|
||||
await shop_register.load_register()
|
||||
GDict['run_sql'].append("ALTER TABLE goods_info ADD is_passive boolean DEFAULT False;")
|
||||
GDict['run_sql'].append("ALTER TABLE goods_info ADD icon VARCHAR(255);")
|
||||
|
||||
|
||||
# 创建商店界面
|
||||
@@ -63,7 +31,7 @@ async def create_shop_help() -> str:
|
||||
if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time:
|
||||
h += len(goods.goods_description.strip().split("\n")) * font_h + 80
|
||||
_list.append(goods)
|
||||
A = BuildImage(1000, h, color="#f9f6f2")
|
||||
A = BuildImage(1100, h, color="#f9f6f2")
|
||||
current_h = 0
|
||||
total_n = 0
|
||||
for goods in _list:
|
||||
@@ -106,9 +74,12 @@ async def create_shop_help() -> str:
|
||||
await goods_image.apaste(name_image, (0, 5), True, center_type="by_width")
|
||||
await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
|
||||
await goods_image.acircle_corner(20)
|
||||
await bk.apaste(goods_image, alpha=True)
|
||||
if goods.icon and (icon_path / goods.icon).exists():
|
||||
icon = BuildImage(100, 100, background=icon_path / goods.icon)
|
||||
await bk.apaste(icon)
|
||||
await bk.apaste(goods_image, (100, 0), alpha=True)
|
||||
n = 0
|
||||
_w = 550
|
||||
_w = 650
|
||||
# 添加限时图标和时间
|
||||
if goods.goods_limit_time > 0:
|
||||
n += 140
|
||||
@@ -162,14 +133,14 @@ async def create_shop_help() -> str:
|
||||
if total_n < n:
|
||||
total_n = n
|
||||
if n:
|
||||
await bk.aline((550, -1, 550 + n, -1), "#a29ad6", 5)
|
||||
await bk.aline((550, 80, 550 + n, 80), "#a29ad6", 5)
|
||||
await bk.aline((650, -1, 650 + n, -1), "#a29ad6", 5)
|
||||
await bk.aline((650, 80, 650 + n, 80), "#a29ad6", 5)
|
||||
|
||||
# 添加限时图标和时间
|
||||
idx += 1
|
||||
await A.apaste(bk, (0, current_h), True)
|
||||
current_h += 90
|
||||
w = 850
|
||||
w = 950
|
||||
if total_n:
|
||||
w += total_n
|
||||
h = A.h + 230 + 100
|
||||
@@ -197,6 +168,8 @@ async def register_goods(
|
||||
discount: Optional[float] = 1,
|
||||
limit_time: Optional[int] = 0,
|
||||
daily_limit: Optional[int] = 0,
|
||||
is_passive: Optional[bool] = False,
|
||||
icon: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
添加商品
|
||||
@@ -209,6 +182,8 @@ async def register_goods(
|
||||
:param discount: 商品折扣
|
||||
:param limit_time: 商品限时销售时间,单位为小时
|
||||
:param daily_limit: 每日购买次数限制
|
||||
:param is_passive: 是否为被动
|
||||
:param icon: 图标
|
||||
:return: 是否添加成功
|
||||
"""
|
||||
if not await GoodsInfo.get_goods_info(name):
|
||||
@@ -220,7 +195,7 @@ async def register_goods(
|
||||
else 0
|
||||
)
|
||||
return await GoodsInfo.add_goods(
|
||||
name, int(price), des, float(discount), limit_time, daily_limit
|
||||
name, int(price), des, float(discount), limit_time, daily_limit, is_passive, icon
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -272,6 +247,7 @@ async def update_goods(**kwargs) -> Tuple[bool, str, str]:
|
||||
discount = goods.goods_discount
|
||||
limit_time = goods.goods_limit_time
|
||||
daily_limit = goods.daily_limit
|
||||
is_passive = goods.is_passive
|
||||
new_time = 0
|
||||
tmp = ""
|
||||
if kwargs.get("price"):
|
||||
@@ -294,6 +270,9 @@ async def update_goods(**kwargs) -> Tuple[bool, str, str]:
|
||||
if kwargs.get("daily_limit"):
|
||||
tmp += f'每日购买限制:{daily_limit} --> {kwargs["daily_limit"]}\n' if daily_limit else "取消了购买限制\n"
|
||||
daily_limit = int(kwargs["daily_limit"])
|
||||
if kwargs.get("is_passive"):
|
||||
tmp += f'被动道具:{is_passive} --> {kwargs["is_passive"]}\n'
|
||||
des = kwargs["is_passive"]
|
||||
await GoodsInfo.update_goods(
|
||||
name,
|
||||
int(price),
|
||||
@@ -304,7 +283,8 @@ async def update_goods(**kwargs) -> Tuple[bool, str, str]:
|
||||
if limit_time != 0 and new_time
|
||||
else 0
|
||||
),
|
||||
daily_limit
|
||||
daily_limit,
|
||||
is_passive
|
||||
)
|
||||
return True, name, tmp[:-1],
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
from nonebot import on_command
|
||||
|
||||
from models.user_shop_gold_log import UserShopGoldLog
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
|
||||
from utils.decorator.shop import NotMeetUseConditionsException
|
||||
from utils.utils import is_number
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from services.db_context import db
|
||||
from nonebot.plugin import export
|
||||
from .data_source import effect, register_use, func_manager
|
||||
from .data_source import effect, register_use, func_manager, build_params
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 使用道具"
|
||||
@@ -30,9 +33,6 @@ __plugin_settings__ = {
|
||||
"cmd": ["商店", "使用道具"],
|
||||
}
|
||||
|
||||
# 导出方法供其他插件使用
|
||||
export = export()
|
||||
export.register_use = register_use
|
||||
|
||||
use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
@@ -45,23 +45,29 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
if len(msg_sp) > 1 and is_number(msg_sp[-1]) and int(msg_sp[-1]) > 0:
|
||||
num = int(msg.split()[-1])
|
||||
msg = " ".join(msg.split()[:-1])
|
||||
property_ = await BagUser.get_property(event.user_id, event.group_id)
|
||||
property_ = await BagUser.get_property(event.user_id, event.group_id, True)
|
||||
if property_:
|
||||
async with db.transaction():
|
||||
if is_number(msg):
|
||||
if 0 < int(msg) <= len(property_):
|
||||
name = list(property_.keys())[int(msg) - 1]
|
||||
else:
|
||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||
name = None
|
||||
if is_number(msg):
|
||||
if 0 < int(msg) <= len(property_):
|
||||
name = list(property_.keys())[int(msg) - 1]
|
||||
else:
|
||||
if msg not in property_.keys():
|
||||
await use_props.finish("道具名称错误!", at_sender=True)
|
||||
name = msg
|
||||
_user_prop_count = property_[name]
|
||||
if num > _user_prop_count:
|
||||
await use_props.finish(f"道具数量不足,无法使用{num}次!")
|
||||
if num > (n := func_manager.get_max_num_limit(name)):
|
||||
await use_props.finish(f"该道具单次只能使用 {n} 个!")
|
||||
await use_props.finish("仔细看看自己的道具仓库有没有这个道具?", at_sender=True)
|
||||
else:
|
||||
if msg not in property_.keys():
|
||||
await use_props.finish("道具名称错误!", at_sender=True)
|
||||
name = msg
|
||||
_user_prop_count = property_[name]
|
||||
if num > _user_prop_count:
|
||||
await use_props.finish(f"道具数量不足,无法使用{num}次!")
|
||||
if num > (n := func_manager.get_max_num_limit(name)):
|
||||
await use_props.finish(f"该道具单次只能使用 {n} 个!")
|
||||
model, kwargs = build_params(bot, event, name, num)
|
||||
try:
|
||||
await func_manager.run_handle(type_="before_handle", param=model, **kwargs)
|
||||
except NotMeetUseConditionsException as e:
|
||||
await use_props.finish(e.get_info(), at_sender=True)
|
||||
async with db.transaction():
|
||||
if await BagUser.delete_property(
|
||||
event.user_id, event.group_id, name, num
|
||||
):
|
||||
@@ -72,10 +78,12 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次成功"
|
||||
)
|
||||
await UserShopGoldLog.add_shop_log(event.user_id, event.group_id, 1, name, num)
|
||||
else:
|
||||
await use_props.send(f"使用道具 {name} {num} 次失败!", at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次失败"
|
||||
)
|
||||
await func_manager.run_handle(type_="after_handle", param=model, **kwargs)
|
||||
else:
|
||||
await use_props.send("您的背包里没有任何的道具噢", at_sender=True)
|
||||
|
||||
@@ -3,7 +3,7 @@ from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from pydantic import create_model
|
||||
from utils.models import ShopParam
|
||||
from typing import Optional, Union
|
||||
from typing import Optional, Union, Callable, List, Tuple, Dict, Any
|
||||
from types import MappingProxyType
|
||||
import inspect
|
||||
import asyncio
|
||||
@@ -13,6 +13,30 @@ class GoodsUseFuncManager:
|
||||
def __init__(self):
|
||||
self._data = {}
|
||||
|
||||
def register_use_before_handle(self, goods_name: str, fun_list: List[Callable]):
|
||||
"""
|
||||
说明:
|
||||
注册商品使用前函数
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param fun_list: 函数列表
|
||||
"""
|
||||
if fun_list:
|
||||
self._data[goods_name]["before_handle"] = fun_list
|
||||
logger.info(f"register_use_before_handle 成功注册商品:{goods_name} 的{len(fun_list)}个使用前函数")
|
||||
|
||||
def register_use_after_handle(self, goods_name: str, fun_list: List[Callable]):
|
||||
"""
|
||||
说明:
|
||||
注册商品使用后函数
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param fun_list: 函数列表
|
||||
"""
|
||||
if fun_list:
|
||||
self._data[goods_name]["after_handle"] = fun_list
|
||||
logger.info(f"register_use_after_handle 成功注册商品:{goods_name} 的{len(fun_list)}个使用后函数")
|
||||
|
||||
def register_use(self, goods_name: str, **kwargs):
|
||||
"""
|
||||
注册商品使用方法
|
||||
@@ -26,7 +50,7 @@ class GoodsUseFuncManager:
|
||||
判断商品使用方法是否被注册
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
return bool(self ._data.get(goods_name))
|
||||
return bool(self._data.get(goods_name))
|
||||
|
||||
def get_max_num_limit(self, goods_name: str) -> int:
|
||||
"""
|
||||
@@ -37,6 +61,21 @@ class GoodsUseFuncManager:
|
||||
return self._data[goods_name]["kwargs"]["max_num_limit"]
|
||||
return 1
|
||||
|
||||
def _parse_args(self, args_: MappingProxyType, param: ShopParam, **kwargs):
|
||||
param_list_ = []
|
||||
_bot = param.bot
|
||||
param.bot = None
|
||||
param_json = param.dict()
|
||||
param_json["bot"] = _bot
|
||||
for par in args_.keys():
|
||||
if par in ["shop_param"]:
|
||||
param_list_.append(param)
|
||||
elif par not in ["args", "kwargs"]:
|
||||
param_list_.append(param_json.get(par))
|
||||
if kwargs.get(par) is not None:
|
||||
del kwargs[par]
|
||||
return param_list_
|
||||
|
||||
async def use(
|
||||
self, param: ShopParam, **kwargs
|
||||
) -> Optional[Union[str, MessageSegment]]:
|
||||
@@ -45,31 +84,18 @@ class GoodsUseFuncManager:
|
||||
:param param: BaseModel
|
||||
:param kwargs: kwargs
|
||||
"""
|
||||
def parse_args(args_: MappingProxyType):
|
||||
param_list_ = []
|
||||
_bot = param.bot
|
||||
param.bot = None
|
||||
param_json = param.dict()
|
||||
param_json["bot"] = _bot
|
||||
for par in args_.keys():
|
||||
if par in ["shop_param"]:
|
||||
param_list_.append(param)
|
||||
elif par not in ["args", "kwargs"]:
|
||||
param_list_.append(param_json.get(par))
|
||||
if kwargs.get(par) is not None:
|
||||
del kwargs[par]
|
||||
return param_list_
|
||||
goods_name = param.goods_name
|
||||
if self.exists(goods_name):
|
||||
# 使用方法
|
||||
args = inspect.signature(self._data[goods_name]["func"]).parameters
|
||||
if args and list(args.keys())[0] != "kwargs":
|
||||
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
|
||||
return await self._data[goods_name]["func"](
|
||||
*parse_args(args)
|
||||
*self._parse_args(args, param, **kwargs)
|
||||
)
|
||||
else:
|
||||
return self._data[goods_name]["func"](
|
||||
*parse_args(args)
|
||||
*self._parse_args(args, param, **kwargs)
|
||||
)
|
||||
else:
|
||||
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
|
||||
@@ -81,6 +107,21 @@ class GoodsUseFuncManager:
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
async def run_handle(self, goods_name: str, type_: str, param: ShopParam, **kwargs):
|
||||
if self._data[goods_name].get(type_):
|
||||
for func in self._data[goods_name].get(type_):
|
||||
args = inspect.signature(func).parameters
|
||||
if args and list(args.keys())[0] != "kwargs":
|
||||
if asyncio.iscoroutinefunction(func):
|
||||
await func(*self._parse_args(args, param, **kwargs))
|
||||
else:
|
||||
func(*self._parse_args(args, param, **kwargs))
|
||||
else:
|
||||
if asyncio.iscoroutinefunction(func):
|
||||
await func(**kwargs)
|
||||
else:
|
||||
func(**kwargs)
|
||||
|
||||
def check_send_success_message(self, goods_name: str) -> bool:
|
||||
"""
|
||||
检查是否发送使用成功信息
|
||||
@@ -115,6 +156,34 @@ class GoodsUseFuncManager:
|
||||
func_manager = GoodsUseFuncManager()
|
||||
|
||||
|
||||
def build_params(
|
||||
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int
|
||||
) -> Tuple[ShopParam, Dict[str, Any]]:
|
||||
"""
|
||||
说明:
|
||||
构造参数
|
||||
参数:
|
||||
:param bot: bot
|
||||
:param event: event
|
||||
:param goods_name: 商品名称
|
||||
:param num: 数量
|
||||
:return:
|
||||
"""
|
||||
_kwargs = func_manager.get_kwargs(goods_name)
|
||||
return (
|
||||
func_manager.init_model(goods_name, bot, event, num),
|
||||
{
|
||||
**_kwargs,
|
||||
"_bot": bot,
|
||||
"event": event,
|
||||
"group_id": event.group_id,
|
||||
"user_id": event.user_id,
|
||||
"num": num,
|
||||
"goods_name": goods_name,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def effect(
|
||||
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int
|
||||
) -> Optional[Union[str, MessageSegment]]:
|
||||
@@ -130,24 +199,14 @@ async def effect(
|
||||
# try:
|
||||
if func_manager.exists(goods_name):
|
||||
_kwargs = func_manager.get_kwargs(goods_name)
|
||||
return await func_manager.use(
|
||||
func_manager.init_model(goods_name, bot, event, num),
|
||||
**{
|
||||
**_kwargs,
|
||||
"_bot": bot,
|
||||
"event": event,
|
||||
"group_id": event.group_id,
|
||||
"user_id": event.user_id,
|
||||
"num": num,
|
||||
"goods_name": goods_name,
|
||||
},
|
||||
)
|
||||
model, kwargs = build_params(bot, event, goods_name, num)
|
||||
return await func_manager.use(model, **kwargs)
|
||||
# except Exception as e:
|
||||
# logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
|
||||
return None
|
||||
|
||||
|
||||
def register_use(goods_name: str, func, **kwargs):
|
||||
def register_use(goods_name: str, func: Callable, **kwargs):
|
||||
"""
|
||||
注册商品使用方法
|
||||
:param goods_name: 商品名称
|
||||
|
||||
+11
-10
@@ -94,13 +94,14 @@ class ConfigsManager:
|
||||
del self._data[module]
|
||||
self.save()
|
||||
|
||||
def set_config(self, module: str, key: str, value: Any , save_simple_data: bool = False):
|
||||
def set_config(self, module: str, key: str, value: Any, auto_save: bool = False, save_simple_data: bool = True):
|
||||
"""
|
||||
设置配置值
|
||||
:param module: 模块名
|
||||
:param key: 配置名称
|
||||
:param value: 值
|
||||
:param save_simple_data: 同时保存至config.yaml
|
||||
:param auto_save: 自动保存
|
||||
:param save_simple_data: 保存至config.yaml
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
if (
|
||||
@@ -109,7 +110,8 @@ class ConfigsManager:
|
||||
):
|
||||
self._data[module][key]["value"] = value
|
||||
self._simple_data[module][key] = value
|
||||
self.save(save_simple_data = save_simple_data)
|
||||
if auto_save:
|
||||
self.save(save_simple_data=save_simple_data)
|
||||
|
||||
def set_help(self, module: str, key: str, help_: str):
|
||||
"""
|
||||
@@ -200,13 +202,12 @@ class ConfigsManager:
|
||||
重新加载配置文件
|
||||
"""
|
||||
_yaml = YAML()
|
||||
temp_file = Path() / "configs" / "config.yaml"
|
||||
if temp_file.exists():
|
||||
with open(temp_file, "r", encoding="utf8") as f:
|
||||
temp = _yaml.load(f)
|
||||
for key in temp.keys():
|
||||
for k in temp[key].keys():
|
||||
self._data[key][k]["value"] = temp[key][k]
|
||||
if self._simple_file.exists():
|
||||
with open(self._simple_file, "r", encoding="utf8") as f:
|
||||
self._simple_data = _yaml.load(f)
|
||||
for key in self._simple_data.keys():
|
||||
for k in self._simple_data[key].keys():
|
||||
self._data[key][k]["value"] = self._simple_data[key][k]
|
||||
self.save()
|
||||
|
||||
def get_admin_level_data(self):
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 694 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 694 KiB After Width: | Height: | Size: 326 KiB |
+27
-19
@@ -2,6 +2,7 @@ from services.db_context import db
|
||||
from typing import Dict
|
||||
from typing import Optional, List
|
||||
from services.log import logger
|
||||
from .goods_info import GoodsInfo
|
||||
|
||||
|
||||
class BagUser(db.Model):
|
||||
@@ -22,9 +23,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取金币概况
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
@@ -44,9 +45,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def get_gold(cls, user_qq: int, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取当前金币
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
@@ -62,17 +63,24 @@ class BagUser(db.Model):
|
||||
return 100
|
||||
|
||||
@classmethod
|
||||
async def get_property(cls, user_qq: int, group_id: int) -> Dict[str, int]:
|
||||
async def get_property(cls, user_qq: int, group_id: int, only_active: bool = False) -> Dict[str, int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取当前道具
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param only_active: 仅仅获取主动使用的道具
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
if only_active and user.property:
|
||||
data = {}
|
||||
name_list = [x.goods_name for x in await GoodsInfo.get_all_goods() if not x.is_passive]
|
||||
for key in [x for x in user.property.keys() if x in name_list]:
|
||||
data[key] = user.property[key]
|
||||
return data
|
||||
return user.property
|
||||
else:
|
||||
await cls.create(
|
||||
@@ -84,9 +92,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def add_gold(cls, user_qq: int, group_id: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
增加金币
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param num: 金币数量
|
||||
@@ -112,9 +120,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def spend_gold(cls, user_qq: int, group_id: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
花费金币
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param num: 金币数量
|
||||
@@ -140,9 +148,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def add_property(cls, user_qq: int, group_id: int, name: str):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
增加道具
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param name: 道具名称
|
||||
@@ -165,9 +173,9 @@ class BagUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, name: str, num: int = 1
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
使用/删除 道具
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param name: 道具名称
|
||||
@@ -192,9 +200,9 @@ class BagUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
购买道具
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param group_id: 所在群聊
|
||||
:param goods: 商品
|
||||
@@ -214,9 +222,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def get_all_users(cls, group_id: Optional[int] = None) -> List["BagUser"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有用户数据
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if not group_id:
|
||||
|
||||
+12
-12
@@ -15,9 +15,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def check_ban_level(cls, user_qq: int, level: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测ban掉目标的用户与unban用户的权限等级大小
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: unban用户的qq号
|
||||
:param level: ban掉目标用户的权限等级
|
||||
"""
|
||||
@@ -31,9 +31,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def check_ban_time(cls, user_qq: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测用户被ban时长
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
@@ -49,9 +49,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def is_ban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
判断用户是否被ban
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
if await cls.check_ban_time(user_qq):
|
||||
@@ -63,9 +63,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def is_super_ban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
判断用户是否被ban
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
|
||||
@@ -77,9 +77,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
ban掉目标用户
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 目标用户qq号
|
||||
:param ban_level: 使用ban命令用户的权限
|
||||
:param duration: ban时长,秒
|
||||
@@ -104,9 +104,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def unban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
unban用户
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
|
||||
+18
-18
@@ -28,9 +28,9 @@ class ChatHistory(db.Model):
|
||||
days: Optional[int] = None,
|
||||
) -> List["ChatHistory"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户消息
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 用户qq
|
||||
:param msg_type: 消息类型,私聊或群聊
|
||||
:param days: 限制日期
|
||||
@@ -46,9 +46,9 @@ class ChatHistory(db.Model):
|
||||
date_scope: Tuple[datetime, datetime] = None,
|
||||
) -> List["ChatHistory"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群聊指定用户聊天记录
|
||||
参数:
|
||||
参数:
|
||||
:param uid: qq
|
||||
:param gid: 群号
|
||||
:param limit: 获取数量
|
||||
@@ -63,9 +63,9 @@ class ChatHistory(db.Model):
|
||||
@classmethod
|
||||
async def get_group_user_msg_count(cls, uid: int, gid: int) -> Optional[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查询群聊指定用户的聊天记录数量
|
||||
参数:
|
||||
参数:
|
||||
:param uid: qq
|
||||
:param gid: 群号
|
||||
"""
|
||||
@@ -86,9 +86,9 @@ class ChatHistory(db.Model):
|
||||
date_scope: Optional[Tuple[datetime, datetime]] = None,
|
||||
) -> Optional[Tuple[int, int]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取排行数据
|
||||
参数:
|
||||
参数:
|
||||
:param gid: 群号
|
||||
:param limit: 获取数量
|
||||
:param order: 排序类型,desc,des
|
||||
@@ -103,9 +103,9 @@ class ChatHistory(db.Model):
|
||||
@classmethod
|
||||
async def get_group_first_msg_datetime(cls, gid: int) -> Optional[datetime]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群第一条记录消息时间
|
||||
参数:
|
||||
参数:
|
||||
:param gid:
|
||||
"""
|
||||
if (
|
||||
@@ -124,9 +124,9 @@ class ChatHistory(db.Model):
|
||||
days: Optional[int] = None,
|
||||
) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户消息数量
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 用户qq
|
||||
:param msg_type: 消息类型,私聊或群聊
|
||||
:param days: 限制日期
|
||||
@@ -142,9 +142,9 @@ class ChatHistory(db.Model):
|
||||
days: Optional[int] = None,
|
||||
) -> List["ChatHistory"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群聊消息
|
||||
参数:
|
||||
参数:
|
||||
:param gid: 用户qq
|
||||
:param days: 限制日期
|
||||
"""
|
||||
@@ -157,9 +157,9 @@ class ChatHistory(db.Model):
|
||||
days: Optional[int] = None,
|
||||
) -> List["ChatHistory"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群聊消息数量
|
||||
参数:
|
||||
参数:
|
||||
:param gid: 用户qq
|
||||
:param days: 限制日期
|
||||
"""
|
||||
@@ -178,9 +178,9 @@ class ChatHistory(db.Model):
|
||||
is_select_count: bool = False,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取消息查询query
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 用户qq
|
||||
:param gid: 群号
|
||||
:param type_: 类型,私聊或群聊
|
||||
|
||||
+10
-10
@@ -15,9 +15,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_name(cls, user_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取好友用户名称
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
@@ -30,9 +30,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def add_friend_info(cls, user_id: int, user_name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加好友信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
:param user_name: 用户名称
|
||||
"""
|
||||
@@ -55,9 +55,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def delete_friend_info(cls, user_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除好友信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
try:
|
||||
@@ -72,9 +72,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def get_friend_nickname(cls, user_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户昵称
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
@@ -92,9 +92,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def set_friend_nickname(cls, user_id: int, nickname: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置用户昵称
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
:param nickname: 昵称
|
||||
"""
|
||||
|
||||
+33
-19
@@ -16,6 +16,8 @@ class GoodsInfo(db.Model):
|
||||
daily_purchase_limit = db.Column(
|
||||
db.JSON(), nullable=False, default={}
|
||||
) # 每日购买限制数据存储
|
||||
is_passive = db.Column(db.Boolean(), nullable=False, default=0) # 是否为被动
|
||||
icon = db.Column(db.String(), default=0) # 图标
|
||||
|
||||
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
|
||||
|
||||
@@ -28,17 +30,21 @@ class GoodsInfo(db.Model):
|
||||
goods_discount: float = 1,
|
||||
goods_limit_time: int = 0,
|
||||
daily_limit: int = 0,
|
||||
is_passive: bool = False,
|
||||
icon: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加商品
|
||||
参数:
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param goods_price: 商品价格
|
||||
:param goods_description: 商品简介
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时
|
||||
:param daily_limit: 每日购买限制
|
||||
:param is_passive: 是否为被动道具
|
||||
:param icon: 图标
|
||||
"""
|
||||
try:
|
||||
if not await cls.get_goods_info(goods_name):
|
||||
@@ -49,18 +55,20 @@ class GoodsInfo(db.Model):
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
daily_limit=daily_limit,
|
||||
is_passive=is_passive,
|
||||
icon=icon
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo add_goods 发生错误 {type(e)}:{e}")
|
||||
logger.error(f"GoodsInfo add_goods {goods_name} 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def delete_goods(cls, goods_name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除商品
|
||||
参数:
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
query = (
|
||||
@@ -81,18 +89,22 @@ class GoodsInfo(db.Model):
|
||||
goods_description: Optional[str] = None,
|
||||
goods_discount: Optional[float] = None,
|
||||
goods_limit_time: Optional[int] = None,
|
||||
daily_limit: Optional[int] = None
|
||||
daily_limit: Optional[int] = None,
|
||||
is_passive: Optional[bool] = None,
|
||||
icon: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
更新商品信息
|
||||
参数:
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param goods_price: 商品价格
|
||||
:param goods_description: 商品简介
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时时间
|
||||
:param daily_limit: 每日次数限制
|
||||
:param is_passive: 是否为被动
|
||||
:param icon: 图标
|
||||
"""
|
||||
try:
|
||||
query = (
|
||||
@@ -108,6 +120,8 @@ class GoodsInfo(db.Model):
|
||||
goods_discount=goods_discount or query.goods_discount,
|
||||
goods_limit_time=goods_limit_time if goods_limit_time is not None else query.goods_limit_time,
|
||||
daily_limit=daily_limit if daily_limit is not None else query.daily_limit,
|
||||
is_passive=is_passive if is_passive is not None else query.is_passive,
|
||||
icon=icon or query.icon
|
||||
).apply()
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -117,9 +131,9 @@ class GoodsInfo(db.Model):
|
||||
@classmethod
|
||||
async def get_goods_info(cls, goods_name: str) -> "GoodsInfo":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取商品对象
|
||||
参数:
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
return await cls.query.where(cls.goods_name == goods_name).gino.first()
|
||||
@@ -127,7 +141,7 @@ class GoodsInfo(db.Model):
|
||||
@classmethod
|
||||
async def get_all_goods(cls) -> List["GoodsInfo"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获得全部有序商品对象
|
||||
"""
|
||||
query = await cls.query.gino.all()
|
||||
@@ -144,9 +158,9 @@ class GoodsInfo(db.Model):
|
||||
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加用户明日购买限制
|
||||
参数:
|
||||
参数:
|
||||
:param goods: 商品
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
@@ -167,9 +181,9 @@ class GoodsInfo(db.Model):
|
||||
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
|
||||
) -> Tuple[bool, int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测用户每日购买上限
|
||||
参数:
|
||||
参数:
|
||||
:param goods: 商品
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
@@ -177,11 +191,11 @@ class GoodsInfo(db.Model):
|
||||
"""
|
||||
user_id = str(user_id)
|
||||
group_id = str(group_id)
|
||||
if goods:
|
||||
if goods and goods.daily_limit > 0:
|
||||
if (
|
||||
not goods.daily_limit
|
||||
or not goods.daily_purchase_limit.get(group_id)
|
||||
or not goods.daily_purchase_limit[group_id].get(user_id)
|
||||
not goods.daily_limit
|
||||
or not goods.daily_purchase_limit.get(group_id)
|
||||
or not goods.daily_purchase_limit[group_id].get(user_id)
|
||||
):
|
||||
return goods.daily_limit - num < 0, goods.daily_limit
|
||||
if goods.daily_purchase_limit[group_id][user_id] + num > goods.daily_limit:
|
||||
|
||||
@@ -17,9 +17,9 @@ class GroupInfo(db.Model):
|
||||
@classmethod
|
||||
async def get_group_info(cls, group_id: int) -> "GroupInfo":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群信息
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where(cls.group_id == group_id)
|
||||
@@ -35,9 +35,9 @@ class GroupInfo(db.Model):
|
||||
group_flag: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加群信息
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param group_name: 群名称
|
||||
:param max_member_count: 群员最大数量
|
||||
@@ -74,9 +74,9 @@ class GroupInfo(db.Model):
|
||||
@classmethod
|
||||
async def delete_group_info(cls, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除群信息
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
await cls.delete.where(cls.group_id == group_id).gino.status()
|
||||
@@ -84,7 +84,7 @@ class GroupInfo(db.Model):
|
||||
@classmethod
|
||||
async def get_all_group(cls) -> List["GroupInfo"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有群对象
|
||||
"""
|
||||
query = await cls.query.gino.all()
|
||||
|
||||
+14
-14
@@ -27,9 +27,9 @@ class GroupInfoUser(db.Model):
|
||||
uid: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加群内用户信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param user_name: 用户名称
|
||||
@@ -57,9 +57,9 @@ class GroupInfoUser(db.Model):
|
||||
cls, user_qq: int, group_id: int
|
||||
) -> "GroupInfoUser":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查询群员信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -71,9 +71,9 @@ class GroupInfoUser(db.Model):
|
||||
@classmethod
|
||||
async def delete_member_info(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除群员信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -96,9 +96,9 @@ class GroupInfoUser(db.Model):
|
||||
@classmethod
|
||||
async def get_group_member_id_list(cls, group_id: int) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取该群所有用户qq
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
member_list = []
|
||||
@@ -112,9 +112,9 @@ class GroupInfoUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, nickname: str
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置群员在该群内的昵称
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param nickname: 昵称
|
||||
@@ -131,9 +131,9 @@ class GroupInfoUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_all_group(cls, user_qq: int) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取该用户所在的所有群聊
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
|
||||
@@ -144,9 +144,9 @@ class GroupInfoUser(db.Model):
|
||||
@classmethod
|
||||
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户在该群的昵称
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
|
||||
+10
-10
@@ -17,9 +17,9 @@ class LevelUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_level(cls, user_qq: int, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户在群内的等级
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -35,9 +35,9 @@ class LevelUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, level: int, group_flag: int = 0
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置用户在群内的权限
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param level: 权限等级
|
||||
@@ -64,9 +64,9 @@ class LevelUser(db.Model):
|
||||
@classmethod
|
||||
async def delete_level(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除用户权限
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -82,9 +82,9 @@ class LevelUser(db.Model):
|
||||
@classmethod
|
||||
async def check_level(cls, user_qq: int, group_id: int, level: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检查用户权限等级是否大于 level
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param level: 权限等级
|
||||
@@ -112,9 +112,9 @@ class LevelUser(db.Model):
|
||||
@classmethod
|
||||
async def is_group_flag(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测是否会被自动更新刷新权限
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
|
||||
@@ -80,9 +80,9 @@ class SignGroupUser(db.Model):
|
||||
@classmethod
|
||||
async def get_all_impression(cls, group_id: int) -> "list, list, list":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取该群所有用户 id 及对应 好感度
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
impression_list = []
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
from datetime import datetime
|
||||
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
class UserShopGoldLog(db.Model):
|
||||
__tablename__ = "user_shop_gold_log"
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_qq = db.Column(db.BigInteger(), nullable=False)
|
||||
group_id = db.Column(db.BigInteger(), nullable=False)
|
||||
type = db.Column(db.Integer(), nullable=False) # 0: 购买,1: 使用,2: 插件
|
||||
name = db.Column(db.String())
|
||||
spend_gold = db.Column(db.Integer(), nullable=False)
|
||||
num = db.Column(db.Integer(), nullable=False)
|
||||
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
|
||||
|
||||
@classmethod
|
||||
async def add_shop_log(
|
||||
cls,
|
||||
user_qq: int,
|
||||
group_id: int,
|
||||
type_: int,
|
||||
name: str,
|
||||
num: int,
|
||||
spend_gold: int = 0,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
添加商店购买或使用日志
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param type_: 类型
|
||||
:param name: 商品名称
|
||||
:param num: 数量
|
||||
:param spend_gold: 花费金币
|
||||
"""
|
||||
await cls.create(
|
||||
user_qq=user_qq,
|
||||
group_id=group_id,
|
||||
type=type_,
|
||||
name=name,
|
||||
num=num,
|
||||
spend_gold=spend_gold,
|
||||
create_time=datetime.now(),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_user_log(cls, user_qq: int, group_id: int) -> "UserShopGoldLog":
|
||||
"""
|
||||
说明:
|
||||
获取用户日志
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
return await cls.query.where(
|
||||
(cls.user_qq == user_qq) & (cls.group_qq == group_id)
|
||||
).first()
|
||||
@@ -1,6 +1,9 @@
|
||||
from nonebot import on_command
|
||||
from nonebot import on_command, on_regex
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
|
||||
|
||||
from utils.image_utils import text2image
|
||||
from utils.message_builder import image
|
||||
from .data_source import (
|
||||
add_live_sub,
|
||||
delete_sub,
|
||||
@@ -12,12 +15,13 @@ from .data_source import (
|
||||
BilibiliSub,
|
||||
)
|
||||
from models.level_user import LevelUser
|
||||
from utils.manager import group_manager
|
||||
from configs.config import Config
|
||||
from utils.utils import is_number, scheduler, get_bot
|
||||
from typing import Optional
|
||||
from typing import Optional, Tuple, Any
|
||||
from services.log import logger
|
||||
from nonebot import Driver
|
||||
from nonebot.params import CommandArg, ArgStr
|
||||
from nonebot.params import CommandArg, ArgStr, RegexGroup
|
||||
import nonebot
|
||||
|
||||
__zx_plugin_name__ = "B站订阅"
|
||||
@@ -50,12 +54,22 @@ __plugin_configs__ = {
|
||||
"value": 5,
|
||||
"help": "群内bilibili订阅需要管理的权限",
|
||||
"default_value": 5,
|
||||
}
|
||||
},
|
||||
"LIVE_MSG_AT_ALL": {
|
||||
"value": False,
|
||||
"help": "直播提醒是否AT全体(仅在真寻是管理员时生效)",
|
||||
"default_value": False,
|
||||
},
|
||||
"UP_MSG_AT_ALL": {
|
||||
"value": False,
|
||||
"help": "UP动态投稿提醒是否AT全体(仅在真寻是管理员时生效)",
|
||||
"default_value": False,
|
||||
},
|
||||
}
|
||||
|
||||
add_sub = on_command("添加订阅", priority=5, block=True)
|
||||
del_sub = on_command("删除订阅", priority=5, block=True)
|
||||
show_sub_info = on_command("查看订阅", priority=5, block=True)
|
||||
del_sub = on_regex(r"^删除订阅(\d+)$", priority=5, block=True)
|
||||
show_sub_info = on_regex("^查看订阅$", priority=5, block=True)
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
@@ -144,12 +158,10 @@ async def _(
|
||||
|
||||
|
||||
@del_sub.handle()
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if not is_number(msg):
|
||||
await del_sub.finish("Id必须为数字!", at_sender=True)
|
||||
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||
msg = reg_group[0]
|
||||
id_ = (
|
||||
f"{event.user_id}:{event.group_id}"
|
||||
f"{event.group_id}"
|
||||
if isinstance(event, GroupMessageEvent)
|
||||
else f"{event.user_id}"
|
||||
)
|
||||
@@ -195,7 +207,15 @@ async def _(event: MessageEvent):
|
||||
live_rst = (
|
||||
"该群目前没有任何订阅..." if isinstance(event, GroupMessageEvent) else "您目前没有任何订阅..."
|
||||
)
|
||||
await show_sub_info.send(live_rst + up_rst + season_rst)
|
||||
await show_sub_info.send(
|
||||
image(
|
||||
b64=(
|
||||
await text2image(
|
||||
live_rst + up_rst + season_rst, padding=10, color="#f9f6f2"
|
||||
)
|
||||
).pic2bs4()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# 推送
|
||||
@@ -207,18 +227,18 @@ async def _():
|
||||
bot = get_bot()
|
||||
sub = None
|
||||
if bot:
|
||||
try:
|
||||
await sub_manager.reload_sub_data()
|
||||
sub = await sub_manager.random_sub_data()
|
||||
if sub:
|
||||
logger.debug(f"Bilibili订阅开始检测:{sub.sub_id}")
|
||||
rst = await get_sub_status(sub.sub_id, sub.sub_type)
|
||||
# try:
|
||||
await sub_manager.reload_sub_data()
|
||||
sub = await sub_manager.random_sub_data()
|
||||
if sub:
|
||||
logger.debug(f"Bilibili订阅开始检测:{sub.sub_id}")
|
||||
rst = await get_sub_status(sub.sub_id, sub.sub_type)
|
||||
await send_sub_msg(rst, sub, bot)
|
||||
if sub.sub_type == "live":
|
||||
rst = await get_sub_status(sub.sub_id, "up")
|
||||
await send_sub_msg(rst, sub, bot)
|
||||
if sub.sub_type == "live":
|
||||
rst = await get_sub_status(sub.sub_id, "up")
|
||||
await send_sub_msg(rst, sub, bot)
|
||||
except Exception as e:
|
||||
logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id if sub else 0} {type(e)}:{e}")
|
||||
# except Exception as e:
|
||||
# logger.error(f"B站订阅推送发生错误 sub_id:{sub.sub_id if sub else 0} {type(e)}:{e}")
|
||||
|
||||
|
||||
async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
|
||||
@@ -233,10 +253,23 @@ async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
|
||||
for x in sub.sub_users.split(",")[:-1]:
|
||||
try:
|
||||
if ":" in x and x.split(":")[1] not in temp_group:
|
||||
temp_group.append(x.split(":")[1])
|
||||
await bot.send_group_msg(
|
||||
group_id=int(x.split(":")[1]), message=Message(rst)
|
||||
)
|
||||
group_id = int(x.split(":")[1])
|
||||
temp_group.append(group_id)
|
||||
if (
|
||||
await bot.get_group_member_info(
|
||||
group_id=group_id, user_id=int(bot.self_id), no_cache=True
|
||||
)
|
||||
)["role"] in ["owner", "admin"]:
|
||||
if (
|
||||
sub.sub_type == "live"
|
||||
and Config.get_config("bilibili_sub", "LIVE_MSG_AT_ALL")
|
||||
) or (
|
||||
sub.sub_type == "up"
|
||||
and Config.get_config("bilibili_sub", "UP_MSG_AT_ALL")
|
||||
):
|
||||
rst = "[CQ:at,qq=all]\n" + rst
|
||||
if group_manager.get_plugin_status("bilibili_sub", group_id):
|
||||
await bot.send_group_msg(group_id=group_id, message=Message(rst))
|
||||
else:
|
||||
await bot.send_private_msg(user_id=int(x), message=Message(rst))
|
||||
except Exception as e:
|
||||
|
||||
@@ -3,13 +3,15 @@ from nonebot.adapters.onebot.v11 import MessageSegment
|
||||
|
||||
from utils.manager import resources_manager
|
||||
from asyncio.exceptions import TimeoutError
|
||||
|
||||
from utils.utils import get_bot
|
||||
from .model import BilibiliSub
|
||||
from bilireq.live import get_room_info_by_id
|
||||
from .utils import get_meta
|
||||
from .utils import get_meta, get_user_card
|
||||
from utils.message_builder import image
|
||||
from bilireq.user import get_user_info
|
||||
from bilireq.user import get_videos
|
||||
# from .utils import get_videos
|
||||
from bilireq import dynamic
|
||||
from .utils import get_videos
|
||||
from typing import Optional, Tuple
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from datetime import datetime
|
||||
@@ -37,36 +39,35 @@ async def add_live_sub(live_id: int, sub_user: str) -> str:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
async with db.transaction():
|
||||
try:
|
||||
"""bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
|
||||
live_info = await get_room_info_by_id(live_id)
|
||||
except ResponseCodeError:
|
||||
return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确"
|
||||
uid = live_info["uid"]
|
||||
room_id = live_info["room_id"]
|
||||
short_id = live_info["short_id"]
|
||||
title = live_info["title"]
|
||||
live_status = live_info["live_status"]
|
||||
if await BilibiliSub.add_bilibili_sub(
|
||||
room_id,
|
||||
"live",
|
||||
sub_user,
|
||||
uid=uid,
|
||||
live_short_id=short_id,
|
||||
live_status=live_status,
|
||||
):
|
||||
await _get_up_status(live_id)
|
||||
uname = (await BilibiliSub.get_sub(live_id)).uname
|
||||
return (
|
||||
"已成功订阅主播:\n"
|
||||
f"\ttitle:{title}\n"
|
||||
f"\tname: {uname}\n"
|
||||
f"\tlive_id:{live_id}\n"
|
||||
f"\tuid:{uid}"
|
||||
try:
|
||||
"""bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
|
||||
live_info = await get_room_info_by_id(live_id)
|
||||
except ResponseCodeError:
|
||||
return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确"
|
||||
uid = live_info["uid"]
|
||||
room_id = live_info["room_id"]
|
||||
short_id = live_info["short_id"]
|
||||
title = live_info["title"]
|
||||
live_status = live_info["live_status"]
|
||||
if await BilibiliSub.add_bilibili_sub(
|
||||
room_id,
|
||||
"live",
|
||||
sub_user,
|
||||
uid=uid,
|
||||
live_short_id=short_id,
|
||||
live_status=live_status,
|
||||
):
|
||||
await _get_up_status(room_id)
|
||||
uname = (await BilibiliSub.get_sub(room_id)).uname
|
||||
return (
|
||||
"已成功订阅主播:\n"
|
||||
f"\ttitle:{title}\n"
|
||||
f"\tname: {uname}\n"
|
||||
f"\tlive_id:{room_id}\n"
|
||||
f"\tuid:{uid}"
|
||||
)
|
||||
else:
|
||||
return "添加订阅失败..."
|
||||
else:
|
||||
return "添加订阅失败..."
|
||||
except Exception as e:
|
||||
logger.error(f"订阅主播live_id:{live_id} 发生了错误 {type(e)}:{e}")
|
||||
return "添加订阅失败..."
|
||||
@@ -82,7 +83,7 @@ async def add_up_sub(uid: int, sub_user: str) -> str:
|
||||
async with db.transaction():
|
||||
try:
|
||||
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
|
||||
user_info = await get_user_info(uid)
|
||||
user_info = await get_user_card(uid)
|
||||
except ResponseCodeError:
|
||||
return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
|
||||
uname = user_info["name"]
|
||||
@@ -206,8 +207,10 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
||||
return await _get_up_status(id_)
|
||||
elif sub_type == "season":
|
||||
return await _get_season_status(id_)
|
||||
except ResponseCodeError:
|
||||
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||
except ResponseCodeError as msg:
|
||||
logger.info(f"Id:{id_} 获取信息失败...{msg}")
|
||||
return None
|
||||
# return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||
# except Exception as e:
|
||||
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
|
||||
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
|
||||
@@ -229,6 +232,7 @@ async def _get_live_status(id_: int) -> Optional[str]:
|
||||
await BilibiliSub.update_sub_info(id_, live_status=live_status)
|
||||
if sub.live_status == 0 and live_status == 1:
|
||||
return (
|
||||
f""
|
||||
f"{image(cover)}\n"
|
||||
f"{sub.uname} 开播啦!\n"
|
||||
f"标题:{title}\n"
|
||||
@@ -240,34 +244,35 @@ async def _get_live_status(id_: int) -> Optional[str]:
|
||||
async def _get_up_status(id_: int) -> Optional[str]:
|
||||
"""
|
||||
获取用户投稿状态
|
||||
:param id_: 用户 id
|
||||
:param id_: 订阅 id
|
||||
:return:
|
||||
"""
|
||||
_user = await BilibiliSub.get_sub(id_)
|
||||
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
|
||||
user_info = await get_user_info(_user.uid)
|
||||
user_info = await get_user_card(_user.uid)
|
||||
uname = user_info["name"]
|
||||
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
|
||||
video_info = await get_videos(id_)
|
||||
video_info = await get_videos(_user.uid)
|
||||
latest_video_created = 0
|
||||
video = None
|
||||
dividing_line = "\n-------------\n"
|
||||
if _user.uname != uname:
|
||||
await BilibiliSub.update_sub_info(id_, uname=uname)
|
||||
dynamic_img, dynamic_upload_time = await get_user_dynamic(id_, _user)
|
||||
dynamic_img, dynamic_upload_time, link = await get_user_dynamic(_user.uid, _user)
|
||||
if video_info["list"].get("vlist"):
|
||||
video = video_info["list"]["vlist"][0]
|
||||
latest_video_created = video["created"]
|
||||
rst = ""
|
||||
if dynamic_img:
|
||||
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
|
||||
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n"
|
||||
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n{link}"
|
||||
if (
|
||||
latest_video_created
|
||||
and _user.latest_video_created
|
||||
and video
|
||||
and _user.latest_video_created < latest_video_created
|
||||
):
|
||||
rst = rst + "-------------\n" if rst else rst
|
||||
rst = rst + dividing_line if rst else rst
|
||||
await BilibiliSub.update_sub_info(
|
||||
id_, latest_video_created=latest_video_created
|
||||
)
|
||||
@@ -278,7 +283,7 @@ async def _get_up_status(id_: int) -> Optional[str]:
|
||||
f'Bvid:{video["bvid"]}\n'
|
||||
f'直链:https://www.bilibili.com/video/{video["bvid"]}'
|
||||
)
|
||||
rst = None if rst == "-------------\n" else rst
|
||||
rst = None if rst == dividing_line else rst
|
||||
return rst
|
||||
|
||||
|
||||
@@ -306,7 +311,7 @@ async def _get_season_status(id_) -> Optional[str]:
|
||||
|
||||
async def get_user_dynamic(
|
||||
uid: int, local_user: BilibiliSub
|
||||
) -> Tuple[Optional[MessageSegment], int]:
|
||||
) -> Tuple[Optional[MessageSegment], int, str]:
|
||||
"""
|
||||
获取用户动态
|
||||
:param uid: 用户uid
|
||||
@@ -318,41 +323,34 @@ async def get_user_dynamic(
|
||||
browser = await get_browser()
|
||||
if dynamic_info.get("cards") and browser:
|
||||
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
||||
dynamic_id = dynamic_info["cards"][0]["desc"]["dynamic_id"]
|
||||
if local_user.dynamic_upload_time < dynamic_upload_time:
|
||||
context = await browser.new_context()
|
||||
page = await context.new_page()
|
||||
try:
|
||||
await page.goto(
|
||||
f"https://space.bilibili.com/{local_user.uid}/dynamic",
|
||||
f"https://t.bilibili.com/{dynamic_id}",
|
||||
wait_until="networkidle",
|
||||
timeout=10000,
|
||||
)
|
||||
# await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s
|
||||
# 删除置顶
|
||||
await page.evaluate(
|
||||
"""
|
||||
xs = document.getElementsByClassName('bili-dyn-item__tag');
|
||||
for (x of xs) {
|
||||
x.parentNode.parentNode.remove();
|
||||
}
|
||||
"""
|
||||
)
|
||||
async with page.expect_popup() as popup_info:
|
||||
await page.locator(".bili-rich-text__content").click()
|
||||
details_page = await popup_info.value
|
||||
await details_page.set_viewport_size(
|
||||
# await page.evaluate(
|
||||
# """
|
||||
# xs = document.getElementsByClassName('bili-dyn-item__tag');
|
||||
# for (x of xs) {
|
||||
# x.parentNode.parentNode.remove();
|
||||
# }
|
||||
# """
|
||||
# )
|
||||
# async with page.expect_popup() as popup_info:
|
||||
# await page.locator(".bili-rich-text__content").click()
|
||||
# details_page = await popup_info.value
|
||||
await page.set_viewport_size(
|
||||
{"width": 2560, "height": 1080, "timeout": 10000 * 20}
|
||||
)
|
||||
await details_page.wait_for_selector(".panel-area")
|
||||
await details_page.evaluate(
|
||||
"""
|
||||
xs = document.getElementById('internationalHeader');
|
||||
xs.remove();
|
||||
xs = document.getElementsByClassName('panel-area')
|
||||
xs[0].remove();
|
||||
"""
|
||||
)
|
||||
card = details_page.locator(".detail-card")
|
||||
await page.wait_for_selector(".bili-dyn-item__main")
|
||||
card = page.locator(".bili-dyn-item__main")
|
||||
await card.wait_for()
|
||||
await card.screenshot(
|
||||
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||
@@ -368,8 +366,9 @@ async def get_user_dynamic(
|
||||
"bilibili_sub/dynamic",
|
||||
),
|
||||
dynamic_upload_time,
|
||||
f"https://t.bilibili.com/{dynamic_id}"
|
||||
)
|
||||
return None, 0
|
||||
return None, 0, ''
|
||||
|
||||
|
||||
class SubManager:
|
||||
|
||||
@@ -47,9 +47,9 @@ class BilibiliSub(db.Model):
|
||||
season_update_time: Optional[datetime] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加订阅
|
||||
参数:
|
||||
参数:
|
||||
:param sub_id: 订阅名称,房间号,番剧号等
|
||||
:param sub_type: 订阅类型
|
||||
:param sub_user: 订阅此条目的用户
|
||||
@@ -65,44 +65,43 @@ class BilibiliSub(db.Model):
|
||||
:param season_update_time: 番剧更新时间
|
||||
"""
|
||||
try:
|
||||
async with db.transaction():
|
||||
query = (
|
||||
await cls.query.where(cls.sub_id == sub_id)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
query = (
|
||||
await cls.query.where(cls.sub_id == sub_id)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
sub_user = sub_user if sub_user[-1] == "," else f"{sub_user},"
|
||||
if query:
|
||||
if sub_user not in query.sub_users:
|
||||
sub_users = query.sub_users + sub_user
|
||||
await query.update(sub_users=sub_users).apply()
|
||||
else:
|
||||
sub = await cls.create(
|
||||
sub_id=sub_id, sub_type=sub_type, sub_users=sub_user
|
||||
)
|
||||
sub_user = sub_user if sub_user[-1] == "," else f"{sub_user},"
|
||||
if query:
|
||||
if sub_user not in query.sub_users:
|
||||
sub_users = query.sub_users + sub_user
|
||||
await query.update(sub_users=sub_users).apply()
|
||||
else:
|
||||
sub = await cls.create(
|
||||
sub_id=sub_id, sub_type=sub_type, sub_users=sub_user
|
||||
)
|
||||
await sub.update(
|
||||
live_short_id=live_short_id
|
||||
if live_short_id
|
||||
else sub.live_short_id,
|
||||
live_status=live_status if live_status else sub.live_status,
|
||||
dynamic_upload_time=dynamic_upload_time
|
||||
if dynamic_upload_time
|
||||
else sub.dynamic_upload_time,
|
||||
uid=uid if uid else sub.uid,
|
||||
uname=uname if uname else sub.uname,
|
||||
latest_video_created=latest_video_created
|
||||
if latest_video_created
|
||||
else sub.latest_video_created,
|
||||
season_update_time=season_update_time
|
||||
if season_update_time
|
||||
else sub.season_update_time,
|
||||
season_current_episode=season_current_episode
|
||||
if season_current_episode
|
||||
else sub.season_current_episode,
|
||||
season_id=season_id if season_id else sub.season_id,
|
||||
season_name=season_name if season_name else sub.season_name,
|
||||
).apply()
|
||||
return True
|
||||
await sub.update(
|
||||
live_short_id=live_short_id
|
||||
if live_short_id
|
||||
else sub.live_short_id,
|
||||
live_status=live_status if live_status else sub.live_status,
|
||||
dynamic_upload_time=dynamic_upload_time
|
||||
if dynamic_upload_time
|
||||
else sub.dynamic_upload_time,
|
||||
uid=uid if uid else sub.uid,
|
||||
uname=uname if uname else sub.uname,
|
||||
latest_video_created=latest_video_created
|
||||
if latest_video_created
|
||||
else sub.latest_video_created,
|
||||
season_update_time=season_update_time
|
||||
if season_update_time
|
||||
else sub.season_update_time,
|
||||
season_current_episode=season_current_episode
|
||||
if season_current_episode
|
||||
else sub.season_current_episode,
|
||||
season_id=season_id if season_id else sub.season_id,
|
||||
season_name=season_name if season_name else sub.season_name,
|
||||
).apply()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.info(f"bilibili_sub 添加订阅错误 {type(e)}: {e}")
|
||||
return False
|
||||
@@ -110,9 +109,9 @@ class BilibiliSub(db.Model):
|
||||
@classmethod
|
||||
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除订阅
|
||||
参数:
|
||||
参数:
|
||||
:param sub_id: 订阅名称
|
||||
:param sub_user: 删除此条目的用户
|
||||
"""
|
||||
@@ -140,9 +139,9 @@ class BilibiliSub(db.Model):
|
||||
@classmethod
|
||||
async def get_sub(cls, sub_id: int) -> Optional["BilibiliSub"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取订阅对象
|
||||
参数:
|
||||
参数:
|
||||
:param sub_id: 订阅 id
|
||||
"""
|
||||
return await cls.query.where(cls.sub_id == sub_id).gino.first()
|
||||
@@ -173,9 +172,9 @@ class BilibiliSub(db.Model):
|
||||
season_update_time: Optional[datetime] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
更新订阅信息
|
||||
参数:
|
||||
参数:
|
||||
:param sub_id: 订阅名称,房间号,番剧号等
|
||||
:param live_short_id: 直接短 id
|
||||
:param live_status: 主播开播状态
|
||||
@@ -232,7 +231,7 @@ class BilibiliSub(db.Model):
|
||||
cls,
|
||||
) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
分类获取所有数据
|
||||
"""
|
||||
live_data = []
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.http_utils import AsyncHttpx, get_user_agent
|
||||
# from bilibili_api import user
|
||||
from bilireq.user import get_user_info
|
||||
from httpx import AsyncClient
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
BORDER_PATH = IMAGE_PATH / "border"
|
||||
BORDER_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
BASE_URL = "https://api.bilibili.com"
|
||||
|
||||
async def get_pic(url: str) -> bytes:
|
||||
"""
|
||||
@@ -78,7 +79,6 @@ async def get_meta(media_id: int, auth=None, reqtype="both", **kwargs):
|
||||
"""
|
||||
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)
|
||||
@@ -86,8 +86,7 @@ async def get_meta(media_id: int, auth=None, reqtype="both", **kwargs):
|
||||
|
||||
|
||||
async def get_videos(
|
||||
uid: int, tid: int = 0, pn: int = 1, keyword: str = "", order: str = "pubdate",
|
||||
*, auth=None, reqtype="both", **kwargs
|
||||
uid: int, tid: int = 0, pn: int = 1, keyword: str = "", order: str = "pubdate"
|
||||
):
|
||||
"""
|
||||
获取用户投该视频信息
|
||||
@@ -100,15 +99,45 @@ async def get_videos(
|
||||
:param keyword: 搜索关键词
|
||||
:param order: 排序方式,可以为 “pubdate(上传日期从新到旧), stow(收藏从多到少), click(播放量从多到少)”
|
||||
"""
|
||||
from bilireq.utils import get
|
||||
BASE_URL = "https://api.bilibili.com"
|
||||
from bilireq.utils import ResponseCodeError
|
||||
|
||||
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)
|
||||
headers = get_user_agent()
|
||||
headers["Referer"] = f"https://space.bilibili.com/{uid}/video"
|
||||
async with AsyncClient() as client:
|
||||
r = await client.head(
|
||||
"https://space.bilibili.com",
|
||||
headers=headers,
|
||||
)
|
||||
params = {
|
||||
"mid": uid,
|
||||
"ps": 30,
|
||||
"tid": tid,
|
||||
"pn": pn,
|
||||
"keyword": keyword,
|
||||
"order": order,
|
||||
}
|
||||
raw_json = (
|
||||
await client.get(url, params=params, headers=headers, cookies=r.cookies)
|
||||
).json()
|
||||
if raw_json["code"] != 0:
|
||||
raise ResponseCodeError(
|
||||
code=raw_json["code"],
|
||||
msg=raw_json["message"],
|
||||
data=raw_json.get("data", None),
|
||||
)
|
||||
return raw_json["data"]
|
||||
|
||||
async def get_user_card(mid, photo: bool = False, auth=None, reqtype="both", **kwargs):
|
||||
from bilireq.utils import get
|
||||
|
||||
url = f"{BASE_URL}/x/web-interface/card"
|
||||
return (
|
||||
await get(
|
||||
url,
|
||||
params={"mid": mid, "photo": photo},
|
||||
auth=auth,
|
||||
reqtype=reqtype,
|
||||
**kwargs,
|
||||
)
|
||||
)["card"]
|
||||
|
||||
+10
-10
@@ -25,9 +25,9 @@ class BlackWord(db.Model):
|
||||
punish_level: int,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加用户发送的敏感词
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户id
|
||||
:param group_id: 群号
|
||||
:param black_word: 黑名单词汇
|
||||
@@ -52,9 +52,9 @@ class BlackWord(db.Model):
|
||||
id_: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置处罚
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户id
|
||||
:param punish: 处罚
|
||||
:param black_word: 黑名单词汇
|
||||
@@ -81,9 +81,9 @@ class BlackWord(db.Model):
|
||||
cls, user_qq: int, days: int = 7, punish_level: Optional[int] = None
|
||||
) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户规定周期内的犯事次数
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param days: 周期天数
|
||||
:param punish_level: 惩罚等级
|
||||
@@ -101,9 +101,9 @@ class BlackWord(db.Model):
|
||||
@classmethod
|
||||
async def get_user_punish_level(cls, user_qq: int, days: int = 7) -> Optional[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户最近一次的惩罚记录等级
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param days: 周期天数
|
||||
"""
|
||||
@@ -125,9 +125,9 @@ class BlackWord(db.Model):
|
||||
date_type: str = "=",
|
||||
) -> List["BlackWord"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过指定条件查询数据
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param group_id: 群号
|
||||
:param date: 日期
|
||||
|
||||
@@ -9,7 +9,7 @@ import platform
|
||||
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
|
||||
|
||||
url = "http://www.eclzz.zone/"
|
||||
url = "http://www.eclzz.cool"
|
||||
|
||||
|
||||
async def get_bt_info(keyword: str, page: int):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot import on_command
|
||||
from .data_source import check_update, get_latest_version_data
|
||||
@@ -50,28 +50,27 @@ restart = on_command(
|
||||
|
||||
|
||||
@update_zhenxun.handle()
|
||||
async def _(bot: Bot):
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
try:
|
||||
code, error = await check_update(bot)
|
||||
if error:
|
||||
logger.error(f"更新真寻未知错误 {error}")
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=f"更新真寻未知错误 {error}"
|
||||
user_id=event.user_id, message=f"更新真寻未知错误 {error}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"更新真寻未知错误 {type(e)}:{e}")
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
user_id=event.user_id,
|
||||
message=f"更新真寻未知错误 {type(e)}:{e}",
|
||||
)
|
||||
else:
|
||||
if code == 200:
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=f"更新完毕,请重启真寻...."
|
||||
user_id=event.user_id, message=f"更新完毕,请重启真寻...."
|
||||
)
|
||||
|
||||
|
||||
|
||||
@restart.got("flag", prompt=f"确定是否重启{NICKNAME}?确定请回复[是|好|确定](重启失败咱们将失去联系,请谨慎!)")
|
||||
async def _(flag: str = ArgStr("flag")):
|
||||
if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
|
||||
|
||||
+23
-15
@@ -1,4 +1,7 @@
|
||||
from typing import Tuple, Any
|
||||
|
||||
from nonebot import on_regex
|
||||
from nonebot.params import RegexGroup
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
|
||||
from utils.message_builder import image
|
||||
@@ -11,7 +14,9 @@ __plugin_usage__ = """
|
||||
usage:
|
||||
三次元也不戳,嘿嘿嘿
|
||||
指令:
|
||||
cos/coser
|
||||
?N连cos/coser
|
||||
示例:cos
|
||||
示例:5连cos (单次请求张数小于9)
|
||||
""".strip()
|
||||
__plugin_des__ = "三次元也不戳,嘿嘿嘿"
|
||||
__plugin_cmd__ = ["cos/coser"]
|
||||
@@ -31,21 +36,24 @@ __plugin_configs__ = {
|
||||
},
|
||||
}
|
||||
|
||||
coser = on_regex("^(cos|COS|coser|括丝)$", priority=5, block=True)
|
||||
coser = on_regex(r"^(\d)?连?(cos|COS|coser|括丝)$", priority=5, block=True)
|
||||
|
||||
|
||||
url = "https://api.iyk0.com/cos"
|
||||
# 纯cos,较慢:https://picture.yinux.workers.dev
|
||||
# 比较杂,有福利姬,较快:https://api.jrsgslb.cn/cos/url.php?return=img
|
||||
url = "https://picture.yinux.workers.dev/"
|
||||
|
||||
|
||||
@coser.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
try:
|
||||
msg_id = await coser.send(image(url))
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event,
|
||||
msg_id["message_id"],
|
||||
Config.get_config("coser", "WITHDRAW_COS_MESSAGE"),
|
||||
)
|
||||
except Exception as e:
|
||||
await coser.send("你cos给我看!")
|
||||
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
|
||||
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||
num = reg_group[0] or 1
|
||||
for _ in range(int(num)):
|
||||
try:
|
||||
msg_id = await coser.send(image(url))
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event,
|
||||
msg_id["message_id"],
|
||||
Config.get_config("coser", "WITHDRAW_COS_MESSAGE"),
|
||||
)
|
||||
except Exception as e:
|
||||
await coser.send("你cos给我看!")
|
||||
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import contextlib
|
||||
import random
|
||||
import dateparser
|
||||
from lxml import etree
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, Tuple
|
||||
from urllib.parse import unquote
|
||||
from pydantic import ValidationError
|
||||
from nonebot.log import logger
|
||||
@@ -12,7 +13,6 @@ from .base_handle import BaseHandle, BaseData, UpEvent as _UpEvent, UpChar as _U
|
||||
from ..config import draw_config
|
||||
from ..util import remove_prohibited_str, cn2py
|
||||
from utils.image_utils import BuildImage
|
||||
import asyncio
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
@@ -29,7 +29,7 @@ class AzurChar(BaseData):
|
||||
|
||||
|
||||
class UpChar(_UpChar):
|
||||
type_: str # 舰娘类型
|
||||
type_: str # 舰娘类型
|
||||
|
||||
|
||||
class UpEvent(_UpEvent):
|
||||
@@ -53,7 +53,9 @@ class AzurHandle(BaseHandle[AzurChar]):
|
||||
type_ = ["维修", "潜艇", "重巡", "轻航", "航母"]
|
||||
up_pool_flag = pool_name == "活动"
|
||||
# Up
|
||||
up_ship = [x for x in self.UP_EVENT.up_char if x.zoom > 0]
|
||||
up_ship = (
|
||||
[x for x in self.UP_EVENT.up_char if x.zoom > 0] if self.UP_EVENT else []
|
||||
)
|
||||
# print(up_ship)
|
||||
acquire_char = None
|
||||
if up_ship and up_pool_flag:
|
||||
@@ -61,19 +63,15 @@ class AzurHandle(BaseHandle[AzurChar]):
|
||||
# 初始化概率
|
||||
cur_ = up_ship[0].zoom / 100
|
||||
for i in range(len(up_ship)):
|
||||
try:
|
||||
up_zoom.append((cur_, cur_ + up_ship[i+1].zoom / 100))
|
||||
cur_ += up_ship[i+1].zoom / 100
|
||||
except IndexError:
|
||||
pass
|
||||
with contextlib.suppress(IndexError):
|
||||
up_zoom.append((cur_, cur_ + up_ship[i + 1].zoom / 100))
|
||||
cur_ += up_ship[i + 1].zoom / 100
|
||||
rand = random.random()
|
||||
# 抽取up
|
||||
for i, zoom in enumerate(up_zoom):
|
||||
if zoom[0] <= rand <= zoom[1]:
|
||||
try:
|
||||
with contextlib.suppress(IndexError):
|
||||
acquire_char = [x for x in self.ALL_CHAR if x.name == up_ship[i].name][0]
|
||||
except IndexError:
|
||||
pass
|
||||
# 没有up或者未抽取到up
|
||||
if not acquire_char:
|
||||
star = self.get_star(
|
||||
@@ -92,9 +90,6 @@ class AzurHandle(BaseHandle[AzurChar]):
|
||||
])
|
||||
return acquire_char
|
||||
|
||||
# async def draw(self, count: int, **kwargs) -> Message:
|
||||
# return await asyncio.get_event_loop().run_in_executor(None, self._draw, count)
|
||||
|
||||
async def draw(self, count: int, **kwargs) -> Message:
|
||||
index2card = self.get_cards(count, **kwargs)
|
||||
cards = [card[0] for card in index2card]
|
||||
@@ -162,22 +157,22 @@ class AzurHandle(BaseHandle[AzurChar]):
|
||||
return
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
contents = dom.xpath(
|
||||
"//div[@class='resp-tabs-container']/div[@class='resp-tab-content']"
|
||||
"//div[@class='mw-body-content mw-content-ltr']/div[@class='mw-parser-output']"
|
||||
)
|
||||
for index, content in enumerate(contents):
|
||||
char_list = content.xpath("./table/tbody/tr[2]/td/div/div/div/div")
|
||||
char_list = content.xpath("./div[@id='CardSelectTr']/div")
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./a/@title")[0]
|
||||
frame = char.xpath("./div/a/img/@alt")[0]
|
||||
avatar = char.xpath("./a/img/@srcset")[0]
|
||||
name = char.xpath("./div/a/@title")[0]
|
||||
frame = char.xpath("./div/div/a/img/@alt")[0]
|
||||
avatar = char.xpath("./div/a/img/@srcset")[0]
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"名称": remove_prohibited_str(name),
|
||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||
"星级": self.parse_star(frame),
|
||||
"类型": self.parse_type(index),
|
||||
"类型": char.xpath("./@data-param1")[0].split(",")[1],
|
||||
}
|
||||
info[member_dict["名称"]] = member_dict
|
||||
# 更新额外信息
|
||||
@@ -225,48 +220,21 @@ class AzurHandle(BaseHandle[AzurChar]):
|
||||
|
||||
@staticmethod
|
||||
def parse_star(star: str) -> int:
|
||||
if star in ["舰娘头像外框普通.png", "舰娘头像外框白色.png"]:
|
||||
if star in {"舰娘头像外框普通.png", "舰娘头像外框白色.png"}:
|
||||
return 1
|
||||
elif star in ["舰娘头像外框稀有.png", "舰娘头像外框蓝色.png"]:
|
||||
elif star in {"舰娘头像外框稀有.png", "舰娘头像外框蓝色.png"}:
|
||||
return 2
|
||||
elif star in ["舰娘头像外框精锐.png", "舰娘头像外框紫色.png"]:
|
||||
elif star in {"舰娘头像外框精锐.png", "舰娘头像外框紫色.png"}:
|
||||
return 3
|
||||
elif star in ["舰娘头像外框超稀有.png", "舰娘头像外框金色.png"]:
|
||||
elif star in {"舰娘头像外框超稀有.png", "舰娘头像外框金色.png"}:
|
||||
return 4
|
||||
elif star in ["舰娘头像外框海上传奇.png", "舰娘头像外框彩色.png"]:
|
||||
elif star in {"舰娘头像外框海上传奇.png", "舰娘头像外框彩色.png"}:
|
||||
return 5
|
||||
elif star in [
|
||||
"舰娘头像外框最高方案.png",
|
||||
"舰娘头像外框决战方案.png",
|
||||
"舰娘头像外框超稀有META.png",
|
||||
"舰娘头像外框精锐META.png",
|
||||
]:
|
||||
elif star in {"舰娘头像外框最高方案.png", "舰娘头像外框决战方案.png", "舰娘头像外框超稀有META.png", "舰娘头像外框精锐META.png"}:
|
||||
return 6
|
||||
else:
|
||||
return 6
|
||||
|
||||
@staticmethod
|
||||
def parse_type(index: int) -> str:
|
||||
azur_types = [
|
||||
"驱逐",
|
||||
"轻巡",
|
||||
"重巡",
|
||||
"超巡",
|
||||
"战巡",
|
||||
"战列",
|
||||
"航母",
|
||||
"航站",
|
||||
"轻航",
|
||||
"重炮",
|
||||
"维修",
|
||||
"潜艇",
|
||||
"运输",
|
||||
]
|
||||
try:
|
||||
return azur_types[index]
|
||||
except IndexError:
|
||||
return azur_types[0]
|
||||
|
||||
async def update_up_char(self):
|
||||
url = "https://wiki.biligame.com/blhx/游戏活动表"
|
||||
result = await self.get_url(url)
|
||||
@@ -290,7 +258,7 @@ class AzurHandle(BaseHandle[AzurChar]):
|
||||
up_chars = []
|
||||
for ship in ships:
|
||||
name = ship.xpath("./tbody/tr/td[2]/p/a/@title")[0]
|
||||
type_ = ship.xpath("./tbody/tr/td[2]/p/small/text()")[0] # 舰船类型
|
||||
type_ = ship.xpath("./tbody/tr/td[2]/p/small/text()")[0] # 舰船类型
|
||||
try:
|
||||
p = float(str(ship.xpath(".//sup/text()")[0]).strip("%"))
|
||||
except (IndexError, ValueError):
|
||||
@@ -298,7 +266,9 @@ class AzurHandle(BaseHandle[AzurChar]):
|
||||
star = self.parse_star(
|
||||
ship.xpath("./tbody/tr/td[1]/div/div/div/a/img/@alt")[0]
|
||||
)
|
||||
up_chars.append(UpChar(name=name, star=star, limited=False, zoom=p, type_=type_))
|
||||
up_chars.append(
|
||||
UpChar(name=name, star=star, limited=False, zoom=p, type_=type_)
|
||||
)
|
||||
self.UP_EVENT = UpEvent(
|
||||
title=title,
|
||||
pool_img="",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import random
|
||||
import json
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from lxml import etree
|
||||
from typing import List, Tuple
|
||||
from PIL import ImageDraw
|
||||
@@ -107,27 +109,70 @@ class BaHandle(BaseHandle[BaChar]):
|
||||
else:
|
||||
return 1
|
||||
|
||||
# Bwiki 待恢复
|
||||
# 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"
|
||||
# )
|
||||
|
||||
# 数据来源:SCHALE DB
|
||||
async def _update_info(self):
|
||||
info = {}
|
||||
url = "https://wiki.biligame.com/bluearchive/学生筛选"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
url = "https://lonqie.github.io/SchaleDB/data/cn/students.min.json?v=49"
|
||||
result = await AsyncHttpx.get(url)
|
||||
if result.status_code != 200:
|
||||
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")
|
||||
char_list = json.loads(result.text)
|
||||
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]
|
||||
name = char.get("Name")
|
||||
avatar = "https://lonqie.github.io/SchaleDB/images/student/icon/"+char.get("CollectionTexture")+".png"
|
||||
star = char.get("StarGrade")
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar)),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"星级": self.title2star(star_pic),
|
||||
"星级": star,
|
||||
}
|
||||
info[member_dict["名称"]] = member_dict
|
||||
self.dump_data(info)
|
||||
@@ -147,4 +192,5 @@ class BaHandle(BaseHandle[BaChar]):
|
||||
await self.download_img(
|
||||
"https://patchwiki.biligame.com/images/bluearchive/thumb/8/8a/577yv79x1rwxk8efdccpblo0lozl158.png/46px-Star-3.png",
|
||||
"star-3"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -50,6 +50,7 @@ class UpEvent(BaseModel):
|
||||
start_time: Optional[datetime] # 开始时间
|
||||
end_time: Optional[datetime] # 结束时间
|
||||
up_char: List[UpChar] # up对象
|
||||
up_name: str = "" # up名称
|
||||
|
||||
|
||||
TC = TypeVar("TC", bound="BaseData")
|
||||
|
||||
@@ -331,9 +331,7 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
try:
|
||||
title = announcement.xpath("./@title")[0]
|
||||
url = "https://wiki.biligame.com/" + announcement.xpath("./@href")[0]
|
||||
if re.match(r".*?\d{8}$", title) or re.match(
|
||||
r"^\d{1,2}月\d{1,2}日.*?", title
|
||||
):
|
||||
if "卡池" in title:
|
||||
break
|
||||
except IndexError:
|
||||
continue
|
||||
@@ -350,48 +348,49 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
char_img = ""
|
||||
card_img = ""
|
||||
up_chars = []
|
||||
up_chars_name = []
|
||||
up_cards = []
|
||||
soup = BeautifulSoup(result, "lxml")
|
||||
heads = soup.find_all("span", {"class": "mw-headline"})
|
||||
up_cards_name = []
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
content = dom.xpath('//*[@id="mw-content-text"]/div/div/div[1]/div')[0]
|
||||
heads = content.xpath("./div")
|
||||
for head in heads:
|
||||
if "时间" in head.text:
|
||||
time = head.find_next("p").text.split("\n")[0]
|
||||
if "时间" in head.find("./img").tail or "期间" in head.find("./img").tail:
|
||||
time = content.xpath("./p")[1].text.split("\n")[0]
|
||||
if "~" in time:
|
||||
start, end = time.split("~")
|
||||
start_time = dateparser.parse(start)
|
||||
end_time = dateparser.parse(end)
|
||||
elif "赛马娘" in head.text:
|
||||
char_img = head.find_next("a", {"class": "image"}).find("img")[
|
||||
"src"
|
||||
]
|
||||
lines = str(head.find_next("p").text).split("\n")
|
||||
elif "赛马娘" in head.find("./img").tail:
|
||||
char_img = content.xpath("./center")[1].find("./a/img").get("src")
|
||||
lines = content.xpath("./p")[2].xpath("string(.)").split("\n")
|
||||
chars = [
|
||||
line
|
||||
for line in lines
|
||||
if "★" in line and "(" in line and ")" in line
|
||||
if "★" in line and "[" in line and "]" in line
|
||||
]
|
||||
for char in chars:
|
||||
for char in set(chars): # list去重
|
||||
star = char.count("★")
|
||||
name = re.split(r"[()]", char)[-2].strip()
|
||||
name = re.split("[ ]",char)[-1]
|
||||
up_chars.append(
|
||||
UpChar(name=name, star=star, limited=False, zoom=70)
|
||||
)
|
||||
elif "支援卡" in head.text:
|
||||
card_img = head.find_next("a", {"class": "image"}).find("img")[
|
||||
"src"
|
||||
]
|
||||
lines = str(head.find_next("p").text).split("\n")
|
||||
up_chars_name.append(name)
|
||||
elif "支援卡" in head.find("./img").tail:
|
||||
card_img = content.xpath("./center")[2].find("./a/img").get("src")
|
||||
lines = content.xpath("./p")[3].xpath("string(.)").split("\n")
|
||||
cards = [
|
||||
line
|
||||
for line in lines
|
||||
if "R" in line and "(" in line and ")" in line
|
||||
if "R" in line and "[" in line and "]" in line
|
||||
]
|
||||
for card in cards:
|
||||
for card in set(cards):
|
||||
star = 3 if "SSR" in card else 2 if "SR" in card else 1
|
||||
name = re.split(r"[()]", card)[-2].strip()
|
||||
name = re.split("[ ]",card)[-1]
|
||||
up_cards.append(
|
||||
UpChar(name=name, star=star, limited=False, zoom=70)
|
||||
)
|
||||
up_cards_name.append(name)
|
||||
if start_time and end_time:
|
||||
if start_time <= datetime.now() <= end_time:
|
||||
self.UP_CHAR = UpEvent(
|
||||
@@ -400,6 +399,7 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_chars,
|
||||
up_name=",".join(up_chars_name),
|
||||
)
|
||||
self.UP_CARD = UpEvent(
|
||||
title=title,
|
||||
@@ -407,6 +407,7 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_cards,
|
||||
up_name=",".join(up_cards_name),
|
||||
)
|
||||
self.dump_up_char()
|
||||
logger.info(f"成功获取{self.game_name_cn}当前up信息...当前up池: {title}")
|
||||
@@ -418,9 +419,8 @@ class PrettyHandle(BaseHandle[PrettyData]):
|
||||
self.load_up_char()
|
||||
if self.UP_CHAR and self.UP_CARD:
|
||||
return Message(
|
||||
Message.template("重载成功!\n当前UP池子:{}{:image}{:image}").format(
|
||||
self.UP_CHAR.title,
|
||||
self.UP_CHAR.pool_img,
|
||||
self.UP_CARD.pool_img,
|
||||
Message.template("重载成功!\n当前UP池子:{}\n当前支援卡池子:{}").format(
|
||||
self.UP_CHAR.up_name,
|
||||
self.UP_CARD.up_name,
|
||||
)
|
||||
)
|
||||
|
||||
+38
-19
@@ -7,7 +7,7 @@ from utils.http_utils import AsyncHttpx
|
||||
|
||||
# 获取所有 Epic Game Store 促销游戏
|
||||
# 方法参考:RSSHub /epicgames 路由
|
||||
# https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js
|
||||
# https://github.com/DIYgod/RSSHub/blob/master/lib/v2/epicgames/index.js
|
||||
async def get_epic_game():
|
||||
epic_url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN"
|
||||
headers = {
|
||||
@@ -39,7 +39,7 @@ async def get_epic_free(bot: Bot, type_event: str):
|
||||
game_corp = game["seller"]["name"]
|
||||
game_price = game["price"]["totalPrice"]["fmtPrice"]["originalPrice"]
|
||||
# 赋初值以避免 local variable referenced before assignment
|
||||
game_dev, game_pub, game_thumbnail = (None, None, None)
|
||||
game_thumbnail, game_dev, game_pub = None, game_corp, game_corp
|
||||
try:
|
||||
game_promotions = game["promotions"]["promotionalOffers"]
|
||||
upcoming_promotions = game["promotions"]["upcomingPromotionalOffers"]
|
||||
@@ -95,25 +95,44 @@ async def get_epic_free(bot: Bot, type_event: str):
|
||||
game_dev = pair["value"]
|
||||
if pair["key"] == "publisherName":
|
||||
game_pub = pair["value"]
|
||||
# 如 game['customAttributes'] 未找到则均使用 game_corp 值
|
||||
game_dev = game_dev if game_dev is not None else game_corp
|
||||
game_pub = game_pub if game_pub is not None else game_corp
|
||||
game_desp = game["description"]
|
||||
end_date_iso = game["promotions"]["promotionalOffers"][0][
|
||||
"promotionalOffers"
|
||||
][0]["endDate"][:-1]
|
||||
end_date = datetime.fromisoformat(end_date_iso).strftime(
|
||||
"%b.%d %H:%M"
|
||||
)
|
||||
try:
|
||||
end_date_iso = game["promotions"]["promotionalOffers"][0][
|
||||
"promotionalOffers"
|
||||
][0]["endDate"][:-1]
|
||||
end_date = datetime.fromisoformat(end_date_iso).strftime(
|
||||
"%b.%d %H:%M"
|
||||
)
|
||||
except IndexError:
|
||||
end_date = '未知'
|
||||
# API 返回不包含游戏商店 URL,此处自行拼接,可能出现少数游戏 404 请反馈
|
||||
game_url_part = (
|
||||
(game["productSlug"].replace("/home", ""))
|
||||
if ("/home" in game["productSlug"])
|
||||
else game["productSlug"]
|
||||
)
|
||||
game_url = "https://www.epicgames.com/store/zh-CN/p/{}".format(
|
||||
game_url_part
|
||||
)
|
||||
if game.get("productSlug"):
|
||||
game_url = "https://store.epicgames.com/zh-CN/p/{}".format(
|
||||
game["productSlug"].replace("/home", "")
|
||||
)
|
||||
elif game.get("url"):
|
||||
game_url = game["url"]
|
||||
else:
|
||||
slugs = (
|
||||
[
|
||||
x["pageSlug"]
|
||||
for x in game.get("offerMappings", [])
|
||||
if x.get("pageType") == "productHome"
|
||||
]
|
||||
+ [
|
||||
x["pageSlug"]
|
||||
for x in game.get("catalogNs", {}).get("mappings", [])
|
||||
if x.get("pageType") == "productHome"
|
||||
]
|
||||
+ [
|
||||
x["value"]
|
||||
for x in game.get("customAttributes", [])
|
||||
if "productSlug" in x.get("key")
|
||||
]
|
||||
)
|
||||
game_url = "https://store.epicgames.com/zh-CN{}".format(
|
||||
f"/p/{slugs[0]}" if len(slugs) else ""
|
||||
)
|
||||
if type_event == "Group":
|
||||
_message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format(
|
||||
game_thumbnail,
|
||||
|
||||
+6
-15
@@ -1,6 +1,8 @@
|
||||
from io import BytesIO
|
||||
import imagehash
|
||||
from PIL import Image
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from configs.path_config import TEMP_PATH
|
||||
from utils.image_utils import get_img_hash
|
||||
import random
|
||||
from utils.message_builder import image
|
||||
from nonebot import on_message
|
||||
@@ -8,7 +10,6 @@ from utils.utils import get_message_img, get_message_text
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from configs.config import Config
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME
|
||||
|
||||
|
||||
@@ -90,7 +91,7 @@ async def _(event: GroupMessageEvent):
|
||||
if not img and not msg:
|
||||
return
|
||||
if img:
|
||||
img_hash = await get_fudu_img_hash(img[0], event.group_id)
|
||||
img_hash = await get_fudu_img_hash(img[0])
|
||||
else:
|
||||
img_hash = ""
|
||||
add_msg = msg + "|-|" + img_hash
|
||||
@@ -123,15 +124,5 @@ async def _(event: GroupMessageEvent):
|
||||
await fudu.finish("[[_task|fudu]]" + rst)
|
||||
|
||||
|
||||
async def get_fudu_img_hash(url, group_id):
|
||||
try:
|
||||
if await AsyncHttpx.download_file(
|
||||
url, TEMP_PATH / f"compare_{group_id}_img.jpg"
|
||||
):
|
||||
img_hash = get_img_hash(TEMP_PATH / f"compare_{group_id}_img.jpg")
|
||||
return str(img_hash)
|
||||
else:
|
||||
logger.warning(f"复读下载图片失败...")
|
||||
except Exception as e:
|
||||
logger.warning(f"复读读取图片Hash出错 {type(e)}:{e}")
|
||||
return ""
|
||||
async def get_fudu_img_hash(url):
|
||||
return str(imagehash.average_hash(Image.open(BytesIO((await AsyncHttpx.get(url)).content))))
|
||||
|
||||
@@ -47,7 +47,7 @@ __plugin_block_limit__ = {
|
||||
qr = on_command("原神资源查询", aliases={"原神资源查找"}, priority=5, block=True)
|
||||
qr_lst = on_command("原神资源列表", priority=5, block=True)
|
||||
rex_qr = on_regex(".*?(在哪|在哪里|哪有|哪里有).*?", priority=5, block=True)
|
||||
update_info = on_command("更新原神资源信息", permission=SUPERUSER, priority=1, block=True)
|
||||
update_info = on_regex("^更新原神资源信息$", permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
|
||||
@qr.handle()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from configs.path_config import IMAGE_PATH, TEXT_PATH
|
||||
from configs.path_config import IMAGE_PATH, TEXT_PATH, TEMP_PATH
|
||||
from utils.image_utils import BuildImage
|
||||
from typing import Tuple, List
|
||||
from math import sqrt, pow
|
||||
@@ -30,7 +30,7 @@ class Map:
|
||||
ratio: float = 1,
|
||||
):
|
||||
"""
|
||||
参数:
|
||||
参数:
|
||||
:param resource_name: 资源名称
|
||||
:param center_point: 中心点
|
||||
:param deviation: 坐标误差
|
||||
@@ -118,7 +118,7 @@ class Map:
|
||||
self._generate_best_route()
|
||||
self.map.crop((min_width, min_height, max_width, max_height))
|
||||
rand = random.randint(1, 10000)
|
||||
self.map.save(f"{IMAGE_PATH}/temp/genshin_map_{rand}.png")
|
||||
self.map.save(f"{TEMP_PATH}/genshin_map_{rand}.png")
|
||||
return rand
|
||||
|
||||
# 资源数量
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from pathlib import Path
|
||||
from typing import Tuple, Optional, List
|
||||
from configs.path_config import IMAGE_PATH, TEXT_PATH
|
||||
from configs.path_config import IMAGE_PATH, TEXT_PATH, TEMP_PATH
|
||||
from utils.message_builder import image
|
||||
from services.log import logger
|
||||
from utils.image_utils import BuildImage
|
||||
@@ -57,7 +57,7 @@ async def query_resource(resource_name: str) -> str:
|
||||
None, map_.generate_resource_icon_in_map
|
||||
)
|
||||
return (
|
||||
f"{image(f'genshin_map_{rand}.png', 'temp')}"
|
||||
f"{image(TEMP_PATH / f'genshin_map_{rand}.png')}"
|
||||
f"\n\n※ {resource_name} 一共找到 {count} 个位置点\n※ 数据来源于米游社wiki"
|
||||
)
|
||||
|
||||
@@ -172,28 +172,29 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
|
||||
if data["message"] == "OK":
|
||||
data = json.loads(data["data"]["info"]["detail"])
|
||||
CENTER_POINT = (data["origin"][0], data["origin"][1])
|
||||
if not _map.exists():
|
||||
if not _map.exists() or flag:
|
||||
data = data["slices"]
|
||||
idx = 0
|
||||
for _map_data in data[0]:
|
||||
map_url = _map_data["url"]
|
||||
await download_image(
|
||||
map_url,
|
||||
map_path / f"{idx}.png",
|
||||
semaphore,
|
||||
force_flag=flag,
|
||||
)
|
||||
BuildImage(
|
||||
0, 0, background=f"{map_path}/{idx}.png", ratio=MAP_RATIO
|
||||
).save()
|
||||
idx += 1
|
||||
_w, h = BuildImage(0, 0, background=f"{map_path}/0.png").size
|
||||
w = _w * len(os.listdir(map_path))
|
||||
map_file = BuildImage(w, h, _w, h, ratio=MAP_RATIO)
|
||||
w_len = len(data[0])
|
||||
h_len = len(data)
|
||||
for _map_data in data:
|
||||
for _map in _map_data:
|
||||
map_url = _map["url"]
|
||||
await download_image(
|
||||
map_url,
|
||||
map_path / f"{idx}.png",
|
||||
semaphore,
|
||||
force_flag=flag,
|
||||
)
|
||||
BuildImage(
|
||||
0, 0, background=f"{map_path}/{idx}.png", ratio=MAP_RATIO
|
||||
).save()
|
||||
idx += 1
|
||||
w, h = BuildImage(0, 0, background=f"{map_path}/0.png").size
|
||||
map_file = BuildImage(w * w_len, h * h_len, w, h, ratio=MAP_RATIO)
|
||||
for i in range(idx):
|
||||
map_file.paste(
|
||||
BuildImage(0, 0, background=f"{map_path}/{i}.png")
|
||||
)
|
||||
img = BuildImage(0, 0, background=f"{map_path}/{i}.png")
|
||||
await map_file.apaste(img)
|
||||
map_file.save(f"{map_path}/map.png")
|
||||
else:
|
||||
logger.warning(f'获取原神地图失败 msg: {data["message"]}')
|
||||
@@ -202,7 +203,7 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
|
||||
except (TimeoutError, ConnectTimeout):
|
||||
logger.warning("下载原神地图数据超时....")
|
||||
except Exception as e:
|
||||
logger.error(f"下载原神地图数据超时 {type(e)}:{e}")
|
||||
logger.error(f"下载原神地图数据失败 {type(e)}:{e}")
|
||||
|
||||
|
||||
# 下载资源类型数据
|
||||
|
||||
@@ -19,15 +19,18 @@ class Genshin(db.Model):
|
||||
resin_remind = db.Column(db.Boolean(), default=False) # 树脂提醒
|
||||
resin_recovery_time = db.Column(db.DateTime(timezone=True)) # 满树脂提醒日期
|
||||
bind_group = db.Column(db.BigInteger())
|
||||
login_ticket = db.Column(db.String(), default="")
|
||||
stuid = db.Column(db.String(), default="")
|
||||
stoken = db.Column(db.String(), default="")
|
||||
|
||||
_idx1 = db.Index("genshin_uid_idx1", "user_qq", "uid", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_uid(cls, user_qq: int, uid: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加一个uid
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
@@ -44,9 +47,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_mys_id(cls, uid: int, mys_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置米游社id
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param mys_id: 米游社id
|
||||
"""
|
||||
@@ -60,9 +63,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_bind_group(cls, uid: int, bind_group) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
绑定group_id,除私聊外的提醒将在此群发送
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
:param bind_group: 群号
|
||||
"""
|
||||
@@ -76,9 +79,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_bind_group(cls, uid: int) -> Optional[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户绑定的群聊
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
"""
|
||||
user = await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -89,9 +92,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_cookie(cls, uid: int, cookie: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param cookie: 米游社id
|
||||
"""
|
||||
@@ -105,9 +108,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_resin_remind(cls, uid: int, flag: bool) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置体力提醒
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param flag: 开关状态
|
||||
"""
|
||||
@@ -121,9 +124,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_user_resin_recovery_time(cls, uid: int, date: datetime):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置体力完成时间
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
:param date: 提醒日期
|
||||
"""
|
||||
@@ -134,9 +137,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_resin_recovery_time(cls, uid: int) -> Optional[datetime]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取体力完成时间
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
"""
|
||||
u = await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -147,7 +150,7 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_all_resin_remind_user(cls) -> List["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有开启体力提醒的用户
|
||||
"""
|
||||
return await cls.query.where(cls.resin_remind == True).gino.all()
|
||||
@@ -155,9 +158,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def clear_resin_remind_time(cls, uid: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
清空提醒日期
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
"""
|
||||
user = await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -169,9 +172,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置米游社/原神自动签到
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param flag: 开关状态
|
||||
"""
|
||||
@@ -185,7 +188,7 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_all_auto_sign_user(cls) -> List["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有开启自动签到的用户
|
||||
"""
|
||||
return await cls.query.where(cls.auto_sign == True).gino.all()
|
||||
@@ -193,7 +196,7 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_all_sign_user(cls) -> List["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取 原神 所有今日签到用户
|
||||
"""
|
||||
return await cls.query.where(cls.auto_sign_time != None).gino.all()
|
||||
@@ -201,9 +204,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def clear_sign_time(cls, uid: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
清空签到日期
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
"""
|
||||
user = await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -215,9 +218,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def random_sign_time(cls, uid: int) -> Optional[datetime]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
随机签到时间
|
||||
说明:
|
||||
说明:
|
||||
:param uid: uid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
@@ -245,9 +248,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_query_cookie(cls, uid: int) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取查询角色信息cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
# 查找用户今日是否已经查找过,防止重复
|
||||
@@ -265,9 +268,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_cookie(cls, uid: int, flag: bool = False) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid:原神uid
|
||||
:param flag:必须使用自己的cookie
|
||||
"""
|
||||
@@ -279,9 +282,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_by_qq(cls, user_qq: int) -> Optional["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过qq获取用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq
|
||||
"""
|
||||
return await cls.query.where(cls.user_qq == user_qq).gino.first()
|
||||
@@ -289,9 +292,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_by_uid(cls, uid: int) -> Optional["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过uid获取用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param uid: qq
|
||||
"""
|
||||
return await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -299,9 +302,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_uid(cls, user_qq: int) -> Optional[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户uid
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq:用户qq
|
||||
"""
|
||||
return await cls._get_user_data(user_qq, None, "uid")
|
||||
@@ -311,7 +314,7 @@ class Genshin(db.Model):
|
||||
"""
|
||||
说嘛:
|
||||
获取用户米游社id
|
||||
参数:
|
||||
参数:
|
||||
:param uid:原神id
|
||||
"""
|
||||
return await cls._get_user_data(None, uid, "mys_id")
|
||||
@@ -319,9 +322,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def delete_user_cookie(cls, uid: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除用户cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
@@ -332,9 +335,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def delete_user(cls, user_qq: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除用户数据
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = cls.query.where(cls.user_qq == user_qq).with_for_update()
|
||||
@@ -347,9 +350,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def _add_query_uid(cls, uid: int, cookie_uid: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加每日查询重复uid的cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param cookie_uid: cookie的uid
|
||||
"""
|
||||
@@ -362,9 +365,9 @@ class Genshin(db.Model):
|
||||
cls, user_qq: Optional[int], uid: Optional[int], type_: str
|
||||
) -> Optional[Union[int, str]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户数据
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param uid: uid
|
||||
:param type_: 数据类型
|
||||
@@ -386,3 +389,96 @@ class Genshin(db.Model):
|
||||
for u in await cls.query.with_for_update().gino.all():
|
||||
if u.today_query_uid:
|
||||
await u.update(today_query_uid="").apply()
|
||||
|
||||
@classmethod
|
||||
async def set_stuid(cls, uid: int, stuid: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置stuid
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param stuid: stuid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(stuid=stuid).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def set_stoken(cls, uid: int, stoken: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置stoken
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param stoken: stoken
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(stoken=stoken).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def set_login_ticket(cls, uid: int, login_ticket: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
设置login_ticket
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param login_ticket: login_ticket
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
await user.update(login_ticket=login_ticket).apply()
|
||||
return True
|
||||
return False
|
||||
|
||||
# 获取login_ticket
|
||||
@classmethod
|
||||
async def get_login_ticket(cls, uid: int) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
获取login_ticket
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.login_ticket
|
||||
return None
|
||||
|
||||
# 获取stuid
|
||||
@classmethod
|
||||
async def get_stuid(cls, uid: int) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
获取stuid
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.stuid
|
||||
return None
|
||||
|
||||
# 获取stoken
|
||||
@classmethod
|
||||
async def get_stoken(cls, uid: int) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
获取stoken
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid)
|
||||
user = await query.gino.first()
|
||||
if user:
|
||||
return user.stoken
|
||||
return None
|
||||
|
||||
@@ -5,6 +5,8 @@ from .._models import Genshin
|
||||
from services.log import logger
|
||||
from nonebot.params import CommandArg, Command
|
||||
from typing import Tuple
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import json
|
||||
|
||||
|
||||
__zx_plugin_name__ = "原神绑定"
|
||||
@@ -39,6 +41,10 @@ bind = on_command(
|
||||
|
||||
unbind = on_command("原神解绑", priority=5, block=True)
|
||||
|
||||
web_Api = "https://api-takumi.mihoyo.com"
|
||||
bbs_Cookie_url = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}"
|
||||
bbs_Cookie_url2 = web_Api + "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}"
|
||||
|
||||
|
||||
@bind.handle()
|
||||
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
@@ -64,9 +70,13 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message
|
||||
_x = f"已成功为uid:{uid} 设置米游社id:{msg}"
|
||||
else:
|
||||
if not msg:
|
||||
await bind.finish(
|
||||
"私聊发送!!\n打开 https://bbs.mihoyo.com/ys/\n登录后按F12点击控制台输入document.cookie复制输出的内容即可"
|
||||
)
|
||||
await bind.finish("""私聊发送!!
|
||||
1.以无痕模式打开浏览器(Edge请新建InPrivate窗口)
|
||||
2.打开http://bbs.mihoyo.com/ys/并登陆
|
||||
3.登陆后打开http://user.mihoyo.com/进行登陆
|
||||
4.按下F12,打开控制台,输入以下命令:
|
||||
var cookie=document.cookie;var ask=confirm('Cookie:'+cookie+'\\n\\nDo you want to copy the cookie to the clipboard?');if(ask==true){copy(cookie);msg=cookie}else{msg='Cancel'}
|
||||
5.私聊发送:原神绑定cookie 刚刚复制的cookie""")
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
await bind.finish("请立即撤回你的消息并私聊发送!")
|
||||
uid = await Genshin.get_user_uid(event.user_id)
|
||||
@@ -77,6 +87,35 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message
|
||||
if msg.endswith('"') or msg.endswith("'"):
|
||||
msg = msg[:-1]
|
||||
await Genshin.set_cookie(uid, msg)
|
||||
cookie = msg
|
||||
# 用: 代替=, ,代替;
|
||||
cookie = '{"' + cookie.replace('=', '": "').replace("; ", '","') + '"}'
|
||||
print(cookie)
|
||||
cookie_json = json.loads(cookie)
|
||||
print(cookie_json)
|
||||
if 'login_ticket' not in cookie_json:
|
||||
await bind.finish("请发送正确完整的cookie!")
|
||||
login_ticket = cookie_json['login_ticket']
|
||||
# try:
|
||||
res = await AsyncHttpx.get(url=bbs_Cookie_url.format(login_ticket))
|
||||
res.encoding = "utf-8"
|
||||
data = json.loads(res.text)
|
||||
print(data)
|
||||
if "成功" in data["data"]["msg"]:
|
||||
stuid = str(data["data"]["cookie_info"]["account_id"])
|
||||
res = await AsyncHttpx.get(url=bbs_Cookie_url2.format(
|
||||
login_ticket, stuid))
|
||||
res.encoding = "utf-8"
|
||||
data = json.loads(res.text)
|
||||
stoken = data["data"]["list"][0]["token"]
|
||||
# await Genshin.set_cookie(uid, cookie)
|
||||
await Genshin.set_stoken(uid, stoken)
|
||||
await Genshin.set_stuid(uid, stuid)
|
||||
await Genshin.set_login_ticket(uid, login_ticket)
|
||||
# except Exception as e:
|
||||
# await bind.finish("获取登陆信息失败,请检查cookie是否正确或更新cookie")
|
||||
elif data["data"]["msg"] == "登录信息已失效,请重新登录":
|
||||
await bind.finish("登录信息失效,请重新获取最新cookie进行绑定")
|
||||
_x = f"已成功为uid:{uid} 设置cookie"
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
await Genshin.set_bind_group(uid, event.group_id)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from .data_source import get_sign_reward_list, genshin_sign
|
||||
from ..mihoyobbs_sign import mihoyobbs_sign
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
@@ -14,15 +15,15 @@ __plugin_usage__ = """
|
||||
usage:
|
||||
米游社原神签到,需要uid以及cookie
|
||||
且在第二天自动排序签到时间
|
||||
# 不听,就要手动签到!(使用命令 “原神我硬签 or 米游社我硬签”
|
||||
# 不听,就要手动签到!(使用命令 “原神我硬签
|
||||
指令:
|
||||
开/关原神自动签到
|
||||
原神我硬签
|
||||
""".strip()
|
||||
__plugin_des__ = "原神懒人签到"
|
||||
__plugin_cmd__ = ["开启/关闭原神自动签到", "原神我硬签"]
|
||||
__plugin_cmd__ = ["开启/关闭原神自动签到", "原神我硬签", "查看我的cookie"]
|
||||
__plugin_type__ = ("原神相关",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_version__ = 0.2
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
@@ -33,7 +34,7 @@ __plugin_settings__ = {
|
||||
|
||||
|
||||
genshin_matcher = on_command(
|
||||
"开原神自动签到", aliases={"关原神自动签到", "原神我硬签"}, priority=5, block=True
|
||||
"开原神自动签到", aliases={"关原神自动签到", "原神我硬签", "查看我的cookie"}, priority=5, block=True
|
||||
)
|
||||
|
||||
|
||||
@@ -41,17 +42,25 @@ genshin_matcher = on_command(
|
||||
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
|
||||
cmd = cmd[0]
|
||||
uid = await Genshin.get_user_uid(event.user_id)
|
||||
if cmd == "查看我的cookie":
|
||||
my_cookie = await Genshin.get_user_cookie(uid, True)
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
await genshin_matcher.finish("请私聊查看您的cookie!")
|
||||
await genshin_matcher.finish("您的cookie为" + my_cookie)
|
||||
if not uid or not await Genshin.get_user_cookie(uid, True):
|
||||
await genshin_matcher.finish("请先绑定uid和cookie!")
|
||||
if "account_id" not in await Genshin.get_user_cookie(uid, True):
|
||||
await genshin_matcher.finish("请更新cookie!")
|
||||
# if "account_id" not in await Genshin.get_user_cookie(uid, True):
|
||||
# await genshin_matcher.finish("请更新cookie!")
|
||||
if cmd == "原神我硬签":
|
||||
try:
|
||||
await genshin_matcher.send("正在进行签到...", at_sender=True)
|
||||
msg = await genshin_sign(uid)
|
||||
return_data = await mihoyobbs_sign(event.user_id)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, "
|
||||
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{uid} 原神签到"
|
||||
)
|
||||
logger.info(msg)
|
||||
# 硬签,移除定时任务
|
||||
try:
|
||||
for i in range(3):
|
||||
@@ -63,7 +72,7 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
|
||||
await u.clear_sign_time(uid)
|
||||
next_date = await Genshin.random_sign_time(uid)
|
||||
add_job(event.user_id, uid, next_date)
|
||||
msg += f"因开启自动签到\n下一次签到时间为:{next_date.replace(microsecond=0)}"
|
||||
msg += f"\n{return_data}\n因开启自动签到\n下一次签到时间为:{next_date.replace(microsecond=0)}"
|
||||
except Exception as e:
|
||||
msg = "原神签到失败..请尝试检查cookie或报告至管理员!"
|
||||
logger.info(
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from configs.config import Config
|
||||
from services.log import logger
|
||||
from .._utils import random_hex, get_old_ds
|
||||
from ..mihoyobbs_sign.setting import *
|
||||
from .._models import Genshin
|
||||
from typing import Optional, Dict
|
||||
import hashlib
|
||||
import random
|
||||
import string
|
||||
import uuid
|
||||
import time
|
||||
|
||||
|
||||
async def genshin_sign(uid: int) -> Optional[str]:
|
||||
@@ -16,22 +21,62 @@ async def genshin_sign(uid: int) -> Optional[str]:
|
||||
return "签到失败..."
|
||||
status = data["message"]
|
||||
if status == "OK":
|
||||
sign_info = await _get_sign_info(uid)
|
||||
if sign_info:
|
||||
sign_info = sign_info["data"]
|
||||
sign_list = await get_sign_reward_list()
|
||||
get_reward = sign_list["data"]["awards"][
|
||||
int(sign_info["total_sign_day"]) - 1
|
||||
]["name"]
|
||||
reward_num = sign_list["data"]["awards"][
|
||||
int(sign_info["total_sign_day"]) - 1
|
||||
]["cnt"]
|
||||
get_im = f"本次签到获得:{get_reward}x{reward_num}"
|
||||
if status == "OK" and sign_info["is_sign"]:
|
||||
return f"\n原神签到成功!\n{get_im}\n本月漏签次数:{sign_info['sign_cnt_missed']}"
|
||||
try:
|
||||
sign_info = await _get_sign_info(uid)
|
||||
if sign_info:
|
||||
sign_info = sign_info["data"]
|
||||
sign_list = await get_sign_reward_list()
|
||||
get_reward = sign_list["data"]["awards"][
|
||||
int(sign_info["total_sign_day"]) - 1
|
||||
]["name"]
|
||||
reward_num = sign_list["data"]["awards"][
|
||||
int(sign_info["total_sign_day"]) - 1
|
||||
]["cnt"]
|
||||
get_im = f"本次签到获得:{get_reward}x{reward_num}"
|
||||
logger.info("get_im:" + get_im + "\nsign_info:" + str(sign_info))
|
||||
if status == "OK" and sign_info["is_sign"]:
|
||||
return f"原神签到成功!\n{get_im}\n本月漏签次数:{sign_info['sign_cnt_missed']}"
|
||||
except Exception as e:
|
||||
logger.error(f"原神签到发生错误 UID:{str(data)}")
|
||||
return f"原神签到发生错误: {str(data)}"
|
||||
else:
|
||||
return status
|
||||
return None
|
||||
if data["data"]["risk_code"] == 375:
|
||||
return "原神签到失败\n账号可能被风控,请前往米游社手动签到!"
|
||||
return str(data)
|
||||
|
||||
|
||||
# 获取请求Header里的DS 当web为true则生成网页端的DS
|
||||
def get_ds(web: bool) -> str:
|
||||
if web:
|
||||
n = mihoyobbs_Salt_web
|
||||
else:
|
||||
n = mihoyobbs_Salt
|
||||
i = str(timestamp())
|
||||
r = random_text(6)
|
||||
c = md5("salt=" + n + "&t=" + i + "&r=" + r)
|
||||
return f"{i},{r},{c}"
|
||||
|
||||
|
||||
# 时间戳
|
||||
def timestamp() -> int:
|
||||
return int(time.time())
|
||||
|
||||
|
||||
def random_text(num: int) -> str:
|
||||
return ''.join(random.sample(string.ascii_lowercase + string.digits, num))
|
||||
|
||||
|
||||
def md5(text: str) -> str:
|
||||
md5 = hashlib.md5()
|
||||
md5.update(text.encode())
|
||||
return md5.hexdigest()
|
||||
|
||||
|
||||
# 生成一个device id
|
||||
def get_device_id(cookie) -> str:
|
||||
return str(uuid.uuid3(uuid.NAMESPACE_URL, cookie)).replace(
|
||||
'-', '').upper()
|
||||
|
||||
|
||||
async def _sign(uid: int, server_id: str = "cn_gf01") -> Optional[Dict[str, str]]:
|
||||
@@ -43,20 +88,16 @@ async def _sign(uid: int, server_id: str = "cn_gf01") -> Optional[Dict[str, str]
|
||||
if str(uid)[0] == "5":
|
||||
server_id = "cn_qd01"
|
||||
try:
|
||||
cookie = await Genshin.get_user_cookie(uid, True)
|
||||
headers['DS'] = get_ds(web=True)
|
||||
headers['Referer'] = 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true' \
|
||||
f'&act_id={genshin_Act_id}&utm_source=bbs&utm_medium=mys&utm_campaign=icon'
|
||||
headers['Cookie'] = cookie
|
||||
headers['x-rpc-device_id'] = get_device_id(cookie)
|
||||
req = await AsyncHttpx.post(
|
||||
url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign",
|
||||
headers={
|
||||
"User_Agent": "Mozilla/5.0 (Linux; Android 10; MIX 2 Build/QKQ1.190825.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.101 Mobile Safari/537.36 miHoYoBBS/2.3.0",
|
||||
"Cookie": await Genshin.get_user_cookie(int(uid), True),
|
||||
"x-rpc-device_id": random_hex(32),
|
||||
"Origin": "https://webstatic.mihoyo.com",
|
||||
"X_Requested_With": "com.mihoyo.hyperion",
|
||||
"DS": get_old_ds(),
|
||||
"x-rpc-client_type": "5",
|
||||
"Referer": "https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=e202009291139501&utm_source=bbs&utm_medium=mys&utm_campaign=icon",
|
||||
"x-rpc-app_version": "2.3.0",
|
||||
},
|
||||
json={"act_id": "e202009291139501", "uid": uid, "region": server_id},
|
||||
url=genshin_Signurl,
|
||||
headers=headers,
|
||||
json={"act_id": genshin_Act_id, "uid": uid, "region": server_id},
|
||||
)
|
||||
return req.json()
|
||||
except Exception as e:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from .data_source import genshin_sign
|
||||
from ..mihoyobbs_sign import mihoyobbs_sign
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from utils.message_builder import at
|
||||
from services.log import logger
|
||||
@@ -57,6 +58,11 @@ async def _sign(user_id: int, uid: int, count: int):
|
||||
:param uid: uid
|
||||
:param count: 执行次数
|
||||
"""
|
||||
try:
|
||||
return_data = await mihoyobbs_sign(user_id)
|
||||
except Exception as e:
|
||||
logger.error(f"mihoyobbs_sign error:{e}")
|
||||
return_data = "米游社签到失败,请尝试发送'米游社签到'进行手动签到"
|
||||
if count < 3:
|
||||
try:
|
||||
msg = await genshin_sign(uid)
|
||||
@@ -101,6 +107,7 @@ async def _sign(user_id: int, uid: int, count: int):
|
||||
bot = get_bot()
|
||||
if bot:
|
||||
if user_id in [x["user_id"] for x in await bot.get_friend_list()]:
|
||||
await bot.send_private_msg(user_id=user_id, message=return_data)
|
||||
await bot.send_private_msg(user_id=user_id, message=msg)
|
||||
else:
|
||||
if not (group_id := await Genshin.get_bind_group(uid)):
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
# from .init_task import add_job, scheduler, _sign
|
||||
# from apscheduler.jobstores.base import JobLookupError
|
||||
from .._models import Genshin
|
||||
from nonebot.params import Command
|
||||
from typing import Tuple
|
||||
from .mihoyobbs import *
|
||||
|
||||
|
||||
__zx_plugin_name__ = "米游社自动签到"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
发送'米游社签到'或绑定原神自动签到
|
||||
即可手动/自动进行米游社签到
|
||||
(若启用了原神自动签到会在签到原神同时完成米游币领取)
|
||||
--> 每天白嫖90-110米游币不香吗
|
||||
注:需要重新绑定原神cookie!!!
|
||||
遇到问题请提issue或@作者
|
||||
""".strip()
|
||||
__plugin_des__ = "米游社自动签到任务"
|
||||
__plugin_cmd__ = ["米游社签到", "米游社我硬签"]
|
||||
__plugin_type__ = ("原神相关",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HDU_Nbsp"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["原神签到"],
|
||||
}
|
||||
|
||||
mihoyobbs_matcher = on_command(
|
||||
"米游社签到", aliases={"米游社我硬签"}, priority=5, block=True
|
||||
)
|
||||
|
||||
|
||||
@mihoyobbs_matcher.handle()
|
||||
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
|
||||
await mihoyobbs_matcher.send("提交米游社签到申请", at_sender=True)
|
||||
return_data = await mihoyobbs_sign(event.user_id)
|
||||
if return_data:
|
||||
await mihoyobbs_matcher.finish(return_data, at_sender=True)
|
||||
else:
|
||||
await mihoyobbs_matcher.finish("米游社签到失败,请查看控制台输出", at_sender=True)
|
||||
|
||||
|
||||
async def mihoyobbs_sign(user_id):
|
||||
uid = await Genshin.get_user_uid(user_id)
|
||||
if not uid or not await Genshin.get_user_cookie(uid, True):
|
||||
await mihoyobbs_matcher.finish("请先绑定uid和cookie!", at_sender=True)
|
||||
stuid = await Genshin.get_stuid(uid)
|
||||
stoken = await Genshin.get_stoken(uid)
|
||||
cookie = await Genshin.get_user_cookie(uid)
|
||||
bbs = mihoyobbs.Mihoyobbs(stuid=stuid, stoken=stoken, cookie=cookie)
|
||||
await bbs.init()
|
||||
return_data = ""
|
||||
if bbs.Task_do["bbs_Sign"] and bbs.Task_do["bbs_Read_posts"] and bbs.Task_do["bbs_Like_posts"] and \
|
||||
bbs.Task_do["bbs_Share"]:
|
||||
return_data += f"今天的米游社签到任务已经全部完成了!\n" \
|
||||
f"一共获得{mihoyobbs.today_have_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
|
||||
logger.info(f"今天已经全部完成了!一共获得{mihoyobbs.today_have_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币")
|
||||
else:
|
||||
i = 0
|
||||
print("开始签到")
|
||||
print(mihoyobbs.today_have_get_coins)
|
||||
while mihoyobbs.today_get_coins != 0 and i < 3:
|
||||
# if i > 0:
|
||||
await bbs.refresh_list()
|
||||
await bbs.signing()
|
||||
await bbs.read_posts()
|
||||
await bbs.like_posts()
|
||||
await bbs.share_post()
|
||||
await bbs.get_tasks_list()
|
||||
i += 1
|
||||
return_data += "\n" + f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币\n" \
|
||||
f"还能获得{mihoyobbs.today_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
|
||||
logger.info(f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币,"
|
||||
f"还能获得{mihoyobbs.today_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币")
|
||||
return return_data
|
||||
@@ -0,0 +1,6 @@
|
||||
class CookieError(Exception):
|
||||
def __init__(self, info):
|
||||
self.info = info
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.info)
|
||||
@@ -0,0 +1,193 @@
|
||||
from services.log import logger
|
||||
from .error import CookieError
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from .setting import *
|
||||
from .tools import *
|
||||
import json
|
||||
|
||||
today_get_coins = 0
|
||||
today_have_get_coins = 0 # 这个变量以后可能会用上,先留着了
|
||||
Have_coins = 0
|
||||
|
||||
|
||||
class Mihoyobbs:
|
||||
def __init__(self, stuid: str, stoken: str, cookie: str) -> None:
|
||||
self.postsList = None
|
||||
self.headers = {
|
||||
"DS": get_ds(web=False),
|
||||
"cookie": f'stuid={stuid};stoken={stoken}',
|
||||
"x-rpc-client_type": mihoyobbs_Client_type,
|
||||
"x-rpc-app_version": mihoyobbs_Version,
|
||||
"x-rpc-sys_version": "6.0.1",
|
||||
"x-rpc-channel": "miyousheluodi",
|
||||
"x-rpc-device_id": get_device_id(cookie=cookie),
|
||||
"x-rpc-device_name": random_text(random.randint(1, 10)),
|
||||
"x-rpc-device_model": "Mi 10",
|
||||
"Referer": "https://app.mihoyo.com",
|
||||
"Host": "bbs-api.mihoyo.com",
|
||||
"User-Agent": "okhttp/4.8.0"
|
||||
}
|
||||
self.Task_do = {
|
||||
"bbs_Sign": False,
|
||||
"bbs_Read_posts": False,
|
||||
"bbs_Read_posts_num": 3,
|
||||
"bbs_Like_posts": False,
|
||||
"bbs_Like_posts_num": 5,
|
||||
"bbs_Share": False
|
||||
}
|
||||
|
||||
async def init(self):
|
||||
await self.get_tasks_list()
|
||||
# 如果这三个任务都做了就没必要获取帖子了
|
||||
if self.Task_do["bbs_Read_posts"] and self.Task_do["bbs_Like_posts"] and self.Task_do["bbs_Share"]:
|
||||
pass
|
||||
else:
|
||||
self.postsList = await self.get_list()
|
||||
|
||||
async def refresh_list(self) -> None:
|
||||
self.postsList = await self.get_list()
|
||||
|
||||
# 获取任务列表,用来判断做了哪些任务
|
||||
async def get_tasks_list(self):
|
||||
global today_get_coins
|
||||
global today_have_get_coins
|
||||
global Have_coins
|
||||
logger.info("正在获取任务列表")
|
||||
req = await AsyncHttpx.get(url=bbs_Tasks_list, headers=self.headers)
|
||||
data = req.json()
|
||||
if "err" in data["message"] or data["retcode"] == -100:
|
||||
logger.error("获取任务列表失败,你的cookie可能已过期,请重新设置cookie。")
|
||||
raise CookieError('Cookie expires')
|
||||
else:
|
||||
today_get_coins = data["data"]["can_get_points"]
|
||||
today_have_get_coins = data["data"]["already_received_points"]
|
||||
Have_coins = data["data"]["total_points"]
|
||||
# 如果当日可获取米游币数量为0直接判断全部任务都完成了
|
||||
if today_get_coins == 0:
|
||||
self.Task_do["bbs_Sign"] = True
|
||||
self.Task_do["bbs_Read_posts"] = True
|
||||
self.Task_do["bbs_Like_posts"] = True
|
||||
self.Task_do["bbs_Share"] = True
|
||||
else:
|
||||
# 如果第0个大于或等于62则直接判定任务没做
|
||||
if data["data"]["states"][0]["mission_id"] >= 62:
|
||||
logger.info(f"今天可以获得{today_get_coins}个米游币")
|
||||
pass
|
||||
else:
|
||||
logger.info(f"还有任务未完成,今天还能获得{today_get_coins}米游币")
|
||||
for i in data["data"]["states"]:
|
||||
# 58是讨论区签到
|
||||
if i["mission_id"] == 58:
|
||||
if i["is_get_award"]:
|
||||
self.Task_do["bbs_Sign"] = True
|
||||
# 59是看帖子
|
||||
elif i["mission_id"] == 59:
|
||||
if i["is_get_award"]:
|
||||
self.Task_do["bbs_Read_posts"] = True
|
||||
else:
|
||||
self.Task_do["bbs_Read_posts_num"] -= i["happened_times"]
|
||||
# 60是给帖子点赞
|
||||
elif i["mission_id"] == 60:
|
||||
if i["is_get_award"]:
|
||||
self.Task_do["bbs_Like_posts"] = True
|
||||
else:
|
||||
self.Task_do["bbs_Like_posts_num"] -= i["happened_times"]
|
||||
# 61是分享帖子
|
||||
elif i["mission_id"] == 61:
|
||||
if i["is_get_award"]:
|
||||
self.Task_do["bbs_Share"] = True
|
||||
# 分享帖子,是最后一个任务,到这里了下面都是一次性任务,直接跳出循环
|
||||
break
|
||||
|
||||
# 获取要帖子列表
|
||||
async def get_list(self) -> list:
|
||||
temp_list = []
|
||||
logger.info("正在获取帖子列表......")
|
||||
req = await AsyncHttpx.get(url=bbs_List_url.format(mihoyobbs_List_Use[0]["forumId"]),
|
||||
headers=self.headers)
|
||||
data = req.json()["data"]["list"]
|
||||
for n in range(5):
|
||||
r_l = random.choice(data)
|
||||
while r_l["post"]["subject"] in str(temp_list):
|
||||
r_l = random.choice(data)
|
||||
temp_list.append([r_l["post"]["post_id"], r_l["post"]["subject"]])
|
||||
# temp_list.append([data["data"]["list"][n]["post"]["post_id"], data["data"]["list"][n]["post"]["subject"]])
|
||||
|
||||
logger.info("已获取{}个帖子".format(len(temp_list)))
|
||||
return temp_list
|
||||
|
||||
# 进行签到操作
|
||||
async def signing(self):
|
||||
if self.Task_do["bbs_Sign"]:
|
||||
logger.info("讨论区任务已经完成过了~")
|
||||
else:
|
||||
logger.info("正在签到......")
|
||||
header = {}
|
||||
header.update(self.headers)
|
||||
for i in mihoyobbs_List_Use:
|
||||
header["DS"] = get_ds2("", json.dumps({"gids": i["id"]}))
|
||||
req = await AsyncHttpx.post(url=bbs_Sign_url, json={"gids": i["id"]}, headers=header)
|
||||
data = req.json()
|
||||
if "err" not in data["message"]:
|
||||
logger.info(str(i["name"] + data["message"]))
|
||||
time.sleep(random.randint(2, 8))
|
||||
else:
|
||||
logger.error("签到失败,你的cookie可能已过期,请重新设置cookie。")
|
||||
raise CookieError('Cookie expires')
|
||||
|
||||
# 看帖子
|
||||
async def read_posts(self):
|
||||
if self.Task_do["bbs_Read_posts"]:
|
||||
logger.info("看帖任务已经完成过了~")
|
||||
else:
|
||||
logger.info("正在看帖......")
|
||||
for i in range(self.Task_do["bbs_Read_posts_num"]):
|
||||
req = await AsyncHttpx.get(url=bbs_Detail_url.format(self.postsList[i][0]), headers=self.headers)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
logger.debug("看帖:{} 成功".format(self.postsList[i][1]))
|
||||
time.sleep(random.randint(2, 8))
|
||||
|
||||
# 点赞
|
||||
async def like_posts(self):
|
||||
if self.Task_do["bbs_Like_posts"]:
|
||||
logger.info("点赞任务已经完成过了~")
|
||||
else:
|
||||
logger.info("正在点赞......")
|
||||
for i in range(self.Task_do["bbs_Like_posts_num"]):
|
||||
req = await AsyncHttpx.post(url=bbs_Like_url, headers=self.headers,
|
||||
json={"post_id": self.postsList[i][0], "is_cancel": False})
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
logger.debug("点赞:{} 成功".format(self.postsList[i][1]))
|
||||
# 判断取消点赞是否打开
|
||||
# if config.config["mihoyobbs"]["un_like"] :
|
||||
# time.sleep(random.randint(2, 8))
|
||||
# req = httpx.post(url=bbs_Like_url, headers=self.headers,
|
||||
# json={"post_id": self.postsList[i][0], "is_cancel": True})
|
||||
# data = req.json()
|
||||
# if data["message"] == "OK":
|
||||
# logger.debug("取消点赞:{} 成功".format(self.postsList[i][1]))
|
||||
time.sleep(random.randint(2, 8))
|
||||
|
||||
# 分享操作
|
||||
|
||||
async def share_post(self):
|
||||
if self.Task_do["bbs_Share"]:
|
||||
logger.info("分享任务已经完成过了~")
|
||||
else:
|
||||
logger.info("正在执行分享任务......")
|
||||
for i in range(3):
|
||||
req = await AsyncHttpx.get(url=bbs_Share_url.format(self.postsList[0][0]), headers=self.headers)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
logger.debug("分享:{} 成功".format(self.postsList[0][1]))
|
||||
logger.info("分享任务执行成功......")
|
||||
break
|
||||
else:
|
||||
logger.debug(f"分享任务执行失败,正在执行第{i + 2}次,共3次")
|
||||
time.sleep(random.randint(2, 8))
|
||||
time.sleep(random.randint(2, 8))
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
# 米游社的Salt
|
||||
mihoyobbs_Salt = "z8DRIUjNDT7IT5IZXvrUAxyupA1peND9"
|
||||
mihoyobbs_Salt2 = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v"
|
||||
mihoyobbs_Salt_web = "9nQiU3AV0rJSIBWgdynfoGMGKaklfbM7"
|
||||
# 米游社的版本
|
||||
mihoyobbs_Version = "2.34.1" # Slat和Version相互对应
|
||||
# 米游社的客户端类型
|
||||
mihoyobbs_Client_type = "2" # 1为ios 2为安卓
|
||||
mihoyobbs_Client_type_web = "5" # 4为pc web 5为mobile web
|
||||
# 米游社的分区列表
|
||||
mihoyobbs_List = [{
|
||||
"id": "1",
|
||||
"forumId": "1",
|
||||
"name": "崩坏3",
|
||||
"url": "https://bbs.mihoyo.com/bh3/"
|
||||
}, {
|
||||
"id": "2",
|
||||
"forumId": "26",
|
||||
"name": "原神",
|
||||
"url": "https://bbs.mihoyo.com/ys/"
|
||||
}, {
|
||||
"id": "3",
|
||||
"forumId": "30",
|
||||
"name": "崩坏2",
|
||||
"url": "https://bbs.mihoyo.com/bh2/"
|
||||
}, {
|
||||
"id": "4",
|
||||
"forumId": "37",
|
||||
"name": "未定事件簿",
|
||||
"url": "https://bbs.mihoyo.com/wd/"
|
||||
}, {
|
||||
"id": "5",
|
||||
"forumId": "34",
|
||||
"name": "大别野",
|
||||
"url": "https://bbs.mihoyo.com/dby/"
|
||||
}, {
|
||||
"id": "6",
|
||||
"forumId": "52",
|
||||
"name": "崩坏:星穹铁道",
|
||||
"url": "https://bbs.mihoyo.com/sr/"
|
||||
}, {
|
||||
"id": "8",
|
||||
"forumId": "57",
|
||||
"name": "绝区零",
|
||||
"url": "https://bbs.mihoyo.com/zzz/"
|
||||
}]
|
||||
|
||||
game_id2name = {
|
||||
"bh2_cn": "崩坏2",
|
||||
"bh3_cn": "崩坏3",
|
||||
"nxx_cn": "未定事件簿",
|
||||
"hk4e_cn": "原神",
|
||||
}
|
||||
# Config Load之后run里面进行列表的选择
|
||||
mihoyobbs_List_Use = [{
|
||||
"id": "2",
|
||||
"forumId": "26",
|
||||
"name": "原神",
|
||||
"url": "https://bbs.mihoyo.com/ys/"
|
||||
},
|
||||
# 不玩原神可以把签到讨论区换为大别墅
|
||||
# {
|
||||
# "id": "5",
|
||||
# "forumId": "34",
|
||||
# "name": "大别野",
|
||||
# "url": "https://bbs.mihoyo.com/dby/"
|
||||
# }
|
||||
]
|
||||
|
||||
# 游戏签到的请求头
|
||||
headers = {
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'DS': "",
|
||||
'Origin': 'https://webstatic.mihoyo.com',
|
||||
'x-rpc-app_version': mihoyobbs_Version,
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||
f'Version/4.0 Chrome/103.0.5060.129 Mobile Safari/537.36 miHoYoBBS/{mihoyobbs_Version}',
|
||||
'x-rpc-client_type': mihoyobbs_Client_type_web,
|
||||
'Referer': '',
|
||||
'Accept-Encoding': 'gzip, deflate',
|
||||
'Accept-Language': 'zh-CN,en-US;q=0.8',
|
||||
'X-Requested-With': 'com.mihoyo.hyperion',
|
||||
"Cookie": "",
|
||||
'x-rpc-device_id': ""
|
||||
}
|
||||
|
||||
# 通用设置
|
||||
bbs_Api = "https://bbs-api.mihoyo.com"
|
||||
web_Api = "https://api-takumi.mihoyo.com"
|
||||
account_Info_url = web_Api + "/binding/api/getUserGameRolesByCookie?game_biz="
|
||||
|
||||
# 米游社的API列表
|
||||
bbs_Cookie_url = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}"
|
||||
bbs_Cookie_url2 = web_Api + "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}"
|
||||
bbs_Tasks_list = bbs_Api + "/apihub/sapi/getUserMissionsState" # 获取任务列表
|
||||
bbs_Sign_url = bbs_Api + "/apihub/app/api/signIn" # post
|
||||
bbs_List_url = bbs_Api + "/post/api/getForumPostList?forum_id={}&is_good=false&is_hot=false&page_size=20&sort_type=1"
|
||||
bbs_Detail_url = bbs_Api + "/post/api/getPostFull?post_id={}"
|
||||
bbs_Share_url = bbs_Api + "/apihub/api/getShareConf?entity_id={}&entity_type=1"
|
||||
bbs_Like_url = bbs_Api + "/apihub/sapi/upvotePost" # post json
|
||||
|
||||
# 崩坏2自动签到相关的相关设置
|
||||
honkai2_Act_id = "e202203291431091"
|
||||
honkai2_checkin_rewards = f'{web_Api}/event/luna/home?lang=zh-cn&act_id={honkai2_Act_id}'
|
||||
honkai2_Is_signurl = web_Api + "/event/luna/info?lang=zh-cn&act_id={}®ion={}&uid={}"
|
||||
honkai2_Sign_url = web_Api + "/event/luna/sign"
|
||||
|
||||
# 崩坏3自动签到相关的设置
|
||||
honkai3rd_Act_id = "e202207181446311"
|
||||
honkai3rd_checkin_rewards = f'{web_Api}/event/luna/home?lang=zh-cn&act_id={honkai3rd_Act_id}'
|
||||
honkai3rd_Is_signurl = web_Api + "/event/luna/info?lang=zh-cn&act_id={}®ion={}&uid={}"
|
||||
honkai3rd_Sign_url = web_Api + "/event/luna/sign"
|
||||
|
||||
# 未定事件簿自动签到相关设置
|
||||
tearsofthemis_Act_id = "e202202251749321"
|
||||
tearsofthemis_checkin_rewards = f'{web_Api}/event/luna/home?lang=zh-cn&act_id={tearsofthemis_Act_id}'
|
||||
tearsofthemis_Is_signurl = honkai2_Is_signurl
|
||||
tearsofthemis_Sign_url = honkai2_Sign_url # 和二崩完全一致
|
||||
|
||||
# 原神自动签到相关的设置
|
||||
genshin_Act_id = "e202009291139501"
|
||||
genshin_checkin_rewards = f'{web_Api}/event/bbs_sign_reward/home?act_id={genshin_Act_id}'
|
||||
genshin_Is_signurl = web_Api + "/event/bbs_sign_reward/info?act_id={}®ion={}&uid={}"
|
||||
genshin_Signurl = web_Api + "/event/bbs_sign_reward/sign"
|
||||
@@ -0,0 +1,65 @@
|
||||
import uuid
|
||||
import time
|
||||
import random
|
||||
import string
|
||||
import hashlib
|
||||
from .setting import *
|
||||
|
||||
|
||||
# md5计算
|
||||
def md5(text: str) -> str:
|
||||
md5 = hashlib.md5()
|
||||
md5.update(text.encode())
|
||||
return md5.hexdigest()
|
||||
|
||||
|
||||
# 随机文本
|
||||
def random_text(num: int) -> str:
|
||||
return ''.join(random.sample(string.ascii_lowercase + string.digits, num))
|
||||
|
||||
|
||||
# 时间戳
|
||||
def timestamp() -> int:
|
||||
return int(time.time())
|
||||
|
||||
|
||||
# 获取请求Header里的DS 当web为true则生成网页端的DS
|
||||
def get_ds(web: bool) -> str:
|
||||
if web:
|
||||
n = mihoyobbs_Salt_web
|
||||
else:
|
||||
n = mihoyobbs_Salt
|
||||
i = str(timestamp())
|
||||
r = random_text(6)
|
||||
c = md5("salt=" + n + "&t=" + i + "&r=" + r)
|
||||
return f"{i},{r},{c}"
|
||||
|
||||
|
||||
# 获取请求Header里的DS(版本2) 这个版本ds之前见到都是查询接口里的
|
||||
def get_ds2(q: str, b: str) -> str:
|
||||
n = mihoyobbs_Salt2
|
||||
i = str(timestamp())
|
||||
r = str(random.randint(100001, 200000))
|
||||
add = f'&b={b}&q={q}'
|
||||
c = md5("salt=" + n + "&t=" + i + "&r=" + r + add)
|
||||
return f"{i},{r},{c}"
|
||||
|
||||
|
||||
# 生成一个device id
|
||||
def get_device_id(cookie) -> str:
|
||||
return str(uuid.uuid3(uuid.NAMESPACE_URL, cookie))
|
||||
|
||||
|
||||
# 获取签到的奖励名称
|
||||
def get_item(raw_data: dict) -> str:
|
||||
temp_name = raw_data["name"]
|
||||
temp_cnt = raw_data["cnt"]
|
||||
return f"{temp_name}x{temp_cnt}"
|
||||
|
||||
|
||||
# 获取明天早晨0点的时间戳
|
||||
def next_day() -> int:
|
||||
now_time = int(time.time())
|
||||
next_day_time = now_time - now_time % 86400 + time.timezone + 86400
|
||||
return next_day_time
|
||||
|
||||
@@ -3,7 +3,6 @@ from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from services.log import logger
|
||||
from .data_source import get_user_memo, get_memo
|
||||
from .._models import Genshin
|
||||
from nonebot.plugin import export
|
||||
|
||||
|
||||
__zx_plugin_name__ = "原神便笺查询"
|
||||
@@ -28,10 +27,6 @@ __plugin_settings__ = {
|
||||
__plugin_block_limit__ = {}
|
||||
|
||||
|
||||
export = export()
|
||||
|
||||
export.get_memo = get_memo
|
||||
|
||||
query_memo_matcher = on_command("原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True)
|
||||
|
||||
|
||||
|
||||
@@ -26,12 +26,17 @@ memo_path.mkdir(exist_ok=True, parents=True)
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
for name, url in zip(
|
||||
["resin.png", "task.png", "resin_discount.png"],
|
||||
[
|
||||
"resin.png", "task.png", "resin_discount.png", "chengehu.png",
|
||||
"zhibian.png"
|
||||
],
|
||||
[
|
||||
"https://upload-bbs.mihoyo.com/upload/2021/09/29/8819732/54266243c7d15ba31690c8f5d63cc3c6_71491376413333325"
|
||||
"20.png?x-oss-process=image//resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,png",
|
||||
"https://patchwiki.biligame.com/images/ys/thumb/c/cc/6k6kuj1kte6m1n7hexqfrn92z6h4yhh.png/60px-委托任务logo.png",
|
||||
"https://patchwiki.biligame.com/images/ys/d/d9/t1hv6wpucbwucgkhjntmzroh90nmcdv.png",
|
||||
"https://s3.bmp.ovh/imgs/2022/08/21/3a3b2e6c22e305ff.png",
|
||||
"https://s3.bmp.ovh/imgs/2022/08/21/c2d7ace21e1d46cf.png",
|
||||
],
|
||||
):
|
||||
file = memo_path / name
|
||||
@@ -40,7 +45,8 @@ async def _():
|
||||
logger.info(f"已下载原神便签资源 -> {file}...")
|
||||
|
||||
|
||||
async def get_user_memo(user_id: int, uid: int, uname: str) -> Optional[Union[str, MessageSegment]]:
|
||||
async def get_user_memo(user_id: int, uid: int,
|
||||
uname: str) -> Optional[Union[str, MessageSegment]]:
|
||||
uid = str(uid)
|
||||
if uid[0] in ["1", "2"]:
|
||||
server_id = "cn_gf01"
|
||||
@@ -54,12 +60,16 @@ async def get_user_memo(user_id: int, uid: int, uname: str) -> Optional[Union[st
|
||||
async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
|
||||
try:
|
||||
req = await AsyncHttpx.get(
|
||||
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
|
||||
url=
|
||||
f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
|
||||
headers={
|
||||
"DS": get_ds(f"role_id={uid}&server={server_id}"),
|
||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
|
||||
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
|
||||
"x-rpc-app_version": Config.get_config("genshin",
|
||||
"mhyVersion"),
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
|
||||
"x-rpc-client_type": Config.get_config("genshin",
|
||||
"client_type"),
|
||||
"Referer": "https://webstatic.mihoyo.com/",
|
||||
"Cookie": await Genshin.get_user_cookie(int(uid))
|
||||
},
|
||||
@@ -75,11 +85,18 @@ async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
|
||||
return "发生了一些错误,请稍后再试", 998
|
||||
|
||||
|
||||
def create_border(
|
||||
image_name: str, content: str, notice_text: str, value: str
|
||||
) -> BuildImage:
|
||||
border = BuildImage(500, 100, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20)
|
||||
text_bk = BuildImage(350, 96, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf")
|
||||
def create_border(image_name: str, content: str, notice_text: str,
|
||||
value: str) -> BuildImage:
|
||||
border = BuildImage(500,
|
||||
75,
|
||||
color="#E0D9D1",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=20)
|
||||
text_bk = BuildImage(350,
|
||||
75,
|
||||
color="#F5F1EB",
|
||||
font_size=23,
|
||||
font="HYWenHei-85W.ttf")
|
||||
_x = 70 if image_name == "resin.png" else 50
|
||||
_px = 10 if image_name == "resin.png" else 20
|
||||
text_bk.paste(
|
||||
@@ -88,7 +105,7 @@ def create_border(
|
||||
True,
|
||||
center_type="by_height",
|
||||
)
|
||||
text_bk.text((87, 20), content)
|
||||
text_bk.text((87, 15), content)
|
||||
text_bk.paste(
|
||||
BuildImage(
|
||||
0,
|
||||
@@ -98,18 +115,19 @@ def create_border(
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=17,
|
||||
),
|
||||
(87, 50),
|
||||
(87, 45),
|
||||
True,
|
||||
)
|
||||
font_width, _ = border.getsize(value)
|
||||
border.text((350 + 76 - int(font_width / 2), 0), value, center_type="by_height")
|
||||
border.text((350 + 76 - int(font_width / 2), 0),
|
||||
value,
|
||||
center_type="by_height")
|
||||
border.paste(text_bk, (2, 0), center_type="by_height")
|
||||
return border
|
||||
|
||||
|
||||
async def parse_data_and_draw(
|
||||
user_id: int, uid: str, server_id: str, uname: str
|
||||
) -> Union[str, MessageSegment]:
|
||||
async def parse_data_and_draw(user_id: int, uid: str, server_id: str,
|
||||
uname: str) -> Union[str, MessageSegment]:
|
||||
data, code = await get_memo(uid, server_id)
|
||||
if code != 200:
|
||||
return data
|
||||
@@ -120,13 +138,11 @@ async def parse_data_and_draw(
|
||||
if not role_avatar.exists():
|
||||
await AsyncHttpx.download_file(x["avatar_side_icon"], role_avatar)
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
None, _parse_data_and_draw, data, user_avatar, uid, uname
|
||||
)
|
||||
None, _parse_data_and_draw, data, user_avatar, uid, uname)
|
||||
|
||||
|
||||
def _parse_data_and_draw(
|
||||
data: dict, user_avatar: BytesIO, uid: int, uname: str
|
||||
) -> Union[str, MessageSegment]:
|
||||
def _parse_data_and_draw(data: dict, user_avatar: BytesIO, uid: int,
|
||||
uname: str) -> Union[str, MessageSegment]:
|
||||
current_resin = data["current_resin"] # 当前树脂
|
||||
max_resin = data["max_resin"] # 最大树脂
|
||||
resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间
|
||||
@@ -137,17 +153,37 @@ def _parse_data_and_draw(
|
||||
current_expedition_num = data["current_expedition_num"] # 当前挖矿人数
|
||||
max_expedition_num = data["max_expedition_num"] # 每日挖矿最大人数
|
||||
expeditions = data["expeditions"] # 挖矿详情
|
||||
|
||||
current_coin = data["current_home_coin"] # 当前宝钱
|
||||
max_coin = data["max_home_coin"] # 最大宝钱
|
||||
coin_recovery_time = data["home_coin_recovery_time"] # 宝钱全部回复时间
|
||||
transformer_available = data["transformer"]["obtained"] # 参量质变仪可获取
|
||||
transformer_state = data["transformer"]["recovery_time"][
|
||||
"reached"] # 参量质变仪状态
|
||||
transformer_recovery_time = data["transformer"]["recovery_time"][
|
||||
"Day"] # 参量质变仪回复时间
|
||||
transformer_recovery_hour = data["transformer"]["recovery_time"][
|
||||
"Hour"] # 参量质变仪回复时间
|
||||
coin_minute, coin_second = divmod(int(coin_recovery_time), 60)
|
||||
coin_hour, coin_minute = divmod(coin_minute, 60)
|
||||
#print(data)
|
||||
minute, second = divmod(int(resin_recovery_time), 60)
|
||||
hour, minute = divmod(minute, 60)
|
||||
|
||||
A = BuildImage(1030, 520, color="#f1e9e1", font_size=15, font="HYWenHei-85W.ttf")
|
||||
A = BuildImage(1030,
|
||||
570,
|
||||
color="#f1e9e1",
|
||||
font_size=15,
|
||||
font="HYWenHei-85W.ttf")
|
||||
A.text((10, 15), "原神便笺 | Create By ZhenXun", (198, 186, 177))
|
||||
ava = BuildImage(100, 100, background=user_avatar)
|
||||
ava.circle()
|
||||
A.paste(ava, (40, 40), True)
|
||||
A.paste(
|
||||
BuildImage(0, 0, plain_text=uname, font_size=20, font="HYWenHei-85W.ttf"),
|
||||
BuildImage(0,
|
||||
0,
|
||||
plain_text=uname,
|
||||
font_size=20,
|
||||
font="HYWenHei-85W.ttf"),
|
||||
(160, 62),
|
||||
True,
|
||||
)
|
||||
@@ -177,26 +213,52 @@ def _parse_data_and_draw(
|
||||
"今日委托已全部完成" if finished_task_num == total_task_num else "今日委托完成数量不足",
|
||||
f"{finished_task_num}/{total_task_num}",
|
||||
)
|
||||
A.paste(border, (10, 265))
|
||||
A.paste(border, (10, 235))
|
||||
border = create_border(
|
||||
"resin_discount.png",
|
||||
"值得铭记的强敌",
|
||||
"本周剩余消耗减半次数",
|
||||
f"{remain_resin_discount_num}/{resin_discount_num_limit}",
|
||||
)
|
||||
A.paste(border, (10, 375))
|
||||
expeditions_border = BuildImage(
|
||||
470, 430, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20
|
||||
A.paste(border, (10, 315))
|
||||
border = create_border(
|
||||
"chengehu.png",
|
||||
"洞天财翁-洞天宝钱",
|
||||
"洞天财翁已达到存储上限"
|
||||
if current_coin == max_coin else f"{coin_hour}小时{coin_minute}分钟后存满",
|
||||
f"{current_coin}/{max_coin}",
|
||||
)
|
||||
expeditions_text = BuildImage(
|
||||
466, 426, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf"
|
||||
A.paste(border, (10, 395))
|
||||
border = create_border(
|
||||
"zhibian.png",
|
||||
"参量质变仪",
|
||||
"不存在" if not transformer_available else
|
||||
"已准备完成 " if transformer_state else f"{transformer_recovery_hour}小时后可使用" if not transformer_recovery_time else f"{transformer_recovery_time}天后可使用",
|
||||
"不存在" if not transformer_available else
|
||||
"可使用" if transformer_state else "冷却中",
|
||||
)
|
||||
A.paste(border, (10, 475))
|
||||
|
||||
expeditions_border = BuildImage(470,
|
||||
510,
|
||||
color="#E0D9D1",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=20)
|
||||
expeditions_text = BuildImage(466,
|
||||
506,
|
||||
color="#F5F1EB",
|
||||
font_size=23,
|
||||
font="HYWenHei-85W.ttf")
|
||||
expeditions_text.text(
|
||||
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}", (100, 100, 98)
|
||||
)
|
||||
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}",
|
||||
(100, 100, 98))
|
||||
h = 45
|
||||
for x in expeditions:
|
||||
_bk = BuildImage(400, 66, color="#ECE3D8", font="HYWenHei-85W.ttf", font_size=21)
|
||||
_bk = BuildImage(400,
|
||||
82,
|
||||
color="#ECE3D8",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=21)
|
||||
file_name = x["avatar_side_icon"].split("_")[-1]
|
||||
role_avatar = memo_path / "role_avatar" / file_name
|
||||
_ava_img = BuildImage(75, 75, background=role_avatar)
|
||||
@@ -227,7 +289,7 @@ def _parse_data_and_draw(
|
||||
_bk.circle_corner(20)
|
||||
|
||||
expeditions_text.paste(_bk, (25, h), True)
|
||||
h += 75
|
||||
h += 75 + 16
|
||||
|
||||
expeditions_border.paste(expeditions_text, center_type="center")
|
||||
|
||||
|
||||
@@ -195,6 +195,7 @@ def parsed_data(
|
||||
"magic_chest_number": data["stats"]["magic_chest_number"], # 奇馈宝箱
|
||||
"common_chest_number": data["stats"]["common_chest_number"], # 普通宝箱
|
||||
"electroculus_number": data["stats"]["electroculus_number"], # 雷神瞳已收集
|
||||
"dendroculus_number": data["stats"]["dendroculus_number"], # 草神瞳已收集
|
||||
}
|
||||
world_data_dict = {}
|
||||
for world in data["world_explorations"]:
|
||||
|
||||
@@ -129,7 +129,7 @@ def get_user_data_image(
|
||||
"""
|
||||
if mys_data:
|
||||
nickname = [x["nickname"] for x in mys_data if x["game_id"] == 2][0]
|
||||
region = BuildImage(1440, 450, color="#E3DBD1", font="HYWenHei-85W.ttf")
|
||||
region = BuildImage(1440, 560, color="#E3DBD1", font="HYWenHei-85W.ttf")
|
||||
region.circle_corner(30)
|
||||
uname_img = BuildImage(
|
||||
0,
|
||||
@@ -163,36 +163,42 @@ def get_user_data_image(
|
||||
/ random.choice(os.listdir(image_path / "chars_ava")),
|
||||
)
|
||||
ava_bk.paste(ava_img, (12, 16), alpha=True)
|
||||
region.paste(uname_img, (int(170 + uid_img.w / 2 - uname_img.w / 2), 305), True)
|
||||
region.paste(uid_img, (170, 355), True)
|
||||
region.paste(ava_bk, (int(550 / 2 - ava_bk.w / 2), 40), True)
|
||||
region.paste(uname_img, (int(170 + uid_img.w / 2 - uname_img.w / 2), 365), True)
|
||||
region.paste(uid_img, (170, 415), True)
|
||||
region.paste(ava_bk, (int(550 / 2 - ava_bk.w / 2), 100), True)
|
||||
data_img = BuildImage(
|
||||
800, 400, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
800, 510, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
_height = 0
|
||||
keys = [
|
||||
["活跃天数", "成就达成", "获得角色", "深境螺旋"],
|
||||
["华丽宝箱", "珍贵宝箱", "精致宝箱", "普通宝箱"],
|
||||
["奇馈宝箱", "风神瞳", "岩神瞳", "雷神瞳"],
|
||||
["活跃天数", "成就达成", "获得角色", "解锁传送"],
|
||||
["风神瞳", "岩神瞳", "雷神瞳", "草神瞳"],
|
||||
["解锁秘境", "深境螺旋", "华丽宝箱", "珍贵宝箱"],
|
||||
["精致宝箱", "普通宝箱", "奇馈宝箱",],
|
||||
]
|
||||
values = [
|
||||
[
|
||||
role_data["active_day_number"],
|
||||
role_data["achievement_number"],
|
||||
role_data["avatar_number"],
|
||||
role_data["spiral_abyss"],
|
||||
role_data["way_point_number"],
|
||||
],
|
||||
[
|
||||
role_data["luxurious_chest_number"],
|
||||
role_data["precious_chest_number"],
|
||||
role_data["exquisite_chest_number"],
|
||||
role_data["common_chest_number"],
|
||||
],
|
||||
[
|
||||
role_data["magic_chest_number"],
|
||||
role_data["anemoculus_number"],
|
||||
role_data["geoculus_number"],
|
||||
role_data["electroculus_number"],
|
||||
role_data["dendroculus_number"],
|
||||
],
|
||||
[
|
||||
role_data["domain_number"],
|
||||
role_data["spiral_abyss"],
|
||||
role_data["luxurious_chest_number"],
|
||||
role_data["precious_chest_number"],
|
||||
],
|
||||
[
|
||||
role_data["exquisite_chest_number"],
|
||||
role_data["common_chest_number"],
|
||||
role_data["magic_chest_number"],
|
||||
],
|
||||
]
|
||||
for key, value in zip(keys, values):
|
||||
@@ -215,7 +221,7 @@ def get_user_data_image(
|
||||
)
|
||||
tmp_.text((0, 0), str(v), center_type="by_width")
|
||||
tmp_.paste(t_, (0, 50), True, "by_width")
|
||||
_tmp_data_img.paste(tmp_, (_width if len(key) > 3 else _width + 15, 0))
|
||||
_tmp_data_img.paste(tmp_, ((_width + 15) if keys.index(key) == 1 else _width, 0))
|
||||
_width += 200
|
||||
data_img.paste(_tmp_data_img, (0, _height))
|
||||
_height += _tmp_data_img.h - 70
|
||||
@@ -228,7 +234,7 @@ def get_home_data_image(home_data_list: List[Dict]) -> BuildImage:
|
||||
画出家园数据
|
||||
:param home_data_list: 家园列表
|
||||
"""
|
||||
h = 130 + 300 * 4
|
||||
h = 130 + 340 * 4
|
||||
region = BuildImage(
|
||||
550, h, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
@@ -287,7 +293,7 @@ def get_home_data_image(home_data_list: List[Dict]) -> BuildImage:
|
||||
x.paste(black_img, alpha=True, center_type="center")
|
||||
x.circle_corner(50)
|
||||
region.paste(x, (0, height), True, "by_width")
|
||||
height += 300
|
||||
height += 340
|
||||
return region
|
||||
|
||||
|
||||
@@ -297,9 +303,9 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
||||
:param world_data_dict: 国家数据字典
|
||||
"""
|
||||
# 层岩巨渊 和 地下矿区 算一个
|
||||
region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2")
|
||||
region = BuildImage(790, 267 * ((len(world_data_dict) - 1) if world_data_dict.get("层岩巨渊·地下矿区") else len(world_data_dict)), color="#F9F6F2")
|
||||
height = 0
|
||||
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]:
|
||||
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫", "须弥"]:
|
||||
if not world_data_dict.get(country):
|
||||
continue
|
||||
x = BuildImage(790, 250, color="#3A4467")
|
||||
@@ -311,15 +317,15 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
||||
)
|
||||
content_bk.paste(logo, (50, 0), True, "by_height")
|
||||
if country in ["蒙德", "璃月"]:
|
||||
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
||||
content_bk.text((300, 40), "蒙德探索" if country == "蒙德" else "璃月探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 40),
|
||||
(500, 40),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 120), "声望", fill=(239, 211, 114))
|
||||
content_bk.text((300, 120), "蒙德声望" if country == "蒙德" else "璃月声望", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 120),
|
||||
(500, 120),
|
||||
f"Lv.{world_data_dict[country]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
@@ -344,45 +350,65 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
elif country in ["龙脊雪山"]:
|
||||
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
||||
content_bk.text((300, 40), "雪山探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 40),
|
||||
(500, 40),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 120), "供奉", fill=(239, 211, 114))
|
||||
content_bk.text((300, 120), "忍冬之树", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 120),
|
||||
(500, 120),
|
||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
elif country in ["稻妻"]:
|
||||
content_bk.text((300, 20), "探索", fill=(239, 211, 114))
|
||||
content_bk.text((300, 20), "稻妻探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 20),
|
||||
(500, 20),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 85), "声望", fill=(239, 211, 114))
|
||||
content_bk.text((300, 85), "稻妻声望", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 85),
|
||||
(500, 85),
|
||||
f"Lv.{world_data_dict[country]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 150), "神樱", fill=(239, 211, 114))
|
||||
content_bk.text((300, 150), "神樱眷顾", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 150),
|
||||
(500, 150),
|
||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
elif country in ["渊下宫"]:
|
||||
content_bk.text((300, 0), "探索", fill=(239, 211, 114), center_type="by_height")
|
||||
content_bk.text((300, 0), "渊下宫探索", fill=(239, 211, 114), center_type="by_height")
|
||||
content_bk.text(
|
||||
(450, 20),
|
||||
(530, 20),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
center_type="by_height",
|
||||
)
|
||||
elif country in ["须弥"]:
|
||||
content_bk.text((300, 20), "须弥探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(500, 20),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 85), "须弥声望", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(500, 85),
|
||||
f"Lv.{world_data_dict[country]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 150), "梦之树", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(500, 150),
|
||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
|
||||
x.paste(tmp_bk, alpha=True, center_type="center")
|
||||
x.paste(content_bk, alpha=True, center_type="center")
|
||||
x.circle_corner(20)
|
||||
|
||||
@@ -19,7 +19,9 @@ import pytz
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
get_memo = require("query_memo").get_memo
|
||||
require("query_memo")
|
||||
|
||||
from ..query_memo import get_memo
|
||||
|
||||
|
||||
global_map = {}
|
||||
|
||||
@@ -18,9 +18,9 @@ class RedbagUser(db.Model):
|
||||
@classmethod
|
||||
async def add_redbag_data(cls, user_qq: int, group_id: int, itype: str, money: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加收发红包数据
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param itype: 收或发
|
||||
@@ -45,9 +45,9 @@ class RedbagUser(db.Model):
|
||||
@classmethod
|
||||
async def ensure(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -61,9 +61,9 @@ class RedbagUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_all(cls, group_id: int = None) -> List["RedbagUser"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if not group_id:
|
||||
|
||||
+7
-5
@@ -1,3 +1,7 @@
|
||||
from io import BytesIO
|
||||
|
||||
import imagehash
|
||||
from PIL import Image
|
||||
from nonebot import on_message, on_command
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, ActionFailed
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
@@ -70,10 +74,8 @@ def save_data():
|
||||
json.dump(mute_data, f, indent=4)
|
||||
|
||||
|
||||
async def download_img_and_hash(url, group_id) -> str:
|
||||
if await AsyncHttpx.download_file(url, TEMP_PATH / f"mute_{group_id}_img.jpg"):
|
||||
return str(get_img_hash(TEMP_PATH / f"mute_{group_id}_img.jpg"))
|
||||
return ""
|
||||
async def download_img_and_hash(url) -> str:
|
||||
return str(imagehash.average_hash(Image.open(BytesIO((await AsyncHttpx.get(url)).content))))
|
||||
|
||||
|
||||
mute_dict = {}
|
||||
@@ -87,7 +89,7 @@ async def _(bot: Bot, event: GroupMessageEvent):
|
||||
img_list = get_message_img(event.json())
|
||||
img_hash = ""
|
||||
for img in img_list:
|
||||
img_hash += await download_img_and_hash(img, event.group_id)
|
||||
img_hash += await download_img_and_hash(img)
|
||||
msg += img_hash
|
||||
if not mute_data.get(group_id):
|
||||
mute_data[group_id] = {
|
||||
|
||||
@@ -27,7 +27,7 @@ __plugin_settings__ = {
|
||||
}
|
||||
|
||||
one_friend = on_regex(
|
||||
"^我.*?朋友.*?[想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问](.*)",
|
||||
"^我.{0,4}朋友.{0,2}(?:想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问)(.{0,30})$",
|
||||
priority=4,
|
||||
block=True,
|
||||
)
|
||||
|
||||
@@ -43,6 +43,7 @@ usage:
|
||||
__plugin_superuser_usage__ = """
|
||||
usage:
|
||||
更新皮肤指令
|
||||
重置开箱: 重置今日开箱所有次数
|
||||
指令:
|
||||
更新开箱图片 ?[武器箱]
|
||||
更新开箱价格 ?[武器箱]
|
||||
@@ -100,6 +101,13 @@ cases_matcher_group = MatcherGroup(priority=5, permission=GROUP, block=True)
|
||||
|
||||
k_open_case = cases_matcher_group.on_command("开箱")
|
||||
|
||||
reload_count = cases_matcher_group.on_command("重置开箱",permission=SUPERUSER)
|
||||
|
||||
|
||||
@reload_count.handle()
|
||||
async def _(event: GroupMessageEvent):
|
||||
await update_count_daily()
|
||||
|
||||
|
||||
@k_open_case.handle()
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
|
||||
@@ -31,7 +31,7 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
|
||||
async with db.transaction():
|
||||
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
|
||||
# 一天次数上限
|
||||
if user.today_open_total == int(
|
||||
if user.today_open_total >= int(
|
||||
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
|
||||
+ int(impression)
|
||||
/ Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
|
||||
@@ -155,7 +155,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
|
||||
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
|
||||
+ int(impression) / Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
|
||||
)
|
||||
if user.today_open_total == max_count:
|
||||
if user.today_open_total >= max_count:
|
||||
return _handle_is_MAX_COUNT()
|
||||
if max_count - user.today_open_total < num:
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from nonebot import on_message
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, ActionFailed
|
||||
|
||||
from utils.manager import group_manager
|
||||
from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from utils.message_builder import image
|
||||
@@ -34,7 +36,10 @@ Config.add_plugin_config(
|
||||
)
|
||||
|
||||
|
||||
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
|
||||
async def plugin_on_checker(event: GroupMessageEvent) -> bool:
|
||||
return group_manager.get_plugin_status("parse_bilibili_json", event.group_id)
|
||||
|
||||
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False, rule=plugin_on_checker)
|
||||
|
||||
_tmp = {}
|
||||
|
||||
@@ -56,18 +61,11 @@ async def _(event: GroupMessageEvent):
|
||||
) as session:
|
||||
async with session.get(
|
||||
data["meta"]["detail_1"]["qqdocurl"],
|
||||
proxy=get_local_proxy(),
|
||||
timeout=7,
|
||||
) as response:
|
||||
url = str(response.url).split("?")[0]
|
||||
bvid = url.split("/")[-1]
|
||||
vd_info = await video.get_video_base_info(bvid)
|
||||
# response = await AsyncHttpx.get(
|
||||
# data["meta"]["detail_1"]["qqdocurl"], timeout=7
|
||||
# )
|
||||
# url = str(response.url).split("?")[0]
|
||||
# bvid = url.split("/")[-1]
|
||||
# vd_info = await video.Video(bvid=bvid).get_info()
|
||||
# 转发专栏
|
||||
if (
|
||||
data.get("meta")
|
||||
@@ -117,17 +115,23 @@ async def _(event: GroupMessageEvent):
|
||||
vd_info = await video.get_video_base_info(msg)
|
||||
elif "av" in msg:
|
||||
index = msg.find("av")
|
||||
if len(msg[index + 2 :]) >= 9:
|
||||
if len(msg[index + 2 :]) >= 1:
|
||||
msg = msg[index + 2 : index + 11]
|
||||
if is_number(msg):
|
||||
url = f"https://www.bilibili.com/video/{msg}"
|
||||
vd_info = await video.get_video_base_info(msg)
|
||||
url = f"https://www.bilibili.com/video/av{msg}"
|
||||
vd_info = await video.get_video_base_info('av' + msg)
|
||||
elif "https://b23.tv" in msg:
|
||||
url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13]
|
||||
res = await AsyncHttpx.get(url, timeout=7)
|
||||
url = str(res.url).split("?")[0]
|
||||
bvid = url.split("/")[-1]
|
||||
vd_info = await video.get_video_base_info(bvid)
|
||||
url = "https://" + msg[msg.find("b23.tv"): msg.find("b23.tv") + 14]
|
||||
async with aiohttp.ClientSession(
|
||||
headers=get_user_agent()
|
||||
) as session:
|
||||
async with session.get(
|
||||
url,
|
||||
timeout=7,
|
||||
) as response:
|
||||
url = (str(response.url).split("?")[0]).strip("/")
|
||||
bvid = url.split("/")[-1]
|
||||
vd_info = await video.get_video_base_info(bvid)
|
||||
if vd_info:
|
||||
if (
|
||||
url in _tmp.keys() and time.time() - _tmp[url] > 30
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from configs.config import Config
|
||||
from utils.utils import GDict
|
||||
import nonebot
|
||||
|
||||
|
||||
@@ -60,6 +61,8 @@ Config.add_plugin_config(
|
||||
default_value=True
|
||||
)
|
||||
|
||||
GDict['run_sql'].append("ALTER TABLE omega_pixiv_illusts ADD classified Integer;")
|
||||
|
||||
nonebot.load_plugins("plugins/pix_gallery")
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from typing import Optional, List
|
||||
from datetime import datetime
|
||||
from typing import Optional, List, Tuple
|
||||
from services.db_context import db
|
||||
|
||||
|
||||
@@ -12,13 +11,12 @@ class OmegaPixivIllusts(db.Model):
|
||||
uid = db.Column(db.BigInteger(), nullable=False)
|
||||
title = db.Column(db.String(), nullable=False)
|
||||
uname = db.Column(db.String(), nullable=False)
|
||||
classified = db.Column(db.Integer(), nullable=False)
|
||||
nsfw_tag = db.Column(db.Integer(), nullable=False)
|
||||
width = db.Column(db.Integer(), nullable=False)
|
||||
height = db.Column(db.Integer(), nullable=False)
|
||||
tags = db.Column(db.String(), nullable=False)
|
||||
url = db.Column(db.String(), nullable=False)
|
||||
created_at = db.Column(db.DateTime(timezone=True))
|
||||
updated_at = db.Column(db.DateTime(timezone=True))
|
||||
|
||||
_idx1 = db.Index("omega_pixiv_illusts_idx1", "pid", "url", unique=True)
|
||||
|
||||
@@ -32,15 +30,14 @@ class OmegaPixivIllusts(db.Model):
|
||||
url: str,
|
||||
uid: int,
|
||||
uname: str,
|
||||
classified: int,
|
||||
nsfw_tag: int,
|
||||
tags: str,
|
||||
created_at: datetime,
|
||||
updated_at: datetime,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加图片信息
|
||||
参数:
|
||||
参数:
|
||||
:param pid: pid
|
||||
:param title: 标题
|
||||
:param width: 宽度
|
||||
@@ -48,10 +45,9 @@ class OmegaPixivIllusts(db.Model):
|
||||
:param url: url链接
|
||||
:param uid: 作者uid
|
||||
:param uname: 作者名称
|
||||
:param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18
|
||||
:param classified: 标记标签, 0=未标记, 1=已人工标记或从可信已标记来源获取
|
||||
:param nsfw_tag: nsfw标签,-1=未标记, 0=safe, 1=setu. 2=r18
|
||||
:param tags: 相关tag
|
||||
:param created_at: 创建日期
|
||||
:param updated_at: 更新日期
|
||||
"""
|
||||
if not await cls.check_exists(pid):
|
||||
await cls.create(
|
||||
@@ -62,6 +58,7 @@ class OmegaPixivIllusts(db.Model):
|
||||
url=url,
|
||||
uid=uid,
|
||||
uname=uname,
|
||||
classified=classified,
|
||||
nsfw_tag=nsfw_tag,
|
||||
tags=tags,
|
||||
)
|
||||
@@ -78,9 +75,9 @@ class OmegaPixivIllusts(db.Model):
|
||||
num: int = 100
|
||||
) -> List[Optional["OmegaPixivIllusts"]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查找符合条件的图片
|
||||
参数:
|
||||
参数:
|
||||
:param keywords: 关键词
|
||||
:param uid: 画师uid
|
||||
:param pid: 图片pid
|
||||
@@ -104,20 +101,20 @@ class OmegaPixivIllusts(db.Model):
|
||||
@classmethod
|
||||
async def check_exists(cls, pid: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测pid是否已存在
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片PID
|
||||
"""
|
||||
query = await cls.query.where(cls.pid == pid).gino.all()
|
||||
return bool(query)
|
||||
|
||||
@classmethod
|
||||
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int, int":
|
||||
async def get_keyword_num(cls, tags: List[str] = None) -> Tuple[int, int, int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取相关关键词(keyword, tag)在图库中的数量
|
||||
参数:
|
||||
参数:
|
||||
:param tags: 关键词/Tag
|
||||
"""
|
||||
setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count'))
|
||||
@@ -133,7 +130,7 @@ class OmegaPixivIllusts(db.Model):
|
||||
@classmethod
|
||||
async def get_all_pid(cls) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有图片PID
|
||||
"""
|
||||
data = await cls.select('pid').gino.all()
|
||||
|
||||
@@ -38,9 +38,9 @@ class Pixiv(db.Model):
|
||||
tags: str,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加图片信息
|
||||
参数:
|
||||
参数:
|
||||
:param pid: pid
|
||||
:param title: 标题
|
||||
:param width: 宽度
|
||||
@@ -74,9 +74,9 @@ class Pixiv(db.Model):
|
||||
@classmethod
|
||||
async def remove_image_data(cls, pid: int, img_p: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除图片数据
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
:param img_p: 图片pid的张数,如:p0,p1
|
||||
"""
|
||||
@@ -94,7 +94,7 @@ class Pixiv(db.Model):
|
||||
@classmethod
|
||||
async def get_all_pid(cls) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有PID
|
||||
"""
|
||||
query = await cls.query.select("pid").gino.first()
|
||||
@@ -112,9 +112,9 @@ class Pixiv(db.Model):
|
||||
num: int = 100
|
||||
) -> List[Optional["Pixiv"]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查找符合条件的图片
|
||||
参数:
|
||||
参数:
|
||||
:param keywords: 关键词
|
||||
:param uid: 画师uid
|
||||
:param pid: 图片pid
|
||||
@@ -140,9 +140,9 @@ class Pixiv(db.Model):
|
||||
@classmethod
|
||||
async def check_exists(cls, pid: int, img_p: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测pid是否已存在
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片PID
|
||||
:param img_p: 张数
|
||||
"""
|
||||
@@ -154,9 +154,9 @@ class Pixiv(db.Model):
|
||||
@classmethod
|
||||
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取相关关键词(keyword, tag)在图库中的数量
|
||||
参数:
|
||||
参数:
|
||||
:param tags: 关键词/Tag
|
||||
"""
|
||||
setattr(Pixiv, 'count', db.func.count(cls.pid).label('count'))
|
||||
|
||||
@@ -19,9 +19,9 @@ class PixivKeywordUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str]
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加搜图的关键词
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param keyword: 关键词
|
||||
@@ -38,9 +38,9 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def delete_keyword(cls, keyword: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除关键词
|
||||
参数:
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
"""
|
||||
if await cls._check_keyword_exists(keyword):
|
||||
@@ -53,9 +53,9 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过或禁用关键词
|
||||
参数:
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
:param is_pass: 通过状态
|
||||
"""
|
||||
@@ -71,7 +71,7 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def get_all_user_dict(cls) -> dict:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取关键词数据库各个用户贡献的关键词字典
|
||||
"""
|
||||
tmp = {}
|
||||
@@ -85,7 +85,7 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def get_current_keyword(cls) -> "List[str], List[str]":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取当前通过与未通过的关键词
|
||||
"""
|
||||
pass_keyword = []
|
||||
@@ -101,7 +101,7 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def get_black_pid(cls) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取黑名单PID
|
||||
"""
|
||||
black_pid = []
|
||||
@@ -113,9 +113,9 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def _check_keyword_exists(cls, keyword: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测关键词是否已存在
|
||||
参数:
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
"""
|
||||
current_keyword = []
|
||||
|
||||
@@ -149,8 +149,8 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
for _ in range(num):
|
||||
img_url = None
|
||||
author = None
|
||||
# if not all_image:
|
||||
# await pix.finish("坏了...发完了,没图了...")
|
||||
if not all_image:
|
||||
await pix.finish("坏了...发完了,没图了...")
|
||||
img = random.choice(all_image)
|
||||
all_image.remove(img)
|
||||
if isinstance(img, OmegaPixivIllusts):
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import re
|
||||
|
||||
from nonebot import on_command
|
||||
from utils.utils import is_number
|
||||
from nonebot.permission import SUPERUSER
|
||||
@@ -11,7 +13,6 @@ import time
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
@@ -144,38 +145,36 @@ async def _(arg: Message = CommandArg()):
|
||||
@check_omega.handle()
|
||||
async def _():
|
||||
async def _tasks(line: str, all_pid: List[int], length: int, index: int):
|
||||
data = line.split("VALUES", maxsplit=1)[-1].strip()
|
||||
if data.startswith("("):
|
||||
data = data[1:]
|
||||
if data.endswith(");"):
|
||||
data = data[:-2]
|
||||
x = data.split(maxsplit=3)
|
||||
pid = int(x[1][:-1].strip())
|
||||
data = line.split("VALUES", maxsplit=1)[-1].strip()[1:-2]
|
||||
num_list = re.findall(r'(\d+)', data)
|
||||
pid = int(num_list[1])
|
||||
uid = int(num_list[2])
|
||||
id_ = 3
|
||||
while num_list[id_] not in ['0', '1']:
|
||||
id_ += 1
|
||||
classified = int(num_list[id_])
|
||||
nsfw_tag = int(num_list[id_ + 1])
|
||||
width = int(num_list[id_ + 2])
|
||||
height = int(num_list[id_ + 3])
|
||||
str_list = re.findall(r"'(.*?)',", data)
|
||||
title = str_list[0]
|
||||
uname = str_list[1]
|
||||
tags = str_list[2]
|
||||
url = str_list[3]
|
||||
if pid in all_pid:
|
||||
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
|
||||
return
|
||||
uid = int(x[2][:-1].strip())
|
||||
x = x[3].split(", '")
|
||||
title = x[0].strip()[1:-1]
|
||||
tmp = x[1].split(", ")
|
||||
author = tmp[0].strip()[:-1]
|
||||
nsfw_tag = int(tmp[1])
|
||||
width = int(tmp[2])
|
||||
height = int(tmp[3])
|
||||
tags = x[2][:-1]
|
||||
url = x[3][:-1]
|
||||
if await OmegaPixivIllusts.add_image_data(
|
||||
pid,
|
||||
title,
|
||||
width,
|
||||
height,
|
||||
url,
|
||||
uid,
|
||||
author,
|
||||
nsfw_tag,
|
||||
tags,
|
||||
datetime.min,
|
||||
datetime.min,
|
||||
pid=pid,
|
||||
title=title,
|
||||
width=width,
|
||||
height=height,
|
||||
url=url,
|
||||
uid=uid,
|
||||
nsfw_tag=nsfw_tag,
|
||||
tags=tags,
|
||||
uname=uname,
|
||||
classified=classified
|
||||
):
|
||||
logger.info(
|
||||
f"成功添加OmegaPixivIllusts图库数据 pid:{pid} 本次预计存储 {length} 张,已更新第 {index} 张"
|
||||
@@ -184,7 +183,7 @@ async def _():
|
||||
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
|
||||
omega_pixiv_illusts = None
|
||||
for file in os.listdir("."):
|
||||
if "omega_pixiv_illusts" in file and ".sql" in file:
|
||||
if "omega_pixiv_artwork" in file and ".sql" in file:
|
||||
omega_pixiv_illusts = Path() / file
|
||||
if omega_pixiv_illusts:
|
||||
with open(omega_pixiv_illusts, "r", encoding="utf8") as f:
|
||||
@@ -197,6 +196,7 @@ async def _():
|
||||
for line in lines:
|
||||
if "INSERT INTO" in line.upper():
|
||||
index += 1
|
||||
logger.info(f'line: {line} 加入更新计划')
|
||||
tasks.append(
|
||||
asyncio.ensure_future(_tasks(line, all_pid, length, index))
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ __zx_plugin_name__ = "P站排行/搜图"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
P站排行:
|
||||
可选参数:
|
||||
可选参数:
|
||||
类型:
|
||||
1. 日排行
|
||||
2. 周排行
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from nonebot import on_command
|
||||
from nonebot import on_regex
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
@@ -24,7 +24,7 @@ __plugin_settings__ = {
|
||||
}
|
||||
|
||||
|
||||
quotations = on_command("语录", aliases={"二次元", "二次元语录"}, priority=5, block=True)
|
||||
quotations = on_regex("^(语录|二次元)$", priority=5, block=True)
|
||||
|
||||
url = "https://international.v1.hitokoto.cn/?c=a"
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@ class RussianUser(db.Model):
|
||||
@classmethod
|
||||
async def ensure(cls, user_qq: int, group_id: int) -> "RussianUser":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -39,9 +39,9 @@ class RussianUser(db.Model):
|
||||
@classmethod
|
||||
async def add_count(cls, user_qq: int, group_id: int, itype: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加用户输赢次数
|
||||
说明:
|
||||
说明:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param itype: 输或赢 'win' or 'lose'
|
||||
@@ -87,9 +87,9 @@ class RussianUser(db.Model):
|
||||
@classmethod
|
||||
async def money(cls, user_qq: int, group_id: int, itype: str, count: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加用户输赢金钱
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param itype: 输或赢 'win' or 'lose'
|
||||
@@ -120,9 +120,9 @@ class RussianUser(db.Model):
|
||||
@classmethod
|
||||
async def get_all_user(cls, group_id: int) -> List["RussianUser"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取该群所有用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
users = await cls.query.where((cls.group_id == group_id)).gino.all()
|
||||
|
||||
@@ -30,9 +30,9 @@ class Setu(db.Model):
|
||||
tags: str,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加一份色图数据
|
||||
参数:
|
||||
参数:
|
||||
:param local_id: 本地存储id
|
||||
:param title: 标题
|
||||
:param author: 作者
|
||||
@@ -62,9 +62,9 @@ class Setu(db.Model):
|
||||
limit: int = 50,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过tag查找色图
|
||||
参数:
|
||||
参数:
|
||||
:param local_id: 本地色图 id
|
||||
:param tags: tags
|
||||
:param r18: 是否 r18,0:非r18 1:r18 2:混合
|
||||
@@ -90,7 +90,7 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def get_image_count(cls, r18: int = 0) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查询图片数量
|
||||
"""
|
||||
flag = False if r18 == 0 else True
|
||||
@@ -101,9 +101,9 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def get_image_in_hash(cls, img_hash: str) -> "Setu":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过图像hash获取图像信息
|
||||
参数:
|
||||
参数:
|
||||
:param img_hash: = 图像hash值
|
||||
"""
|
||||
query = await cls.query.where(cls.img_hash == img_hash).gino.first()
|
||||
@@ -112,9 +112,9 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def _check_exists(cls, pid: int, img_url: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测图片是否存在
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
:param img_url: 图片链接
|
||||
"""
|
||||
@@ -127,9 +127,9 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def delete_image(cls, pid: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除图片并替换
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
"""
|
||||
query = await cls.query.where(cls.pid == pid).gino.first()
|
||||
@@ -157,9 +157,9 @@ class Setu(db.Model):
|
||||
tags: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
根据PID修改图片数据
|
||||
参数:
|
||||
参数:
|
||||
:param local_id: 本地id
|
||||
:param pid: 图片pid
|
||||
:param title: 标题
|
||||
@@ -190,7 +190,7 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def get_all_setu(cls) -> List["Setu"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有图片对象
|
||||
"""
|
||||
return await cls.query.gino.all()
|
||||
|
||||
@@ -254,8 +254,10 @@ async def send_setu_handle(
|
||||
if code == 401:
|
||||
await setu.finish(urls[0], at_sender=True)
|
||||
if code == 200:
|
||||
forward_list = []
|
||||
for i in range(len(urls)):
|
||||
try:
|
||||
msg_id = None
|
||||
setu_img, index = await search_online_setu(urls[i])
|
||||
# 下载成功的话
|
||||
if index != -1:
|
||||
@@ -264,9 +266,17 @@ async def send_setu_handle(
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 发送色图 {index}.png"
|
||||
)
|
||||
msg_id = await matcher.send(
|
||||
Message(f"{text_list[i]}\n{setu_img}")
|
||||
)
|
||||
if (
|
||||
Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
|
||||
and num
|
||||
>= Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
|
||||
and isinstance(event, GroupMessageEvent)
|
||||
):
|
||||
forward_list.append(Message(f"{text_list[i]}\n{setu_img}"))
|
||||
else:
|
||||
msg_id = await matcher.send(
|
||||
Message(f"{text_list[i]}\n{setu_img}")
|
||||
)
|
||||
else:
|
||||
if setu_list is None:
|
||||
setu_list, code = await get_setu_list(tags=tags, r18=r18)
|
||||
@@ -275,14 +285,35 @@ async def send_setu_handle(
|
||||
if setu_list:
|
||||
setu_image = random.choice(setu_list)
|
||||
setu_list.remove(setu_image)
|
||||
msg_id = await matcher.send(
|
||||
Message(
|
||||
gen_message(setu_image)
|
||||
+ (
|
||||
await check_local_exists_or_download(setu_image)
|
||||
)[0]
|
||||
if (
|
||||
Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
|
||||
and num
|
||||
>= Config.get_config(
|
||||
"send_setu", "MAX_ONCE_NUM2FORWARD"
|
||||
)
|
||||
and isinstance(event, GroupMessageEvent)
|
||||
):
|
||||
forward_list.append(
|
||||
Message(
|
||||
gen_message(setu_image)
|
||||
+ (
|
||||
await check_local_exists_or_download(
|
||||
setu_image
|
||||
)
|
||||
)[0]
|
||||
)
|
||||
)
|
||||
else:
|
||||
msg_id = await matcher.send(
|
||||
Message(
|
||||
gen_message(setu_image)
|
||||
+ (
|
||||
await check_local_exists_or_download(
|
||||
setu_image
|
||||
)
|
||||
)[0]
|
||||
)
|
||||
)
|
||||
)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
@@ -298,6 +329,16 @@ async def send_setu_handle(
|
||||
)
|
||||
except ActionFailed:
|
||||
await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
|
||||
if forward_list:
|
||||
msg_id = await bot.send_group_forward_msg(
|
||||
group_id=event.group_id,
|
||||
messages=custom_forward_msg(forward_list, bot.self_id),
|
||||
)
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event,
|
||||
msg_id,
|
||||
Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
|
||||
)
|
||||
return
|
||||
if code != 200:
|
||||
await matcher.finish("网络连接失败...", at_sender=True)
|
||||
|
||||
@@ -12,6 +12,7 @@ from .._model import Setu
|
||||
import asyncio
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
@@ -22,6 +23,7 @@ except ModuleNotFoundError:
|
||||
url = "https://api.lolicon.app/setu/v2"
|
||||
path = "_setu"
|
||||
r18_path = "_r18"
|
||||
host_pattern = re.compile(r"https?://([^/]+)")
|
||||
|
||||
|
||||
# 获取url
|
||||
@@ -89,7 +91,9 @@ async def search_online_setu(
|
||||
"""
|
||||
ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
|
||||
if ws_url:
|
||||
url_ = url_.replace("i.pximg.net", ws_url).replace("i.pixiv.cat", ws_url)
|
||||
host_match = re.match(host_pattern, url_)
|
||||
host = host_match.group(1)
|
||||
url_ = url_.replace(host, ws_url)
|
||||
index = random.randint(1, 100000) if id_ is None else id_
|
||||
path_ = IMAGE_PATH / path_ if path_ else TEMP_PATH
|
||||
file_name = f"{index}_temp_setu.jpg" if path_ == TEMP_PATH else f"{index}.jpg"
|
||||
|
||||
@@ -18,6 +18,7 @@ from configs.path_config import DATA_PATH
|
||||
from services.log import logger
|
||||
from .utils import clear_sign_data_pic
|
||||
from utils.utils import is_number
|
||||
from .goods_register import driver
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
from models.sign_group_user import SignGroupUser
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
from utils.decorator.shop import shop_register, NotMeetUseConditionsException
|
||||
import nonebot
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
"""
|
||||
导入内置的三个商品
|
||||
"""
|
||||
|
||||
@shop_register(
|
||||
name=("好感度双倍加持卡Ⅰ", "好感度双倍加持卡Ⅱ", "好感度双倍加持卡Ⅲ"),
|
||||
price=(30, 150, 250),
|
||||
des=(
|
||||
"下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
|
||||
"下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)",
|
||||
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
|
||||
),
|
||||
load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
|
||||
icon=("favorability_card_1.png", "favorability_card_2.png", "favorability_card_3.png"),
|
||||
** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
|
||||
)
|
||||
async def sign_card(user_id: int, group_id: int, prob: float):
|
||||
user = await SignGroupUser.ensure(user_id, group_id)
|
||||
await user.update(add_probability=prob).apply()
|
||||
|
||||
@shop_register(
|
||||
name="测试道具A",
|
||||
price=99,
|
||||
des="随便侧而出",
|
||||
load_status=False,
|
||||
icon="sword.png",
|
||||
)
|
||||
async def _(user_id: int, group_id: int):
|
||||
print(user_id, group_id, '使用测试道具')
|
||||
|
||||
@shop_register.before_handle(name="测试道具A", load_status=False)
|
||||
async def _(user_id: int, group_id: int):
|
||||
print(user_id, group_id, '第一个使用前函数(before handle)')
|
||||
|
||||
@shop_register.before_handle(name="测试道具A", load_status=False)
|
||||
async def _(user_id: int, group_id: int):
|
||||
print(user_id, group_id, '第二个使用前函数(before handle)222')
|
||||
raise NotMeetUseConditionsException("太笨了!") # 抛出异常,阻断使用,并返回信息
|
||||
|
||||
@shop_register.after_handle(name="测试道具A", load_status=False)
|
||||
async def _(user_id: int, group_id: int):
|
||||
print(user_id, group_id, '第一个使用后函数(after handle)')
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _():
|
||||
await shop_register.load_register()
|
||||
|
||||
@@ -81,19 +81,15 @@ async def _handle_check_in(
|
||||
await BagUser.add_gold(user_qq, group, gold)
|
||||
await BagUser.add_property(user_qq, group, gift)
|
||||
gift += ' + 1'
|
||||
|
||||
logger.info(
|
||||
f"(USER {user.user_qq}, GROUP {user.group_id})"
|
||||
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
||||
f"(+{impression_added:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
||||
)
|
||||
if critx2 + add_probability > 0.97 or critx2 < specify_probability:
|
||||
logger.info(
|
||||
f"(USER {user.user_qq}, GROUP {user.group_id})"
|
||||
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
||||
f"(+{impression_added * 2:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
||||
)
|
||||
return await get_card(user, nickname, impression_added, gold, gift, True)
|
||||
else:
|
||||
logger.info(
|
||||
f"(USER {user.user_qq}, GROUP {user.group_id})"
|
||||
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
||||
f"(+{impression_added:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
||||
)
|
||||
return await get_card(user, nickname, impression_added, gold, gift)
|
||||
|
||||
|
||||
|
||||
@@ -24,8 +24,6 @@ from io import BytesIO
|
||||
import asyncio
|
||||
import random
|
||||
import nonebot
|
||||
import time
|
||||
import locale
|
||||
import os
|
||||
|
||||
|
||||
|
||||
+22
-20
@@ -40,28 +40,30 @@ wbtop_data = []
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
global wbtop_data
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if not wbtop_data or not msg:
|
||||
if wbtop_data:
|
||||
now_time = datetime.datetime.now()
|
||||
if now_time > wbtop_data["time"] + datetime.timedelta(minutes=5):
|
||||
data, code = await get_wbtop(wbtop_url)
|
||||
if code != 200:
|
||||
await wbtop.finish(data, at_sender=True)
|
||||
wbtop_data = data
|
||||
else:
|
||||
if wbtop_data:
|
||||
now_time = datetime.datetime.now()
|
||||
if now_time > wbtop_data["time"] + datetime.timedelta(minutes=5):
|
||||
data, code = await get_wbtop(wbtop_url)
|
||||
if code != 200:
|
||||
await wbtop.finish(data, at_sender=True)
|
||||
else:
|
||||
wbtop_data = data
|
||||
else:
|
||||
data, code = await get_wbtop(wbtop_url)
|
||||
if code != 200:
|
||||
await wbtop.finish(data, at_sender=True)
|
||||
else:
|
||||
wbtop_data = data
|
||||
if not msg:
|
||||
img = await asyncio.get_event_loop().run_in_executor(
|
||||
None, gen_wbtop_pic, wbtop_data["data"]
|
||||
)
|
||||
await wbtop.send(img)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 查询微博热搜"
|
||||
)
|
||||
|
||||
if not msg:
|
||||
img = await asyncio.get_event_loop().run_in_executor(
|
||||
None, gen_wbtop_pic, wbtop_data["data"]
|
||||
)
|
||||
await wbtop.send(img)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 查询微博热搜"
|
||||
)
|
||||
if is_number(msg) and 0 < int(msg) <= 50:
|
||||
url = wbtop_data["data"][int(msg) - 1]["url"]
|
||||
await wbtop.send("开始截取数据...")
|
||||
@@ -72,7 +74,7 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
wait_time=12
|
||||
)
|
||||
if img:
|
||||
await wbtop.send(img)
|
||||
await wbtop.finish(img)
|
||||
else:
|
||||
await wbtop.send("发生了一些错误.....")
|
||||
await wbtop.finish("发生了一些错误.....")
|
||||
|
||||
|
||||
@@ -111,6 +111,9 @@ def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result:
|
||||
try:
|
||||
if plugin.plugin_config:
|
||||
for c in plugin.plugin_config:
|
||||
if not c.value:
|
||||
Config.set_config(plugin.model, c.key, None)
|
||||
continue
|
||||
if str(c.value).lower() in ["true", "false"] and (
|
||||
c.default_value is None or isinstance(c.default_value, bool)
|
||||
):
|
||||
@@ -124,8 +127,8 @@ def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result:
|
||||
) or isinstance(c.default_value, float):
|
||||
c.value = float(c.value)
|
||||
elif isinstance(c.value, str) and (
|
||||
isinstance(Config.get_config(plugin.model, c.key, c.value), list)
|
||||
or isinstance(c.default_value, list)
|
||||
isinstance(Config.get_config(plugin.model, c.key, c.value), (list, tuple))
|
||||
or isinstance(c.default_value, (list, tuple))
|
||||
):
|
||||
default_value = Config.get_config(plugin.model, c.key, c.value)
|
||||
c.value = c.value.split(",")
|
||||
|
||||
@@ -76,7 +76,7 @@ async def _(user: User = Depends(token_to_user)) -> Result:
|
||||
|
||||
async def get_system_data(user: User = Depends(token_to_user)):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取系统信息,资源文件大小,网络状态等
|
||||
"""
|
||||
baidu = 200
|
||||
@@ -107,7 +107,7 @@ async def get_system_data(user: User = Depends(token_to_user)):
|
||||
|
||||
def _get_system_status(user: User = Depends(token_to_user)) -> SystemStatus:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取系统信息等
|
||||
"""
|
||||
cpu = psutil.cpu_percent()
|
||||
@@ -126,7 +126,7 @@ def _get_system_disk(
|
||||
type_: Optional[str], user: User = Depends(token_to_user)
|
||||
) -> Union[SystemFolderSize, Dict[str, Union[float, datetime]]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取资源文件大小等
|
||||
"""
|
||||
if not type_:
|
||||
@@ -171,9 +171,9 @@ def _get_system_disk(
|
||||
|
||||
def _get_dir_size(dir_path: Path) -> float:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取文件夹大小
|
||||
参数:
|
||||
参数:
|
||||
:param dir_path: 文件夹路径
|
||||
"""
|
||||
size = 0
|
||||
@@ -184,9 +184,9 @@ def _get_dir_size(dir_path: Path) -> float:
|
||||
|
||||
def save_system_data(cpu: float, memory: float, disk: float):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
保存一些系统信息
|
||||
参数:
|
||||
参数:
|
||||
:param cpu: cpu
|
||||
:param memory: memory
|
||||
:param disk: disk
|
||||
|
||||
@@ -10,25 +10,4 @@ Config.add_plugin_config(
|
||||
default_value=5
|
||||
)
|
||||
|
||||
Config.add_plugin_config(
|
||||
"word_bank",
|
||||
"WORD_BANK_FUZZY",
|
||||
False,
|
||||
help_="模糊匹配",
|
||||
default_value=False
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"word_bank",
|
||||
"WORD_BANK_KEY",
|
||||
True,
|
||||
help_="关键字匹配",
|
||||
default_value=True
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
"word_bank",
|
||||
"WORD_BANK_MIX",
|
||||
25,
|
||||
help_="查看词条时图片内最多显示条数",
|
||||
default_value=25
|
||||
)
|
||||
nonebot.load_plugins("plugins/word_bank")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
scope2int = {
|
||||
"全局": 0,
|
||||
"群聊": 1,
|
||||
"私聊": 2,
|
||||
}
|
||||
|
||||
type2int = {
|
||||
"精准": 0,
|
||||
"模糊": 1,
|
||||
"正则": 2,
|
||||
"图片": 3,
|
||||
}
|
||||
|
||||
int2type = {
|
||||
0: "精准",
|
||||
1: "模糊",
|
||||
2: "正则",
|
||||
3: "图片",
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user