mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-09-29 00:32:06 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f59895c3b | ||
|
|
b5ce4fab31 | ||
|
|
062e4c2062 | ||
|
|
0adb66a8bf | ||
|
|
2aad517112 | ||
|
|
14d1512b1e | ||
|
|
3f533516af | ||
|
|
f1354308fd | ||
|
|
c06248e46b | ||
|
|
9c8eaed938 | ||
|
|
2081302e32 | ||
|
|
678fc19f2d | ||
|
|
adc2757e8e | ||
|
|
82a1261371 | ||
|
|
067da9dc57 | ||
|
|
0eb9f9fc6f | ||
|
|
aee1340714 | ||
|
|
a72a9bd8cb | ||
|
|
7250410653 | ||
|
|
12f55800b0 | ||
|
|
53b375b4b2 | ||
|
|
fba27abe29 | ||
|
|
4caa3dec04 | ||
|
|
516b0f5ccb | ||
|
|
b5098be08e | ||
|
|
5b08a4650c | ||
|
|
eb02157b94 | ||
|
|
222e1719a4 | ||
|
|
3c8983e753 | ||
|
|
1fe41dd823 | ||
|
|
e8df59203c | ||
|
|
0f6690606b | ||
|
|
a0115309dd | ||
|
|
ca18d45786 | ||
|
|
76df21036a | ||
|
|
c674d581b7 | ||
|
|
fc53c3c487 | ||
|
|
7a4e31df80 | ||
|
|
f1d308d559 | ||
|
|
b7914bac05 | ||
|
|
8c40d88cc4 | ||
|
|
b4ed6dcb5d | ||
|
|
0d3bd8a89c | ||
|
|
87f0189abd | ||
|
|
1c17ac1f9d | ||
|
|
f038763041 | ||
|
|
eaf6d54757 | ||
|
|
d7368c83bc | ||
|
|
4011620da1 | ||
|
|
6e0b91531e | ||
|
|
b8ca1d68aa | ||
|
|
2b9cda40a0 | ||
|
|
d8983bdcbf | ||
|
|
14bce52f2f | ||
|
|
a7b0f7da68 | ||
|
|
7dd68cf1ef | ||
|
|
ab443a21ec | ||
|
|
ed7e8a8a4c | ||
|
|
a1435e2fc4 | ||
|
|
44a80f89da | ||
|
|
164f6af30c | ||
|
|
9093a79101 | ||
|
|
14cce89a18 | ||
|
|
4bce20a0a9 | ||
|
|
f32d8b4eff | ||
|
|
685f2b8c53 | ||
|
|
1e63ca2549 | ||
|
|
c1bc4eff2b | ||
|
|
bc903d3813 | ||
|
|
80fc17b610 | ||
|
|
0efb2bbc60 | ||
|
|
95ad533b87 | ||
|
|
b6e3240df9 |
+1
-2
@@ -139,10 +139,9 @@ dmypy.json
|
||||
cython_debug/
|
||||
|
||||
test.py
|
||||
server.py
|
||||
server_ip.py
|
||||
member_activity_handle.py
|
||||
Yu-Gi-Oh/
|
||||
search_image/
|
||||
black_word/
|
||||
csgo/
|
||||
fantasy_card/
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
## 声明
|
||||
此项目仅用于学习交流,请勿用于非法用途
|
||||
|
||||
## Gitee
|
||||
|
||||
# [Gitee](https://gitee.com/two_Dimension/zhenxun_bot)
|
||||
|
||||
## 未完成的文档
|
||||
|
||||
# [传送门](https://hibikier.github.io/zhenxun_bot/)
|
||||
@@ -33,7 +37,7 @@
|
||||
[AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot)
|
||||
|
||||
## 来点优点?
|
||||
一.作为bot:
|
||||
|
||||
* 实现了许多功能,且提供了大量功能管理命令
|
||||
* 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改
|
||||
* 方便增删插件,原生nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
|
||||
@@ -67,6 +71,8 @@
|
||||
- [x] 原神资源查询 (借鉴[Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot)插件)
|
||||
- [x] 原神便笺查询
|
||||
- [x] 原神玩家查询
|
||||
- [x] 原神树脂提醒
|
||||
- [x] 原神签到/自动签到
|
||||
- [x] 金币红包
|
||||
- [x] 微博热搜
|
||||
- [x] B站主播/UP/番剧订阅
|
||||
@@ -147,6 +153,7 @@
|
||||
- [x] 清理临时数据
|
||||
- [x] 增删群认证
|
||||
- [x] 同意/拒绝好友/群聊请求
|
||||
- [x] 配置重载
|
||||
|
||||
#### 超级用户的被动技能
|
||||
- [x] 邀请入群提醒(别人邀请真寻入群)
|
||||
@@ -171,6 +178,7 @@
|
||||
- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
|
||||
- [x] 群权限系统
|
||||
- [x] 定时更新权限
|
||||
- [x] 自动配置重载
|
||||
</details>
|
||||
|
||||
## 详细配置请前往文档,以下为最简部署和配置,如果你有基础并学习过nonebot2的话
|
||||
@@ -183,7 +191,7 @@
|
||||
# 配置gocq
|
||||
|
||||
在 https://github.com/Mrs4s/go-cqhttp 下载Releases最新版本,运行后选择反向代理,
|
||||
后将gocq的配置文件config.yml中的universal改为universal: ws://127.0.0.1:8080/cqhttp/ws
|
||||
后将gocq的配置文件config.yml中的universal改为universal: ws://127.0.0.1:8080/onebot/v11/ws
|
||||
|
||||
# 获取代码
|
||||
git clone https://github.com/HibiKier/zhenxun_bot.git
|
||||
@@ -192,12 +200,14 @@ git clone https://github.com/HibiKier/zhenxun_bot.git
|
||||
cd zhenxun_bot
|
||||
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
pip install poetry # 安装 poetry
|
||||
poetry install # 安装依赖
|
||||
|
||||
# 进行基础配置
|
||||
####请查看 配置 部分####
|
||||
|
||||
# 开始运行
|
||||
poetry shell # 进入虚拟环境
|
||||
python bot.py
|
||||
```
|
||||
|
||||
@@ -217,10 +227,125 @@ python bot.py
|
||||
```
|
||||
|
||||
|
||||
## 使用Docker
|
||||
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
||||
#### GitHub:[Sakuracio/zxenv](https://github.com/Sakuracio/zxenv)
|
||||
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
|
||||
|
||||
|
||||
|
||||
## 更新
|
||||
|
||||
### 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)
|
||||
|
||||
### 2021/2/11
|
||||
|
||||
* 修复pix不使用反代无法下载图片
|
||||
|
||||
### 2021/2/10 \[v0.1.1]
|
||||
|
||||
* 修复购买道具出错
|
||||
|
||||
### 2021/2/9 \[v0.1]
|
||||
|
||||
* 新增原神自动签到和手动签到
|
||||
* 新增原神树脂提醒
|
||||
* 新增手动重载Config.yaml命令以及重载配置定时任务(极少部分帮助或配置可能需要重启
|
||||
* 修改了发送本地图库的matcher,改为on_message
|
||||
* register_use可以通过返回值发送消息
|
||||
* 修复修改商品时限制时间出错
|
||||
* 修复超时商品依旧可以被购买
|
||||
|
||||
### 2021/1/16 \[v0.0.9.0]
|
||||
|
||||
* Ai提供文本敏感词过滤器
|
||||
@@ -296,7 +421,6 @@ __..... 更多更新信息请查看文档__
|
||||
|
||||
|
||||
## Todo
|
||||
- [ ] docker容器
|
||||
- [ ] web管理
|
||||
|
||||
## 感谢
|
||||
@@ -311,5 +435,5 @@ __..... 更多更新信息请查看文档__
|
||||
[H-K-Y / Genshin_Impact_bot](https://github.com/H-K-Y/Genshin_Impact_bot) :原神bot,这是一个基于nonebot和HoshinoBot的原神娱乐及信息查询插件
|
||||
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
|
||||
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
|
||||
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
|
||||
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
|
||||
[KimigaiiWuyi / GenshinUID]("https://github.com/KimigaiiWuyi/GenshinUID") :一个基于HoshinoBot/NoneBot2的原神UID查询插件
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__: v0.0.9.0
|
||||
__version__: v0.1.4.5
|
||||
Executable → Regular
+323
-319
@@ -1,319 +1,323 @@
|
||||
from typing import List
|
||||
from nonebot.adapters.cqhttp.message import MessageSegment
|
||||
from services.log import logger
|
||||
from configs.path_config import DATA_PATH
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_local_proxy, get_bot
|
||||
from pathlib import Path
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from datetime import datetime
|
||||
from services.db_context import db
|
||||
from models.level_user import LevelUser
|
||||
from configs.config import Config
|
||||
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import asyncio
|
||||
import time
|
||||
import os
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
async def group_current_status(group_id: int) -> str:
|
||||
"""
|
||||
获取当前所有通知的开关
|
||||
:param group_id: 群号
|
||||
"""
|
||||
rst = "[被动技能 状态]\n"
|
||||
_data = group_manager.get_task_data()
|
||||
for task in _data.keys():
|
||||
rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n'
|
||||
return rst.strip()
|
||||
|
||||
|
||||
custom_welcome_msg_json = (
|
||||
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
|
||||
)
|
||||
|
||||
|
||||
async def custom_group_welcome(
|
||||
msg: str, imgs: List[str], user_id: int, group_id: int
|
||||
) -> str:
|
||||
"""
|
||||
替换群欢迎消息
|
||||
:param msg: 欢迎消息文本
|
||||
:param imgs: 欢迎消息图片,只取第一张
|
||||
:param user_id: 用户id,用于log记录
|
||||
:param group_id: 群号
|
||||
"""
|
||||
img_result = ""
|
||||
img = imgs[0] if imgs else ""
|
||||
result = ""
|
||||
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"):
|
||||
os.remove(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
|
||||
if not custom_welcome_msg_json.exists():
|
||||
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
|
||||
data = {}
|
||||
else:
|
||||
try:
|
||||
data = json.load(open(custom_welcome_msg_json, "r"))
|
||||
except FileNotFoundError:
|
||||
data = {}
|
||||
try:
|
||||
if msg:
|
||||
data[str(group_id)] = str(msg)
|
||||
json.dump(
|
||||
data, open(custom_welcome_msg_json, "w"), indent=4, ensure_ascii=False
|
||||
)
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}")
|
||||
result += msg
|
||||
if img:
|
||||
await AsyncHttpx.download_file(
|
||||
img, DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"
|
||||
)
|
||||
img_result = image(abspath=DATA_PATH + f"custom_welcome_msg/{group_id}.jpg")
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片")
|
||||
except Exception as e:
|
||||
logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}")
|
||||
return "替换群消息失败.."
|
||||
return f"替换群欢迎消息成功:\n{result}" + img_result
|
||||
|
||||
|
||||
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: 是否位超级用户,超级用户用于私聊开关功能状态
|
||||
"""
|
||||
if not task_data:
|
||||
task_data = group_manager.get_task_data()
|
||||
group_help_file = Path(DATA_PATH) / "group_help" / f"{group_id}.png"
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
type_ = "plugin"
|
||||
modules = plugins2settings_manager.get_plugin_module(cmd, True)
|
||||
if cmd == "全部被动":
|
||||
for task in task_data:
|
||||
if status == "开启":
|
||||
if not await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.open_group_task(group_id, task)
|
||||
else:
|
||||
if await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.close_group_task(group_id, task)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
return f"已 {status} 全部被动技能!"
|
||||
if cmd == "全部功能":
|
||||
for f in plugins2settings_manager.get_data():
|
||||
if status == "开启":
|
||||
group_manager.unblock_plugin(f, group_id)
|
||||
else:
|
||||
group_manager.block_plugin(f, group_id)
|
||||
return f"已 {status} 全部功能!"
|
||||
if cmd in [task_data[x] for x in task_data.keys()]:
|
||||
type_ = "task"
|
||||
modules = [x for x in task_data.keys() if task_data[x] == cmd]
|
||||
for module in modules:
|
||||
if is_super:
|
||||
module = f"{module}:super"
|
||||
if status == "开启":
|
||||
if type_ == "task":
|
||||
if await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
|
||||
await group_manager.open_group_task(group_id, module)
|
||||
else:
|
||||
if group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于开启状态!不要重复开启."
|
||||
group_manager.unblock_plugin(module, group_id)
|
||||
else:
|
||||
if type_ == "task":
|
||||
if not await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
|
||||
await group_manager.close_group_task(group_id, module)
|
||||
else:
|
||||
if not group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
|
||||
group_manager.block_plugin(module, group_id)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
if is_super:
|
||||
for file in os.listdir(Path(DATA_PATH) / "group_help"):
|
||||
file = Path(DATA_PATH) / "group_help" / file
|
||||
file.unlink()
|
||||
else:
|
||||
_help_image = Path(DATA_PATH) / "group_help" / f"{group_id}.png"
|
||||
if _help_image.exists():
|
||||
_help_image.unlink()
|
||||
return f"{status} {cmd} 功能!"
|
||||
|
||||
|
||||
def set_plugin_status(cmd: str, block_type: str = "all"):
|
||||
"""
|
||||
设置插件功能状态(超级用户使用)
|
||||
:param cmd: 功能名称
|
||||
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
|
||||
"""
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
module = plugins2settings_manager.get_plugin_module(cmd)
|
||||
if status == "开启":
|
||||
plugins_manager.unblock_plugin(module)
|
||||
else:
|
||||
plugins_manager.block_plugin(module, block_type=block_type)
|
||||
for file in os.listdir(Path(DATA_PATH) / "group_help"):
|
||||
file = Path(DATA_PATH) / "group_help" / file
|
||||
file.unlink()
|
||||
|
||||
|
||||
async def get_plugin_status():
|
||||
"""
|
||||
获取功能状态
|
||||
"""
|
||||
return await asyncio.get_event_loop().run_in_executor(None, _get_plugin_status)
|
||||
|
||||
|
||||
def _get_plugin_status() -> MessageSegment:
|
||||
"""
|
||||
合成功能状态图片
|
||||
"""
|
||||
rst = "\t功能\n"
|
||||
flag_str = "状态".rjust(4) + "\n"
|
||||
for module in plugins_manager.get_data():
|
||||
flag = plugins_manager.get_plugin_block_type(module)
|
||||
flag = flag.upper() + " CLOSE" if flag else "OPEN"
|
||||
try:
|
||||
plugin_name = plugins_manager.get(module)["plugin_name"]
|
||||
if (
|
||||
"[Hidden]" in plugin_name
|
||||
or "[Admin]" in plugin_name
|
||||
or "[Superuser]" in plugin_name
|
||||
):
|
||||
continue
|
||||
rst += f"{plugin_name}"
|
||||
except KeyError:
|
||||
rst += f"{module}"
|
||||
if plugins_manager.get(module)["error"]:
|
||||
rst += "[ERROR]"
|
||||
rst += "\n"
|
||||
flag_str += f"{flag}\n"
|
||||
height = len(rst.split("\n")) * 24
|
||||
a = BuildImage(250, height, font_size=20)
|
||||
a.text((10, 10), rst)
|
||||
b = BuildImage(200, height, font_size=20)
|
||||
b.text((10, 10), flag_str)
|
||||
A = BuildImage(500, height)
|
||||
A.paste(a)
|
||||
A.paste(b, (270, 0))
|
||||
return image(b64=A.pic2bs4())
|
||||
|
||||
|
||||
async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool:
|
||||
"""
|
||||
更新群成员信息
|
||||
:param group_id: 群号
|
||||
:param remind_superuser: 失败信息提醒超级用户
|
||||
"""
|
||||
bot = get_bot()
|
||||
_group_user_list = await bot.get_group_member_list(group_id=group_id)
|
||||
_error_member_list = []
|
||||
_exist_member_list = []
|
||||
# try:
|
||||
for user_info in _group_user_list:
|
||||
if user_info["card"] == "":
|
||||
nickname = user_info["nickname"]
|
||||
else:
|
||||
nickname = user_info["card"]
|
||||
async with db.transaction():
|
||||
# 更新权限
|
||||
if (
|
||||
user_info["role"]
|
||||
in [
|
||||
"owner",
|
||||
"admin",
|
||||
]
|
||||
and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
|
||||
):
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
|
||||
)
|
||||
if str(user_info["user_id"]) in bot.config.superusers:
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"], user_info["group_id"], 9
|
||||
)
|
||||
user = await GroupInfoUser.get_member_info(
|
||||
user_info["user_id"], user_info["group_id"]
|
||||
)
|
||||
if user:
|
||||
if user.user_name != nickname:
|
||||
await user.update(user_name=nickname).apply()
|
||||
logger.info(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功"
|
||||
)
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
continue
|
||||
join_time = datetime.strptime(
|
||||
time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"])
|
||||
),
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
if await GroupInfoUser.add_member_info(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
nickname,
|
||||
join_time,
|
||||
):
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
else:
|
||||
_error_member_list.append(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n"
|
||||
)
|
||||
_del_member_list = list(
|
||||
set(_exist_member_list).difference(
|
||||
set(await GroupInfoUser.get_group_member_id_list(group_id))
|
||||
)
|
||||
)
|
||||
if _del_member_list:
|
||||
for del_user in _del_member_list:
|
||||
if await GroupInfoUser.delete_member_info(del_user, group_id):
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
|
||||
else:
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
|
||||
if _error_member_list and remind_superuser:
|
||||
result = ""
|
||||
for error_user in _error_member_list:
|
||||
result += error_user
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def set_group_bot_status(group_id: int, status: bool) -> str:
|
||||
"""
|
||||
设置群聊bot开关状态
|
||||
:param group_id: 群号
|
||||
:param status: 状态
|
||||
"""
|
||||
if status:
|
||||
if group_manager.check_group_bot_status(group_id):
|
||||
return "我还醒着呢!"
|
||||
group_manager.turn_on_group_bot_status(group_id)
|
||||
return "呜..醒来了..."
|
||||
else:
|
||||
group_manager.shutdown_group_bot_status(group_id)
|
||||
# for x in group_manager.get_task_data():
|
||||
# group_manager.close_group_task(group_id, x)
|
||||
return "那我先睡觉了..."
|
||||
from typing import List
|
||||
from nonebot.adapters.onebot.v11.message import MessageSegment
|
||||
from services.log import logger
|
||||
from configs.path_config import DATA_PATH
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_bot, get_matchers
|
||||
from pathlib import Path
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from datetime import datetime
|
||||
from services.db_context import db
|
||||
from models.level_user import LevelUser
|
||||
from configs.config import Config
|
||||
from utils.manager import group_manager, plugins2settings_manager, plugins_manager
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import asyncio
|
||||
import time
|
||||
import os
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
async def group_current_status(group_id: int) -> str:
|
||||
"""
|
||||
获取当前所有通知的开关
|
||||
:param group_id: 群号
|
||||
"""
|
||||
rst = "[被动技能 状态]\n"
|
||||
_data = group_manager.get_task_data()
|
||||
for task in _data.keys():
|
||||
rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n'
|
||||
return rst.strip()
|
||||
|
||||
|
||||
custom_welcome_msg_json = (
|
||||
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
|
||||
)
|
||||
|
||||
|
||||
async def custom_group_welcome(
|
||||
msg: str, imgs: List[str], user_id: int, group_id: int
|
||||
) -> str:
|
||||
"""
|
||||
替换群欢迎消息
|
||||
:param msg: 欢迎消息文本
|
||||
:param imgs: 欢迎消息图片,只取第一张
|
||||
:param user_id: 用户id,用于log记录
|
||||
:param group_id: 群号
|
||||
"""
|
||||
img_result = ""
|
||||
img = imgs[0] if imgs else ""
|
||||
result = ""
|
||||
if (DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").exists():
|
||||
(DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").unlink()
|
||||
if not custom_welcome_msg_json.exists():
|
||||
custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True)
|
||||
data = {}
|
||||
else:
|
||||
try:
|
||||
data = json.load(open(custom_welcome_msg_json, "r"))
|
||||
except FileNotFoundError:
|
||||
data = {}
|
||||
try:
|
||||
if msg:
|
||||
data[str(group_id)] = str(msg)
|
||||
json.dump(
|
||||
data, open(custom_welcome_msg_json, "w"), indent=4, ensure_ascii=False
|
||||
)
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}")
|
||||
result += msg
|
||||
if img:
|
||||
await AsyncHttpx.download_file(
|
||||
img, DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg"
|
||||
)
|
||||
img_result = image(DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg")
|
||||
logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片")
|
||||
except Exception as e:
|
||||
logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}")
|
||||
return "替换群消息失败.."
|
||||
return f"替换群欢迎消息成功:\n{result}" + img_result
|
||||
|
||||
|
||||
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: 是否位超级用户,超级用户用于私聊开关功能状态
|
||||
"""
|
||||
if not task_data:
|
||||
task_data = group_manager.get_task_data()
|
||||
group_help_file = DATA_PATH / "group_help" / f"{group_id}.png"
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
type_ = "plugin"
|
||||
modules = plugins2settings_manager.get_plugin_module(cmd, True)
|
||||
if cmd == "全部被动":
|
||||
for task in task_data:
|
||||
if status == "开启":
|
||||
if not await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.open_group_task(group_id, task)
|
||||
else:
|
||||
if await group_manager.check_group_task_status(group_id, task):
|
||||
await group_manager.close_group_task(group_id, task)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
return f"已 {status} 全部被动技能!"
|
||||
if cmd == "全部功能":
|
||||
for f in plugins2settings_manager.get_data():
|
||||
if status == "开启":
|
||||
group_manager.unblock_plugin(f, group_id)
|
||||
else:
|
||||
group_manager.block_plugin(f, group_id)
|
||||
return f"已 {status} 全部功能!"
|
||||
if cmd in [task_data[x] for x in task_data.keys()]:
|
||||
type_ = "task"
|
||||
modules = [x for x in task_data.keys() if task_data[x] == cmd]
|
||||
for module in modules:
|
||||
if is_super:
|
||||
module = f"{module}:super"
|
||||
if status == "开启":
|
||||
if type_ == "task":
|
||||
if await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
|
||||
await group_manager.open_group_task(group_id, module)
|
||||
else:
|
||||
if group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于开启状态!不要重复开启."
|
||||
group_manager.unblock_plugin(module, group_id)
|
||||
else:
|
||||
if type_ == "task":
|
||||
if not await group_manager.check_group_task_status(group_id, module):
|
||||
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
|
||||
await group_manager.close_group_task(group_id, module)
|
||||
else:
|
||||
if not group_manager.get_plugin_status(module, group_id):
|
||||
return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
|
||||
group_manager.block_plugin(module, group_id)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
if is_super:
|
||||
for file in os.listdir(DATA_PATH / "group_help"):
|
||||
file = DATA_PATH / "group_help" / file
|
||||
file.unlink()
|
||||
else:
|
||||
_help_image = DATA_PATH / "group_help" / f"{group_id}.png"
|
||||
if _help_image.exists():
|
||||
_help_image.unlink()
|
||||
return f"{status} {cmd} 功能!"
|
||||
|
||||
|
||||
def set_plugin_status(cmd: str, block_type: str = "all"):
|
||||
"""
|
||||
设置插件功能状态(超级用户使用)
|
||||
:param cmd: 功能名称
|
||||
:param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊
|
||||
"""
|
||||
status = cmd[:2]
|
||||
cmd = cmd[2:]
|
||||
module = plugins2settings_manager.get_plugin_module(cmd)
|
||||
if status == "开启":
|
||||
plugins_manager.unblock_plugin(module)
|
||||
else:
|
||||
plugins_manager.block_plugin(module, block_type=block_type)
|
||||
for file in os.listdir(DATA_PATH / "group_help"):
|
||||
file = DATA_PATH / "group_help" / file
|
||||
file.unlink()
|
||||
|
||||
|
||||
async def get_plugin_status():
|
||||
"""
|
||||
获取功能状态
|
||||
"""
|
||||
return await asyncio.get_event_loop().run_in_executor(None, _get_plugin_status)
|
||||
|
||||
|
||||
def _get_plugin_status() -> MessageSegment:
|
||||
"""
|
||||
合成功能状态图片
|
||||
"""
|
||||
rst = "\t功能\n"
|
||||
flag_str = "状态".rjust(4) + "\n"
|
||||
tmp_name = []
|
||||
for matcher in get_matchers():
|
||||
if matcher.plugin_name not in tmp_name:
|
||||
tmp_name.append(matcher.plugin_name)
|
||||
module = matcher.plugin_name
|
||||
flag = plugins_manager.get_plugin_block_type(module)
|
||||
flag = flag.upper() + " CLOSE" if flag else "OPEN"
|
||||
try:
|
||||
plugin_name = plugins_manager.get(module)["plugin_name"]
|
||||
if (
|
||||
"[Hidden]" in plugin_name
|
||||
or "[Admin]" in plugin_name
|
||||
or "[Superuser]" in plugin_name
|
||||
):
|
||||
continue
|
||||
rst += f"{plugin_name}"
|
||||
except KeyError:
|
||||
rst += f"{module}"
|
||||
if plugins_manager.get(module)["error"]:
|
||||
rst += "[ERROR]"
|
||||
rst += "\n"
|
||||
flag_str += f"{flag}\n"
|
||||
height = len(rst.split("\n")) * 24
|
||||
a = BuildImage(250, height, font_size=20)
|
||||
a.text((10, 10), rst)
|
||||
b = BuildImage(200, height, font_size=20)
|
||||
b.text((10, 10), flag_str)
|
||||
A = BuildImage(500, height)
|
||||
A.paste(a)
|
||||
A.paste(b, (270, 0))
|
||||
return image(b64=A.pic2bs4())
|
||||
|
||||
|
||||
async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool:
|
||||
"""
|
||||
更新群成员信息
|
||||
:param group_id: 群号
|
||||
:param remind_superuser: 失败信息提醒超级用户
|
||||
"""
|
||||
bot = get_bot()
|
||||
_group_user_list = await bot.get_group_member_list(group_id=group_id)
|
||||
_error_member_list = []
|
||||
_exist_member_list = []
|
||||
# try:
|
||||
for user_info in _group_user_list:
|
||||
if user_info["card"] == "":
|
||||
nickname = user_info["nickname"]
|
||||
else:
|
||||
nickname = user_info["card"]
|
||||
async with db.transaction():
|
||||
# 更新权限
|
||||
if (
|
||||
user_info["role"]
|
||||
in [
|
||||
"owner",
|
||||
"admin",
|
||||
]
|
||||
and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
|
||||
):
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
|
||||
)
|
||||
if str(user_info["user_id"]) in bot.config.superusers:
|
||||
await LevelUser.set_level(
|
||||
user_info["user_id"], user_info["group_id"], 9
|
||||
)
|
||||
user = await GroupInfoUser.get_member_info(
|
||||
user_info["user_id"], user_info["group_id"]
|
||||
)
|
||||
if user:
|
||||
if user.user_name != nickname:
|
||||
await user.update(user_name=nickname).apply()
|
||||
logger.info(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功"
|
||||
)
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
continue
|
||||
join_time = datetime.strptime(
|
||||
time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"])
|
||||
),
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
if await GroupInfoUser.add_member_info(
|
||||
user_info["user_id"],
|
||||
user_info["group_id"],
|
||||
nickname,
|
||||
join_time,
|
||||
):
|
||||
_exist_member_list.append(int(user_info["user_id"]))
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
else:
|
||||
_error_member_list.append(
|
||||
f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n"
|
||||
)
|
||||
_del_member_list = list(
|
||||
set(_exist_member_list).difference(
|
||||
set(await GroupInfoUser.get_group_member_id_list(group_id))
|
||||
)
|
||||
)
|
||||
if _del_member_list:
|
||||
for del_user in _del_member_list:
|
||||
if await GroupInfoUser.delete_member_info(del_user, group_id):
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 已删除")
|
||||
else:
|
||||
logger.info(f"退群用户{del_user} 所属{group_id} 删除失败")
|
||||
if _error_member_list and remind_superuser:
|
||||
result = ""
|
||||
for error_user in _error_member_list:
|
||||
result += error_user
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]), message=result[:-1]
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def set_group_bot_status(group_id: int, status: bool) -> str:
|
||||
"""
|
||||
设置群聊bot开关状态
|
||||
:param group_id: 群号
|
||||
:param status: 状态
|
||||
"""
|
||||
if status:
|
||||
if group_manager.check_group_bot_status(group_id):
|
||||
return "我还醒着呢!"
|
||||
group_manager.turn_on_group_bot_status(group_id)
|
||||
return "呜..醒来了..."
|
||||
else:
|
||||
group_manager.shutdown_group_bot_status(group_id)
|
||||
# for x in group_manager.get_task_data():
|
||||
# group_manager.close_group_task(group_id, x)
|
||||
return "那我先睡觉了..."
|
||||
@@ -1,7 +1,6 @@
|
||||
from nonebot import on_notice
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupAdminNoticeEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import GroupAdminNoticeEvent
|
||||
from models.level_user import LevelUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from configs.config import Config
|
||||
@@ -16,7 +15,7 @@ admin_notice = on_notice(priority=5)
|
||||
|
||||
|
||||
@admin_notice.handle()
|
||||
async def _(bot: Bot, event: GroupAdminNoticeEvent, state: T_State):
|
||||
async def _(event: GroupAdminNoticeEvent):
|
||||
try:
|
||||
nickname = (
|
||||
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from nonebot import on_command
|
||||
from utils.utils import get_message_text, get_message_img
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from .data_source import custom_group_welcome
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from utils.utils import get_message_img
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from ._data_source import custom_group_welcome
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from configs.config import Config
|
||||
from services.log import logger
|
||||
|
||||
@@ -35,14 +35,14 @@ custom_welcome = on_command(
|
||||
|
||||
|
||||
@custom_welcome.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
try:
|
||||
msg = get_message_text(event.json())
|
||||
imgs = get_message_img(event.json())
|
||||
if not msg and not imgs:
|
||||
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, imgs, event.user_id, event.group_id),
|
||||
await custom_group_welcome(msg, img, event.user_id, event.group_id),
|
||||
at_sender=True,
|
||||
)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}")
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import Event
|
||||
from utils.manager import group_manager, plugins2settings_manager
|
||||
from utils.utils import get_message_text
|
||||
from services.log import logger
|
||||
@@ -7,12 +6,10 @@ from services.log import logger
|
||||
cmd = []
|
||||
|
||||
|
||||
def switch_rule(bot: Bot, event: Event, state: T_State) -> bool:
|
||||
def switch_rule(event: Event) -> bool:
|
||||
"""
|
||||
检测文本是否是关闭功能命令
|
||||
:param bot: pass
|
||||
:param event: pass
|
||||
:param state: pass
|
||||
"""
|
||||
global cmd
|
||||
try:
|
||||
@@ -27,11 +24,17 @@ def switch_rule(bot: Bot, event: Event, state: T_State) -> bool:
|
||||
_data = plugins2settings_manager.get_data()
|
||||
for key in _data:
|
||||
try:
|
||||
for x in _data[key]["cmd"]:
|
||||
cmd.append(f"开启{x}")
|
||||
cmd.append(f"关闭{x}")
|
||||
cmd.append(f"开启 {x}")
|
||||
cmd.append(f"关闭 {x}")
|
||||
if isinstance(_data[key]["cmd"], list):
|
||||
for x in _data[key]["cmd"]:
|
||||
cmd.append(f"开启{x}")
|
||||
cmd.append(f"关闭{x}")
|
||||
cmd.append(f"开启 {x}")
|
||||
cmd.append(f"关闭 {x}")
|
||||
else:
|
||||
cmd.append(f"开启{key}")
|
||||
cmd.append(f"关闭{key}")
|
||||
cmd.append(f"开启 {key}")
|
||||
cmd.append(f"关闭 {key}")
|
||||
except KeyError:
|
||||
pass
|
||||
msg = get_message_text(event.json()).split()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent, GROUP
|
||||
from nonebot import on_command, on_message, on_regex
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP
|
||||
from .data_source import (
|
||||
from nonebot.params import RegexGroup
|
||||
from ._data_source import (
|
||||
change_group_switch,
|
||||
set_plugin_status,
|
||||
get_plugin_status,
|
||||
@@ -12,8 +12,8 @@ from services.log import logger
|
||||
from configs.config import NICKNAME, Config
|
||||
from utils.utils import get_message_text, is_number
|
||||
from nonebot.permission import SUPERUSER
|
||||
from typing import Tuple, Any
|
||||
from .rule import switch_rule
|
||||
import re
|
||||
|
||||
|
||||
__zx_plugin_name__ = "群功能开关 [Admin]"
|
||||
@@ -65,7 +65,7 @@ group_status = on_regex("^(休息吧|醒来)$", permission=GROUP, priority=5, bl
|
||||
|
||||
|
||||
@switch_rule_matcher.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
_cmd = get_message_text(event.json()).split()[0]
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
await switch_rule_matcher.send(await change_group_switch(_cmd, event.group_id))
|
||||
@@ -77,7 +77,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if is_number(block_type):
|
||||
if not int(block_type) in [
|
||||
g["group_id"]
|
||||
for g in await bot.get_group_list(self_id=int(bot.self_id))
|
||||
for g in await bot.get_group_list()
|
||||
]:
|
||||
await switch_rule_matcher.finish(f"{NICKNAME}未加入群聊:{block_type}")
|
||||
await change_group_switch(_cmd, int(block_type), True)
|
||||
@@ -104,22 +104,21 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@plugins_status.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
await plugins_status.send(await get_plugin_status())
|
||||
|
||||
|
||||
@group_task_status.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
await group_task_status.send(await group_current_status(event.group_id))
|
||||
|
||||
|
||||
@group_status.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
r = re.search("^(休息吧|醒来)$", get_message_text(event.json()))
|
||||
if r:
|
||||
if r.group(1) == "休息吧":
|
||||
msg = set_group_bot_status(event.group_id, False)
|
||||
else:
|
||||
msg = set_group_bot_status(event.group_id, True)
|
||||
await group_status.send(msg)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用总开关命令:{r.group(1)}")
|
||||
async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||
cmd = reg_group[0]
|
||||
if cmd == "休息吧":
|
||||
msg = set_group_bot_status(event.group_id, False)
|
||||
else:
|
||||
msg = set_group_bot_status(event.group_id, True)
|
||||
await group_status.send(msg)
|
||||
logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用总开关命令:{cmd}")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from utils.utils import scheduler, get_bot
|
||||
from .data_source import update_member_info
|
||||
from ._data_source import update_member_info
|
||||
from services.log import logger
|
||||
from models.group_info import GroupInfo
|
||||
from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from nonebot import on_command, on_notice
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
|
||||
from .data_source import update_member_info
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
|
||||
from ._data_source import update_member_info
|
||||
|
||||
__zx_plugin_name__ = "更新群组成员列表 [Admin]"
|
||||
__plugin_usage__ = """
|
||||
@@ -25,7 +24,7 @@ refresh_member_group = on_command(
|
||||
|
||||
|
||||
@refresh_member_group.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
if await update_member_info(event.group_id):
|
||||
await refresh_member_group.finish("更新群员信息成功!", at_sender=True)
|
||||
else:
|
||||
@@ -36,6 +35,6 @@ group_increase_handle = on_notice(priority=1, block=False)
|
||||
|
||||
|
||||
@group_increase_handle.handle()
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
|
||||
if event.user_id == int(bot.self_id):
|
||||
await update_member_info(event.group_id)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_help_image, admin_help_image
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ from configs.path_config import IMAGE_PATH
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
from utils.manager import group_manager
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from pathlib import Path
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot import Driver
|
||||
import asyncio
|
||||
import nonebot
|
||||
@@ -12,9 +11,9 @@ import nonebot
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
background = Path(IMAGE_PATH) / "background" / "0.png"
|
||||
background = IMAGE_PATH / "background" / "0.png"
|
||||
|
||||
admin_help_image = Path(IMAGE_PATH) / 'admin_help_img.png'
|
||||
admin_help_image = IMAGE_PATH / 'admin_help_img.png'
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
@@ -42,7 +41,7 @@ def _create_help_image():
|
||||
width = 0
|
||||
_plugin_level = {}
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
@@ -71,7 +70,7 @@ def _create_help_image():
|
||||
x = len(f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)) * 23
|
||||
width = width if width > x else x
|
||||
except AttributeError:
|
||||
logger.warning(f"获取管理插件 {matcher.module}: {plugin_name} 设置失败...")
|
||||
logger.warning(f"获取管理插件 {matcher.plugin_name}: {plugin_name} 设置失败...")
|
||||
help_str = "* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" \
|
||||
"[权限等级] 管理员帮助:\n\n"
|
||||
x = list(_plugin_level.keys())
|
||||
|
||||
@@ -4,7 +4,7 @@ from nonebot import on_message
|
||||
from services.log import logger
|
||||
from models.group_info import GroupInfo
|
||||
from models.friend_user import FriendUser
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||
from configs.config import NICKNAME, Config
|
||||
from utils.manager import group_manager
|
||||
from pathlib import Path
|
||||
@@ -57,12 +57,11 @@ async def _():
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
for g in gl:
|
||||
if await group_manager.check_group_task_status(g, 'zwa'):
|
||||
result = image("zao.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(group_id=g, message="早上好" + result)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送早安")
|
||||
result = image("zao.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + result)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送早安")
|
||||
except Exception as e:
|
||||
logger.error(f"早晚安错误 e:{e}")
|
||||
|
||||
@@ -79,14 +78,13 @@ async def _():
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
for g in gl:
|
||||
if await group_manager.check_group_task_status(g, 'zwa'):
|
||||
result = image("sleep.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(
|
||||
group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result
|
||||
)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送晚安")
|
||||
result = image("sleep.jpg", "zhenxun")
|
||||
try:
|
||||
await bot.send_group_msg(
|
||||
group_id=g, message=f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + result
|
||||
)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{g} 群被禁言中,无法发送晚安")
|
||||
except Exception as e:
|
||||
logger.error(f"早晚安错误 e:{e}")
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent, MessageEvent, Message, Bot
|
||||
from nonebot.params import CommandArg, Command
|
||||
from nonebot import on_command
|
||||
from models.ban_user import BanUser
|
||||
from models.level_user import LevelUser
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent, MessageEvent
|
||||
from utils.utils import get_message_at, get_message_text, is_number
|
||||
from typing import Tuple
|
||||
from utils.utils import get_message_at, is_number
|
||||
from configs.config import NICKNAME, Config
|
||||
from nonebot.permission import SUPERUSER
|
||||
from .data_source import parse_ban_time, a_ban
|
||||
from services.log import logger
|
||||
|
||||
|
||||
@@ -61,62 +62,35 @@ super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True)
|
||||
|
||||
|
||||
@ban.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
result = ""
|
||||
qq = get_message_at(event.json())
|
||||
if qq:
|
||||
qq = qq[0]
|
||||
user_name = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
|
||||
user_name = user_name['card'] if user_name['card'] else user_name['nickname']
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
msg = msg.split()
|
||||
if len(msg) == 2:
|
||||
if not is_number(msg[0].strip()) or not is_number(msg[1].strip()):
|
||||
await ban.finish("参数必须是数字!", at_sender=True)
|
||||
time = int(msg[0]) * 60 * 60 + int(msg[1]) * 60
|
||||
else:
|
||||
if not is_number(msg[0].strip()):
|
||||
await ban.finish("参数必须是数字!", at_sender=True)
|
||||
time = int(msg[0]) * 60 * 60
|
||||
else:
|
||||
time = -1
|
||||
if state["_prefix"]["raw_command"] in [".ban", "/ban"]:
|
||||
user_name = user_name['card'] or user_name['nickname']
|
||||
msg = arg.extract_plain_text().strip()
|
||||
time = parse_ban_time(msg)
|
||||
if isinstance(time, str):
|
||||
await ban.finish(time, at_sender=True)
|
||||
if cmd in [".ban", "/ban"]:
|
||||
if (
|
||||
await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
<= await LevelUser.get_user_level(qq, event.group_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
<= await LevelUser.get_user_level(qq, event.group_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
await ban.finish(
|
||||
f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!",
|
||||
at_sender=True,
|
||||
)
|
||||
if await BanUser.ban(
|
||||
qq, await LevelUser.get_user_level(event.user_id, event.group_id), time
|
||||
):
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time/60} 分钟"
|
||||
)
|
||||
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
|
||||
if time != -1:
|
||||
result += f"将在 {time/60} 分钟后解封"
|
||||
else:
|
||||
time = await BanUser.check_ban_time(qq)
|
||||
if is_number(time):
|
||||
time = abs(int(time))
|
||||
if time < 60:
|
||||
time = str(time) + " 秒"
|
||||
else:
|
||||
time = str(int(time / 60)) + " 分钟"
|
||||
else:
|
||||
time += " 分钟"
|
||||
result = f"{user_name} 已在黑名单!预计 {time}后解封"
|
||||
result = await a_ban(qq, time, user_name, event)
|
||||
else:
|
||||
if (
|
||||
await BanUser.check_ban_level(
|
||||
qq, await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
await BanUser.check_ban_level(
|
||||
qq, await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
await ban.finish(
|
||||
f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True
|
||||
@@ -130,78 +104,53 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
result = f"{user_name} 不在黑名单!"
|
||||
else:
|
||||
await ban.finish("艾特人了吗??", at_sender=True)
|
||||
await ban.finish(result, at_sender=True)
|
||||
await ban.send(result, at_sender=True)
|
||||
|
||||
|
||||
@ban.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
msg = get_message_text(event.json())
|
||||
msg = msg.split()
|
||||
if is_number(msg[0]):
|
||||
qq = int(msg[0])
|
||||
if state["_prefix"]["raw_command"] in [".ban", "/ban"]:
|
||||
hour = 0
|
||||
minute = 0
|
||||
if len(msg) > 1 and is_number(msg[1]):
|
||||
hour = int(msg[1])
|
||||
if len(msg) > 2 and is_number(msg[2]):
|
||||
minute = int(msg[2])
|
||||
time = hour * 60 * 60 + minute * 60
|
||||
time = time if time else -1
|
||||
if await BanUser.ban(
|
||||
qq, 9, time
|
||||
):
|
||||
logger.info(
|
||||
f"USER {event.user_id} 将 USER {qq} 封禁 时长 {time/60} 分钟"
|
||||
)
|
||||
result = f"已经将 {qq} 加入{NICKNAME}的黑名单了!"
|
||||
if time != -1:
|
||||
result += f"将在 {time/60} 分钟后解封"
|
||||
else:
|
||||
result += f"将在 ∞ 分钟后解封"
|
||||
await ban.send(result)
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if msg:
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
if is_number(arg.extract_plain_text().strip().split()[0]):
|
||||
qq = int(msg[0])
|
||||
msg = msg[1:]
|
||||
if cmd in [".ban", "/ban"]:
|
||||
time = parse_ban_time(msg)
|
||||
if isinstance(time, str):
|
||||
await ban.finish(time)
|
||||
result = await a_ban(qq, time, str(qq), event, 9)
|
||||
else:
|
||||
time = await BanUser.check_ban_time(qq)
|
||||
if is_number(time):
|
||||
time = abs(int(time))
|
||||
if time < 60:
|
||||
time = str(time) + " 秒"
|
||||
else:
|
||||
time = str(int(time / 60)) + " 分钟"
|
||||
if await BanUser.unban(qq):
|
||||
logger.info(
|
||||
f"USER {event.user_id} 将 USER {qq} 解禁"
|
||||
)
|
||||
result = f"已经把 {qq} 从黑名单中删除了!"
|
||||
else:
|
||||
time += " 分钟"
|
||||
await ban.send(f"{qq} 已在黑名单!预计 {time}后解封")
|
||||
else:
|
||||
if await BanUser.unban(qq):
|
||||
logger.info(
|
||||
f"USER {event.user_id} 将 USER {qq} 解禁"
|
||||
)
|
||||
result = f"已经把 {qq} 从黑名单中删除了!"
|
||||
else:
|
||||
result = f"{qq} 不在黑名单!"
|
||||
result = f"{qq} 不在黑名单!"
|
||||
await ban.send(result)
|
||||
else:
|
||||
await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
|
||||
else:
|
||||
await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
|
||||
|
||||
|
||||
@super_ban.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
qq = get_message_at(event.json())
|
||||
else:
|
||||
qq = get_message_text(event.json())
|
||||
qq = arg.extract_plain_text().strip()
|
||||
if not is_number(qq):
|
||||
await super_ban.finish("对象qq必须为纯数字...")
|
||||
qq = [qq]
|
||||
if qq:
|
||||
qq = qq[0]
|
||||
user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq)
|
||||
user_name = user['card'] if user['card'] else user['nickname']
|
||||
user_name = user['card'] or user['nickname']
|
||||
if not await BanUser.ban(qq, 10, 99999999):
|
||||
await BanUser.unban(qq)
|
||||
await BanUser.ban(qq, 10, 99999999)
|
||||
await ban.send(f"已将 {user_name} 拉入黑名单!")
|
||||
else:
|
||||
await super_ban.send('需要艾特被super ban的对象..')
|
||||
await super_ban.send('需要添加被super ban的对象,可以使用at或者指定qq..')
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from configs.config import NICKNAME
|
||||
from models.level_user import LevelUser
|
||||
from utils.utils import is_number
|
||||
from models.ban_user import BanUser
|
||||
from services.log import logger
|
||||
from typing import Union
|
||||
|
||||
|
||||
def parse_ban_time(msg: str) -> Union[int, str]:
|
||||
"""
|
||||
解析ban时长
|
||||
:param msg: 文本消息
|
||||
"""
|
||||
if not msg:
|
||||
return -1
|
||||
msg = msg.split()
|
||||
if len(msg) == 1:
|
||||
if not is_number(msg[0].strip()):
|
||||
return "参数必须是数字!"
|
||||
return int(msg[0]) * 60 * 60
|
||||
else:
|
||||
if not is_number(msg[0].strip()) or not is_number(msg[1].strip()):
|
||||
return "参数必须是数字!"
|
||||
return int(msg[0]) * 60 * 60 + int(msg[1]) * 60
|
||||
|
||||
|
||||
async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None) -> str:
|
||||
"""
|
||||
ban
|
||||
:param qq: qq
|
||||
:param time: ban时长
|
||||
:param user_name: ban用户昵称
|
||||
:param event: event
|
||||
:param ban_level: ban级别
|
||||
"""
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
ban_level = await LevelUser.get_user_level(event.user_id, event.group_id)
|
||||
if await BanUser.ban(qq, ban_level, time):
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time / 60} 分钟"
|
||||
)
|
||||
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
|
||||
if time != -1:
|
||||
result += f"将在 {time / 60} 分钟后解封"
|
||||
else:
|
||||
result += f"将在 ∞ 分钟后解封"
|
||||
else:
|
||||
time = await BanUser.check_ban_time(qq)
|
||||
if is_number(time):
|
||||
time = abs(int(time))
|
||||
if time < 60:
|
||||
time = str(time) + " 秒"
|
||||
else:
|
||||
time = str(int(time / 60)) + " 分钟"
|
||||
else:
|
||||
time += " 分钟"
|
||||
result = f"{user_name} 已在黑名单!预计 {time}后解封"
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.permission import SUPERUSER
|
||||
import asyncio
|
||||
from utils.utils import get_message_text, get_message_img
|
||||
from nonebot.params import CommandArg
|
||||
from utils.utils import get_message_img
|
||||
from services.log import logger
|
||||
from utils.message_builder import image
|
||||
from utils.manager import group_manager
|
||||
from configs.config import Config
|
||||
import asyncio
|
||||
|
||||
|
||||
__zx_plugin_name__ = "广播 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
@@ -33,14 +34,13 @@ broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@broadcast.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
imgs = get_message_img(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
img_list = get_message_img(event.json())
|
||||
rst = ""
|
||||
for img in imgs:
|
||||
for img in img_list:
|
||||
rst += image(img)
|
||||
sid = bot.self_id
|
||||
gl = await bot.get_group_list(self_id=sid)
|
||||
gl = await bot.get_group_list()
|
||||
gl = [
|
||||
g["group_id"]
|
||||
for g in gl
|
||||
@@ -56,7 +56,7 @@ async def _(bot: Bot, event: Event, state: T_State):
|
||||
await broadcast.send(f"已播报至 {int(cnt / g_cnt * 100)}% 的群聊")
|
||||
x += 0.25
|
||||
try:
|
||||
await bot.send_group_msg(self_id=sid, group_id=g, message=msg + rst)
|
||||
await bot.send_group_msg(group_id=g, message=msg + rst)
|
||||
logger.info(f"GROUP {g} 投递广播成功")
|
||||
except Exception as e:
|
||||
logger.error(f"GROUP {g} 投递广播失败:{type(e)}")
|
||||
|
||||
@@ -4,12 +4,12 @@ from utils.message_builder import image
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from datetime import datetime
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
GroupIncreaseNoticeEvent,
|
||||
GroupDecreaseNoticeEvent,
|
||||
)
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||
from utils.manager import group_manager, plugins2settings_manager, requests_manager
|
||||
from configs.config import NICKNAME
|
||||
from models.group_info import GroupInfo
|
||||
@@ -66,7 +66,7 @@ add_group = on_request(priority=1, block=False)
|
||||
|
||||
|
||||
@group_increase_handle.handle()
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
|
||||
if event.user_id == int(bot.self_id):
|
||||
group = await GroupInfo.get_group_info(event.group_id)
|
||||
# 群聊不存在或被强制拉群,退出该群
|
||||
@@ -112,9 +112,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
|
||||
|
||||
# 群欢迎消息
|
||||
if await group_manager.check_group_task_status(
|
||||
event.group_id, "group_welcome"
|
||||
) and _flmt.check(event.group_id):
|
||||
if _flmt.check(event.group_id):
|
||||
_flmt.start_cd(event.group_id)
|
||||
msg = ""
|
||||
img = ""
|
||||
@@ -129,23 +127,25 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
|
||||
if msg.find("[at]") != -1:
|
||||
msg = msg.replace("[at]", "")
|
||||
at_flag = True
|
||||
if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"):
|
||||
if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists():
|
||||
img = image(
|
||||
abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"
|
||||
DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg"
|
||||
)
|
||||
if msg or img:
|
||||
msg = msg.strip() + img
|
||||
msg = "\n" + msg if at_flag else msg
|
||||
await group_increase_handle.send(
|
||||
"\n" + msg.strip() + img, at_sender=at_flag
|
||||
"[[_task|group_welcome]]" + msg, at_sender=at_flag
|
||||
)
|
||||
else:
|
||||
await group_increase_handle.send(
|
||||
"新人快跑啊!!本群现状↓(快使用自定义!)"
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz")
|
||||
"[[_task|group_welcome]]新人快跑啊!!本群现状↓(快使用自定义!)"
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH / "qxz")), "qxz")
|
||||
)
|
||||
|
||||
|
||||
@group_decrease_handle.handle()
|
||||
async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
|
||||
async def _(bot: Bot, event: GroupDecreaseNoticeEvent):
|
||||
# 被踢出群
|
||||
if event.sub_type == "kick_me":
|
||||
group_id = event.group_id
|
||||
@@ -180,21 +180,16 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
|
||||
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除成功")
|
||||
else:
|
||||
logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败")
|
||||
if await group_manager.check_group_task_status(
|
||||
event.group_id, "refund_group_remind"
|
||||
):
|
||||
rst = ""
|
||||
if event.sub_type == "leave":
|
||||
rst = f"{user_name}离开了我们..."
|
||||
if event.sub_type == "kick":
|
||||
operator = await bot.get_group_member_info(
|
||||
user_id=event.operator_id, group_id=event.group_id
|
||||
)
|
||||
operator_name = (
|
||||
operator["card"] if operator["card"] else operator["nickname"]
|
||||
)
|
||||
rst = f"{user_name} 被 {operator_name} 送走了."
|
||||
try:
|
||||
await group_decrease_handle.send(f"{rst}")
|
||||
except ActionFailed:
|
||||
return
|
||||
rst = ""
|
||||
if event.sub_type == "leave":
|
||||
rst = f"{user_name}离开了我们..."
|
||||
if event.sub_type == "kick":
|
||||
operator = await bot.get_group_member_info(
|
||||
user_id=event.operator_id, group_id=event.group_id
|
||||
)
|
||||
operator_name = operator["card"] if operator["card"] else operator["nickname"]
|
||||
rst = f"{user_name} 被 {operator_name} 送走了."
|
||||
try:
|
||||
await group_decrease_handle.send(f"[[_task|refund_group_remind]]{rst}")
|
||||
except ActionFailed:
|
||||
return
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent
|
||||
GroupMessageEvent,
|
||||
Message
|
||||
)
|
||||
from nonebot.params import CommandArg
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
from configs.path_config import IMAGE_PATH, DATA_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_help_img, get_plugin_help
|
||||
from utils.utils import get_message_text
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
|
||||
__zx_plugin_name__ = "帮助"
|
||||
|
||||
group_help_path = Path(DATA_PATH) / "group_help"
|
||||
help_image = Path(IMAGE_PATH) / "help.png"
|
||||
simple_help_image = Path(IMAGE_PATH) / "simple_help.png"
|
||||
group_help_path = DATA_PATH / "group_help"
|
||||
help_image = IMAGE_PATH / "help.png"
|
||||
simple_help_image = IMAGE_PATH / "simple_help.png"
|
||||
if help_image.exists():
|
||||
help_image.unlink()
|
||||
if simple_help_image.exists():
|
||||
@@ -44,8 +44,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@simple_help.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
is_super = False
|
||||
if msg:
|
||||
if '-super' in msg:
|
||||
|
||||
@@ -16,9 +16,9 @@ import nonebot
|
||||
import os
|
||||
|
||||
|
||||
random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help"
|
||||
random_bk_path = IMAGE_PATH / "background" / "help" / "simple_help"
|
||||
|
||||
background = Path(IMAGE_PATH) / "background" / "0.png"
|
||||
background = IMAGE_PATH / "background" / "0.png"
|
||||
|
||||
|
||||
async def create_help_img(
|
||||
@@ -55,7 +55,7 @@ def _create_help_img(
|
||||
# 插件分类
|
||||
for matcher in _matchers:
|
||||
plugin_name = None
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
@@ -74,10 +74,10 @@ def _create_help_img(
|
||||
plugin_type = ("normal",)
|
||||
text_type = 0
|
||||
if plugins2settings_manager.get(
|
||||
matcher.module
|
||||
) and plugins2settings_manager[matcher.module].get("plugin_type"):
|
||||
matcher.plugin_name
|
||||
) and plugins2settings_manager[matcher.plugin_name].get("plugin_type"):
|
||||
plugin_type = tuple(
|
||||
plugins2settings_manager.get_plugin_data(matcher.module)[
|
||||
plugins2settings_manager.get_plugin_data(matcher.plugin_name)[
|
||||
"plugin_type"
|
||||
]
|
||||
)
|
||||
@@ -111,7 +111,7 @@ def _create_help_img(
|
||||
logger.warning(f"{type(e)}: {e}")
|
||||
else:
|
||||
matchers_data[plugin_type][plugin_name] = {
|
||||
"modules": matcher.module,
|
||||
"modules": matcher.plugin_name,
|
||||
"des": plugin_des,
|
||||
"cmd": plugin_cmd,
|
||||
"text_type": text_type,
|
||||
@@ -129,7 +129,7 @@ def _create_help_img(
|
||||
_des_tmp[plugin_des] = plugin_name
|
||||
except AttributeError as e:
|
||||
if plugin_name not in _plugin_name_tmp:
|
||||
logger.warning(f"获取功能 {matcher.module}: {plugin_name} 设置失败...e:{e}")
|
||||
logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e:{e}")
|
||||
if plugin_name not in _plugin_name_tmp:
|
||||
_plugin_name_tmp.append(plugin_name)
|
||||
help_img_list = []
|
||||
@@ -357,7 +357,7 @@ def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
|
||||
bk = BuildImage(
|
||||
width,
|
||||
height,
|
||||
background=Path(IMAGE_PATH) / "background" / "1.png",
|
||||
background=IMAGE_PATH / "background" / "1.png",
|
||||
)
|
||||
A.paste(bk, alpha=True)
|
||||
A.text((int(width * 0.048), int(height * 0.21)), result)
|
||||
|
||||
Executable → Regular
+52
-48
@@ -1,48 +1,52 @@
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent
|
||||
from utils.manager import plugins2block_manager, StaticData
|
||||
import time
|
||||
|
||||
|
||||
class StatusMessageManager(StaticData):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
|
||||
def add(self, id_: int):
|
||||
self._data[id_] = time.time()
|
||||
|
||||
def delete(self, id_: int):
|
||||
if self._data.get(id_):
|
||||
del self._data[id_]
|
||||
|
||||
def check(self, id_: int, t: int = 30) -> bool:
|
||||
if self._data.get(id_):
|
||||
if time.time() - self._data[id_] > t:
|
||||
del self._data[id_]
|
||||
return True
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
status_message_manager = StatusMessageManager()
|
||||
|
||||
|
||||
def set_block_limit_false(event, module):
|
||||
"""
|
||||
设置用户block为false
|
||||
:param event: event
|
||||
:param module: 插件模块
|
||||
"""
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
if not (
|
||||
(isinstance(event, GroupMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, PrivateMessageEvent) and check_type == "group")
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
plugins2block_manager.set_false(block_type_, module)
|
||||
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent
|
||||
from utils.manager import plugins2block_manager, StaticData
|
||||
import time
|
||||
|
||||
ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
|
||||
other_limit_plugins = ["poke"]
|
||||
|
||||
|
||||
class StatusMessageManager(StaticData):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
|
||||
def add(self, id_: int):
|
||||
self._data[id_] = time.time()
|
||||
|
||||
def delete(self, id_: int):
|
||||
if self._data.get(id_):
|
||||
del self._data[id_]
|
||||
|
||||
def check(self, id_: int, t: int = 30) -> bool:
|
||||
if self._data.get(id_):
|
||||
if time.time() - self._data[id_] > t:
|
||||
del self._data[id_]
|
||||
return True
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
status_message_manager = StatusMessageManager()
|
||||
|
||||
|
||||
def set_block_limit_false(event, module):
|
||||
"""
|
||||
设置用户block为false
|
||||
:param event: event
|
||||
:param module: 插件模块
|
||||
"""
|
||||
if plugins2block_manager.check_plugin_block_status(module):
|
||||
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
|
||||
check_type = plugin_block_data["check_type"]
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
if not (
|
||||
(isinstance(event, GroupMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, PrivateMessageEvent) and check_type == "group")
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
block_type_ = event.group_id
|
||||
plugins2block_manager.set_false(block_type_, module)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.bag_user import BagUser
|
||||
@@ -11,19 +11,24 @@ from utils.manager import (
|
||||
plugins_manager,
|
||||
plugins2cd_manager,
|
||||
plugins2block_manager,
|
||||
plugins2count_manager
|
||||
plugins2count_manager,
|
||||
)
|
||||
from ._utils import (
|
||||
set_block_limit_false,
|
||||
status_message_manager,
|
||||
ignore_rst_module,
|
||||
other_limit_plugins,
|
||||
)
|
||||
from .utils import set_block_limit_false, status_message_manager
|
||||
from nonebot.typing import T_State
|
||||
from typing import Optional
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
PokeNotifyEvent,
|
||||
PrivateMessageEvent,
|
||||
Message,
|
||||
Event
|
||||
Event,
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
@@ -37,35 +42,38 @@ _flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
|
||||
|
||||
ignore_rst_module = ["ai", "poke", "dialogue"]
|
||||
|
||||
|
||||
# 权限检测
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
module = matcher.module
|
||||
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
||||
module = matcher.plugin_name
|
||||
plugins2info_dict = plugins2settings_manager.get_data()
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
# 功能的金币检测 #######################################
|
||||
cost_gold = 0
|
||||
if isinstance(event, GroupMessageEvent) and plugins2settings_manager.get_plugin_data(module).get('cost_gold'):
|
||||
cost_gold = plugins2settings_manager.get_plugin_data(module).get('cost_gold')
|
||||
if isinstance(
|
||||
event, GroupMessageEvent
|
||||
) and plugins2settings_manager.get_plugin_data(module).get("cost_gold"):
|
||||
cost_gold = plugins2settings_manager.get_plugin_data(module).get("cost_gold")
|
||||
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} 金币限制...")
|
||||
# 当插件不阻塞超级用户时,超级用户提前扣除金币
|
||||
if str(event.user_id) in bot.config.superusers and not plugins2info_dict[module]["limit_superuser"]:
|
||||
if (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
|
||||
try:
|
||||
if (
|
||||
(not isinstance(event, MessageEvent) and module != "poke")
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
(not isinstance(event, MessageEvent) and module not in other_limit_plugins)
|
||||
or await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
) or (
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
str(event.user_id) in bot.config.superusers
|
||||
and plugins2info_dict.get(module)
|
||||
and not plugins2info_dict[module]["limit_superuser"]
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
@@ -76,16 +84,19 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
_module = _plugin.module
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
if (
|
||||
"[superuser]" in plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
"[superuser]" in plugin_name.lower()
|
||||
and str(event.user_id) in bot.config.superusers
|
||||
):
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
# 群黑名单检测 群总开关检测
|
||||
if isinstance(event, GroupMessageEvent) or matcher.module == "poke":
|
||||
if isinstance(event, GroupMessageEvent) or matcher.plugin_name == other_limit_plugins:
|
||||
try:
|
||||
if group_manager.get_group_level(event.group_id) < 0:
|
||||
if (
|
||||
group_manager.get_group_level(event.group_id) < 0
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
raise IgnoredException("群黑名单")
|
||||
if not group_manager.check_group_bot_status(event.group_id):
|
||||
try:
|
||||
@@ -99,12 +110,12 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
# 个人权限
|
||||
if (
|
||||
not await LevelUser.check_level(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
admin_manager.get_plugin_level(module),
|
||||
)
|
||||
and admin_manager.get_plugin_level(module) > 0
|
||||
not await LevelUser.check_level(
|
||||
event.user_id,
|
||||
event.group_id,
|
||||
admin_manager.get_plugin_level(module),
|
||||
)
|
||||
and admin_manager.get_plugin_level(module) > 0
|
||||
):
|
||||
try:
|
||||
if _flmt.check(event.user_id):
|
||||
@@ -112,7 +123,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
|
||||
f"{admin_manager.get_plugin_level(module)}",
|
||||
f"{admin_manager.get_plugin_level(module)}",
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
@@ -122,7 +133,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
raise IgnoredException("权限不足")
|
||||
else:
|
||||
if not await LevelUser.check_level(
|
||||
event.user_id, 0, admin_manager.get_plugin_level(module)
|
||||
event.user_id, 0, admin_manager.get_plugin_level(module)
|
||||
):
|
||||
try:
|
||||
await bot.send_private_msg(
|
||||
@@ -137,13 +148,11 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
raise IgnoredException("权限不足")
|
||||
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
|
||||
# 戳一戳单独判断
|
||||
if isinstance(event, GroupMessageEvent) or (
|
||||
isinstance(event, PokeNotifyEvent) and event.group_id
|
||||
):
|
||||
if isinstance(event, GroupMessageEvent) or isinstance(event, PokeNotifyEvent) or matcher.plugin_name in other_limit_plugins:
|
||||
if status_message_manager.get(event.group_id) is None:
|
||||
status_message_manager.delete(event.group_id)
|
||||
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
|
||||
event.group_id
|
||||
event.group_id
|
||||
):
|
||||
try:
|
||||
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
|
||||
@@ -161,7 +170,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if not group_manager.get_plugin_status(module, event.group_id):
|
||||
try:
|
||||
if module not in ignore_rst_module and _flmt_s.check(
|
||||
event.group_id
|
||||
event.group_id
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@@ -177,8 +186,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
|
||||
try:
|
||||
if (
|
||||
_flmt_s.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
_flmt_s.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_s.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@@ -194,8 +203,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if not plugins_manager.get_plugin_status(module, block_type="group"):
|
||||
try:
|
||||
if (
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@@ -225,14 +234,14 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
# 维护
|
||||
if not plugins_manager.get_plugin_status(module, block_type="all"):
|
||||
if isinstance(
|
||||
event, GroupMessageEvent
|
||||
event, GroupMessageEvent
|
||||
) and group_manager.check_group_is_white(event.group_id):
|
||||
return
|
||||
try:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
if (
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
_flmt_c.check(event.group_id)
|
||||
and module not in ignore_rst_module
|
||||
):
|
||||
_flmt_c.start_cd(event.group_id)
|
||||
await bot.send_group_msg(
|
||||
@@ -267,9 +276,9 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
limit_type = plugin_cd_data["limit_type"]
|
||||
rst = plugin_cd_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
|
||||
):
|
||||
cd_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
@@ -288,9 +297,9 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
limit_type = plugin_block_data["limit_type"]
|
||||
rst = plugin_block_data["rst"]
|
||||
if (
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or check_type == "all"
|
||||
(isinstance(event, PrivateMessageEvent) and check_type == "private")
|
||||
or (isinstance(event, GroupMessageEvent) and check_type == "group")
|
||||
or check_type == "all"
|
||||
):
|
||||
block_type_ = event.user_id
|
||||
if limit_type == "group" and isinstance(event, GroupMessageEvent):
|
||||
@@ -304,8 +313,8 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
plugins2block_manager.set_true(block_type_, module)
|
||||
# Count
|
||||
if (
|
||||
plugins2count_manager.check_plugin_count_status(module)
|
||||
and event.user_id not in bot.config.superusers
|
||||
plugins2count_manager.check_plugin_count_status(module)
|
||||
and event.user_id not in bot.config.superusers
|
||||
):
|
||||
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
|
||||
limit_type = plugin_count_data["limit_type"]
|
||||
@@ -354,15 +363,15 @@ async def _(
|
||||
event: Event,
|
||||
state: T_State,
|
||||
):
|
||||
if not isinstance(event, MessageEvent) and matcher.module != "poke":
|
||||
if not isinstance(event, MessageEvent) and matcher.plugin_name != "poke":
|
||||
return
|
||||
module = matcher.module
|
||||
module = matcher.plugin_name
|
||||
set_block_limit_false(event, module)
|
||||
|
||||
|
||||
async def init_rst(rst: str, event: MessageEvent):
|
||||
if "[uname]" in rst:
|
||||
uname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
uname = event.sender.card or event.sender.nickname
|
||||
rst = rst.replace("[uname]", uname)
|
||||
if "[nickname]" in rst:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
@@ -375,4 +384,3 @@ async def init_rst(rst: str, event: MessageEvent):
|
||||
if "[at]" in rst and isinstance(event, GroupMessageEvent):
|
||||
rst = rst.replace("[at]", str(at(event.user_id)))
|
||||
return rst
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
Event,
|
||||
MessageEvent,
|
||||
PokeNotifyEvent,
|
||||
GroupMessageEvent,
|
||||
)
|
||||
from configs.config import Config
|
||||
from models.ban_user import BanUser
|
||||
from utils.utils import is_number, static_flmt, FreqLimiter
|
||||
from utils.message_builder import at
|
||||
from ._utils import ignore_rst_module, other_limit_plugins
|
||||
|
||||
|
||||
Config.add_plugin_config(
|
||||
@@ -25,18 +28,19 @@ _flmt = FreqLimiter(300)
|
||||
|
||||
# 检查是否被ban
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
try:
|
||||
if (
|
||||
await BanUser.is_super_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
raise IgnoredException("用户处于超级黑名单中")
|
||||
except AttributeError:
|
||||
pass
|
||||
if not isinstance(event, MessageEvent):
|
||||
return
|
||||
if matcher.type == "message" and matcher.priority not in [1, 9]:
|
||||
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
|
||||
if (
|
||||
(isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent))
|
||||
and matcher.priority not in [1, 9]
|
||||
) or matcher.plugin_name in other_limit_plugins:
|
||||
try:
|
||||
if (
|
||||
await BanUser.is_super_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
):
|
||||
raise IgnoredException("用户处于超级黑名单中")
|
||||
except AttributeError:
|
||||
pass
|
||||
if (
|
||||
await BanUser.is_ban(event.user_id)
|
||||
and str(event.user_id) not in bot.config.superusers
|
||||
@@ -57,7 +61,11 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if matcher.priority != 9:
|
||||
try:
|
||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||
if ban_result and _flmt.check(event.user_id):
|
||||
if (
|
||||
ban_result
|
||||
and _flmt.check(event.user_id)
|
||||
and matcher.plugin_name not in ignore_rst_module
|
||||
):
|
||||
_flmt.start_cd(event.user_id)
|
||||
await bot.send_group_msg(
|
||||
group_id=event.group_id,
|
||||
@@ -74,7 +82,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if matcher.priority != 9:
|
||||
try:
|
||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||
if ban_result:
|
||||
if ban_result and matcher.plugin_name not in ignore_rst_module:
|
||||
await bot.send_private_msg(
|
||||
user_id=event.user_id,
|
||||
message=at(event.user_id)
|
||||
@@ -83,4 +91,4 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
)
|
||||
except ActionFailed:
|
||||
pass
|
||||
raise IgnoredException("用户处于黑名单中")
|
||||
raise IgnoredException("用户处于黑名单中")
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor, IgnoredException
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
MessageEvent,
|
||||
GroupMessageEvent,
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
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 nonebot.adapters.cqhttp import (
|
||||
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会自己和自己聊天
|
||||
@@ -24,7 +27,7 @@ async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_Sta
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
if not isinstance(event, MessageEvent):
|
||||
return
|
||||
if matcher.type == "message" and matcher.module == "ai":
|
||||
if matcher.type == "message" and matcher.plugin_name == "ai":
|
||||
if (
|
||||
isinstance(event, GroupMessageEvent)
|
||||
and not status_message_manager.check(event.group_id)
|
||||
@@ -35,7 +38,14 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
isinstance(event, PrivateMessageEvent)
|
||||
and not status_message_manager.check(event.user_id)
|
||||
):
|
||||
print(status_message_manager)
|
||||
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\|?(.*?)[[")):
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
from nonebot.exception import MockApiException
|
||||
from nonebot.adapters.onebot.v11 import Bot, Message
|
||||
from utils.manager import group_manager
|
||||
from typing import Dict, Any
|
||||
import re
|
||||
|
||||
|
||||
@Bot.on_calling_api
|
||||
async def handle_api_call(bot: Bot, api: str, data: Dict[str, Any]):
|
||||
r = None
|
||||
if (
|
||||
(
|
||||
(api == "send_msg" and data["message_type"] == "group")
|
||||
or api == "send_group_msg"
|
||||
)
|
||||
and (
|
||||
(
|
||||
r := re.search(
|
||||
"^\[\[_task\|(.*)]]",
|
||||
data["message"].strip()
|
||||
if isinstance(data["message"], str)
|
||||
else str(data["message"]["text"]).strip(),
|
||||
)
|
||||
)
|
||||
or (
|
||||
r := re.search(
|
||||
"^[[_task\|(.*)]]",
|
||||
data["message"].strip()
|
||||
if isinstance(data["message"], str)
|
||||
else str(data["message"]["text"]).strip(),
|
||||
)
|
||||
)
|
||||
)
|
||||
and r.group(1) in group_manager.get_task_data().keys()
|
||||
):
|
||||
task = r.group(1)
|
||||
group_id = data["group_id"]
|
||||
if group_manager.get_group_level(
|
||||
group_id
|
||||
) < 0 or not await group_manager.check_group_task_status(group_id, task):
|
||||
raise MockApiException(f"被动技能 {task} 处于关闭状态...")
|
||||
else:
|
||||
msg = str(data["message"]).strip()
|
||||
msg = msg.replace(f"[[_task|{task}]]", "").replace(
|
||||
f"[[_task|{task}]]", ""
|
||||
)
|
||||
data["message"] = Message(msg)
|
||||
@@ -2,7 +2,7 @@ from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_postprocessor
|
||||
from typing import Optional
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.adapters.onebot.v11 import Bot, Event
|
||||
from utils.manager import withdraw_message_manager
|
||||
import asyncio
|
||||
|
||||
@@ -25,4 +25,4 @@ async def _(
|
||||
|
||||
async def _withdraw_message(bot: Bot, id_: int, time: int):
|
||||
await asyncio.sleep(time)
|
||||
await bot.delete_msg(message_id=id_, self_id=int(bot.self_id))
|
||||
await bot.delete_msg(message_id=id_)
|
||||
|
||||
@@ -11,8 +11,7 @@ from .init_plugins_limit import (
|
||||
)
|
||||
from .init import init
|
||||
from .check_plugin_status import check_plugin_status
|
||||
from utils.manager import admin_manager
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from configs.path_config import DATA_PATH
|
||||
from services.log import logger
|
||||
from pathlib import Path
|
||||
@@ -34,7 +33,7 @@ def _():
|
||||
初始化数据
|
||||
"""
|
||||
_flag = False
|
||||
config_file = Path(DATA_PATH) / "configs" / "plugins2config.yaml"
|
||||
config_file = DATA_PATH / "configs" / "plugins2config.yaml"
|
||||
if not config_file.exists():
|
||||
_flag = True
|
||||
init()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from utils.manager import plugins_manager
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
|
||||
|
||||
async def check_plugin_status(bot: Bot):
|
||||
|
||||
@@ -15,14 +15,14 @@ def init_plugins_config(data_path):
|
||||
"""
|
||||
初始化插件数据配置
|
||||
"""
|
||||
plugins2config_file = Path(data_path) / "configs" / "plugins2config.yaml"
|
||||
plugins2config_file = data_path / "configs" / "plugins2config.yaml"
|
||||
plugins2config_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
_data = {}
|
||||
if plugins2config_file.exists():
|
||||
_data = _yaml.load(open(plugins2config_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
@@ -39,16 +39,16 @@ def init_plugins_config(data_path):
|
||||
if (
|
||||
plugin_version is None
|
||||
or (
|
||||
_data.get(matcher.module)
|
||||
and _data[matcher.module].keys() != plugin_configs.keys()
|
||||
_data.get(matcher.plugin_name)
|
||||
and _data[matcher.plugin_name].keys() != plugin_configs.keys()
|
||||
)
|
||||
or plugin_version > plugins_manager.get(matcher.module)["version"]
|
||||
or matcher.module not in _data.keys()
|
||||
or plugin_version > plugins_manager.get(matcher.plugin_name)["version"]
|
||||
or matcher.plugin_name not in _data.keys()
|
||||
):
|
||||
for key in plugin_configs:
|
||||
if isinstance(plugin_configs[key], dict):
|
||||
Config.add_plugin_config(
|
||||
matcher.module,
|
||||
matcher.plugin_name,
|
||||
key,
|
||||
plugin_configs[key].get("value"),
|
||||
help_=plugin_configs[key].get("help"),
|
||||
@@ -56,12 +56,12 @@ def init_plugins_config(data_path):
|
||||
_override=True,
|
||||
)
|
||||
else:
|
||||
Config.add_plugin_config(matcher.module, key, plugin_configs[key])
|
||||
Config.add_plugin_config(matcher.plugin_name, key, plugin_configs[key])
|
||||
else:
|
||||
plugin_configs = _data[matcher.module]
|
||||
plugin_configs = _data[matcher.plugin_name]
|
||||
for key in plugin_configs:
|
||||
Config.add_plugin_config(
|
||||
matcher.module,
|
||||
matcher.plugin_name,
|
||||
key,
|
||||
plugin_configs[key]["value"],
|
||||
help_=plugin_configs[key]["help"],
|
||||
@@ -99,7 +99,10 @@ def init_plugins_config(data_path):
|
||||
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):
|
||||
admin_manager.set_admin_level(level2module, _data[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)
|
||||
Config.save()
|
||||
temp_file = Path() / "configs" / "temp_config.yaml"
|
||||
|
||||
@@ -17,27 +17,27 @@ def init_plugins_data(data_path):
|
||||
"""
|
||||
初始化插件数据信息
|
||||
"""
|
||||
plugin2data_file = Path(data_path) / "manager" / "plugin_manager.json"
|
||||
plugin2data_file = data_path / "manager" / "plugin_manager.json"
|
||||
plugin2data_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
_data = {}
|
||||
if plugin2data_file.exists():
|
||||
_data = json.load(open(plugin2data_file, "r", encoding="utf8"))
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
if matcher.module not in _data.keys():
|
||||
if matcher.plugin_name not in _data.keys():
|
||||
plugins_manager.add_plugin_data(
|
||||
matcher.module, matcher.module, error=True
|
||||
matcher.plugin_name, matcher.plugin_name, error=True
|
||||
)
|
||||
else:
|
||||
plugins_manager.set_module_data(matcher.module, "error", True)
|
||||
plugin_data = plugins_manager.get(matcher.module)
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "error", True)
|
||||
plugin_data = plugins_manager.get(matcher.plugin_name)
|
||||
if plugin_data:
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "version", plugin_data.get("version")
|
||||
matcher.plugin_name, "version", plugin_data.get("version")
|
||||
)
|
||||
else:
|
||||
try:
|
||||
@@ -47,36 +47,36 @@ def init_plugins_data(data_path):
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
except AttributeError:
|
||||
plugin_name = matcher.module
|
||||
plugin_name = matcher.plugin_name
|
||||
try:
|
||||
plugin_author = _module.__getattribute__("__plugin_author__")
|
||||
except AttributeError:
|
||||
plugin_author = None
|
||||
if matcher.module in plugins_manager.keys():
|
||||
plugins_manager.set_module_data(matcher.module, "error", False)
|
||||
if matcher.module not in plugins_manager.keys():
|
||||
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.module,
|
||||
matcher.plugin_name,
|
||||
plugin_name=plugin_name,
|
||||
author=plugin_author,
|
||||
version=plugin_version,
|
||||
)
|
||||
elif plugins_manager[matcher.module]["version"] is None or (
|
||||
elif plugins_manager[matcher.plugin_name]["version"] is None or (
|
||||
plugin_version is not None
|
||||
and plugin_version > plugins_manager[matcher.module]["version"]
|
||||
and plugin_version > plugins_manager[matcher.plugin_name]["version"]
|
||||
):
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "plugin_name", plugin_name
|
||||
matcher.plugin_name, "plugin_name", plugin_name
|
||||
)
|
||||
plugins_manager.set_module_data(matcher.module, "author", plugin_author)
|
||||
plugins_manager.set_module_data(matcher.plugin_name, "author", plugin_author)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "version", plugin_version
|
||||
matcher.plugin_name, "version", plugin_version
|
||||
)
|
||||
if matcher.module in _data.keys():
|
||||
if matcher.plugin_name in _data.keys():
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "error", _data[matcher.module]["error"]
|
||||
matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
|
||||
)
|
||||
plugins_manager.set_module_data(
|
||||
matcher.module, "plugin_name", _data[matcher.module]["plugin_name"]
|
||||
matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
|
||||
)
|
||||
plugins_manager.save()
|
||||
|
||||
@@ -17,18 +17,18 @@ def init_plugins_cd_limit(data_path):
|
||||
"""
|
||||
加载 cd 限制
|
||||
"""
|
||||
plugins2cd_file = Path(data_path) / "configs" / "plugins2cd.yaml"
|
||||
plugins2cd_file = data_path / "configs" / "plugins2cd.yaml"
|
||||
plugins2cd_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
if not plugins2cd_manager.get_plugin_cd_data(matcher.module):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
|
||||
plugins2cd_manager.add_cd_limit(
|
||||
matcher.module, data_dict=plugin_cd_limit
|
||||
matcher.plugin_name, data_dict=plugin_cd_limit
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
@@ -65,18 +65,18 @@ def init_plugins_block_limit(data_path):
|
||||
"""
|
||||
加载阻塞限制
|
||||
"""
|
||||
plugins2block_file = Path(data_path) / "configs" / "plugins2block.yaml"
|
||||
plugins2block_file = data_path / "configs" / "plugins2block.yaml"
|
||||
plugins2block_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
if not plugins2block_manager.get_plugin_block_data(matcher.module):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
|
||||
plugins2block_manager.add_block_limit(
|
||||
matcher.module, data_dict=plugin_block_limit
|
||||
matcher.plugin_name, data_dict=plugin_block_limit
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
@@ -113,18 +113,18 @@ def init_plugins_count_limit(data_path):
|
||||
"""
|
||||
加载次数限制
|
||||
"""
|
||||
plugins2count_file = Path(data_path) / "configs" / "plugins2count.yaml"
|
||||
plugins2count_file = data_path / "configs" / "plugins2count.yaml"
|
||||
plugins2count_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_data = {}
|
||||
_matchers = get_matchers()
|
||||
for matcher in _matchers:
|
||||
if not plugins2count_manager.get_plugin_count_data(matcher.module):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
if not plugins2count_manager.get_plugin_count_data(matcher.plugin_name):
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
plugin_count_limit = _module.__getattribute__("__plugin_count_limit__")
|
||||
plugins2count_manager.add_count_limit(
|
||||
matcher.module, data_dict=plugin_count_limit
|
||||
matcher.plugin_name, data_dict=plugin_count_limit
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@@ -11,13 +11,13 @@ def init_plugins_resources():
|
||||
"""
|
||||
_tmp = []
|
||||
for matcher in get_matchers():
|
||||
if matcher.module not in _tmp:
|
||||
_tmp.append(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
if matcher.plugin_name not in _tmp:
|
||||
_tmp.append(matcher.plugin_name)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
try:
|
||||
_module = _plugin.module
|
||||
except AttributeError:
|
||||
logger.warning(f"插件 {matcher.module} 加载失败...,资源控制未加载...")
|
||||
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,资源控制未加载...")
|
||||
else:
|
||||
try:
|
||||
resources = _module.__getattribute__("__plugin_resources__")
|
||||
@@ -26,7 +26,7 @@ def init_plugins_resources():
|
||||
else:
|
||||
path = Path(_module.__getattribute__("__file__")).parent
|
||||
for resource in resources.keys():
|
||||
resources_manager.add_resource(matcher.module, (path / resource).absolute(), resources[resource])
|
||||
resources_manager.add_resource(matcher.plugin_name, path / resource, resources[resource])
|
||||
resources_manager.save()
|
||||
resources_manager.start_move()
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ def init_plugins_settings(data_path: str):
|
||||
"""
|
||||
初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
|
||||
"""
|
||||
plugins2settings_file = Path(data_path) / "configs" / "plugins2settings.yaml"
|
||||
plugins2settings_file = data_path / "configs" / "plugins2settings.yaml"
|
||||
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
|
||||
_matchers = get_matchers()
|
||||
_tmp_module = {}
|
||||
@@ -29,12 +29,12 @@ def init_plugins_settings(data_path: str):
|
||||
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
|
||||
_tmp_module[x] = ""
|
||||
for matcher in _matchers:
|
||||
if matcher.module not in plugins2settings_manager.keys():
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
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.module} 加载失败...,插件控制未加载.")
|
||||
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
|
||||
else:
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
@@ -51,41 +51,41 @@ def init_plugins_settings(data_path: str):
|
||||
if level is None:
|
||||
level = 5
|
||||
admin_manager.add_admin_plugin_settings(
|
||||
matcher.module, cmd, level
|
||||
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.module in plugins2settings_manager.keys()
|
||||
or matcher.plugin_name in plugins2settings_manager.keys()
|
||||
):
|
||||
continue
|
||||
except AttributeError:
|
||||
if matcher.module not in _tmp:
|
||||
if matcher.plugin_name not in _tmp:
|
||||
logger.warning(
|
||||
f"获取插件 {matcher.module} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||
)
|
||||
else:
|
||||
try:
|
||||
_tmp_module[matcher.module] = plugin_name
|
||||
_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
|
||||
if (
|
||||
plugin_settings["cmd"] is not None
|
||||
plugin_settings.get("cmd") is not None
|
||||
and plugin_name not in plugin_settings["cmd"]
|
||||
):
|
||||
plugin_settings["cmd"].append(plugin_name)
|
||||
if plugins2settings_manager.get(
|
||||
matcher.module
|
||||
) and plugins2settings_manager[matcher.module].get(
|
||||
matcher.plugin_name
|
||||
) and plugins2settings_manager[matcher.plugin_name].get(
|
||||
"plugin_type"
|
||||
):
|
||||
plugin_type = tuple(
|
||||
plugins2settings_manager.get_plugin_data(
|
||||
matcher.module
|
||||
matcher.plugin_name
|
||||
)["plugin_type"]
|
||||
)
|
||||
else:
|
||||
@@ -95,15 +95,15 @@ def init_plugins_settings(data_path: str):
|
||||
)
|
||||
except AttributeError:
|
||||
plugin_type = ("normal",)
|
||||
if plugin_settings and matcher.module:
|
||||
if plugin_settings and matcher.plugin_name:
|
||||
plugins2settings_manager.add_plugin_settings(
|
||||
matcher.module,
|
||||
matcher.plugin_name,
|
||||
plugin_type=plugin_type,
|
||||
**plugin_settings,
|
||||
)
|
||||
except AttributeError:
|
||||
pass
|
||||
_tmp.append(matcher.module)
|
||||
_tmp.append(matcher.plugin_name)
|
||||
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
|
||||
with open(plugins2settings_file, "w", encoding="utf8") as wf:
|
||||
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from nonebot import on_request, on_message
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
FriendRequestEvent,
|
||||
GroupRequestEvent,
|
||||
@@ -8,7 +8,7 @@ from nonebot.adapters.cqhttp import (
|
||||
from models.friend_user import FriendUser
|
||||
from datetime import datetime
|
||||
from configs.config import NICKNAME, Config
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||
from utils.manager import requests_manager
|
||||
from models.group_info import GroupInfo
|
||||
from utils.utils import scheduler
|
||||
@@ -31,7 +31,7 @@ exists_data = {"private": {}, "group": {}}
|
||||
|
||||
|
||||
@friend_req.handle()
|
||||
async def _(bot: Bot, event: FriendRequestEvent, state: dict):
|
||||
async def _(bot: Bot, event: FriendRequestEvent):
|
||||
global exists_data
|
||||
if exists_data["private"].get(event.user_id):
|
||||
if time.time() - exists_data["private"][event.user_id] < 60 * 5:
|
||||
@@ -66,7 +66,7 @@ async def _(bot: Bot, event: FriendRequestEvent, state: dict):
|
||||
|
||||
|
||||
@group_req.handle()
|
||||
async def _(bot: Bot, event: GroupRequestEvent, state: dict):
|
||||
async def _(bot: Bot, event: GroupRequestEvent):
|
||||
global exists_data
|
||||
if event.sub_type == "invite":
|
||||
if str(event.user_id) in bot.config.superusers:
|
||||
@@ -125,7 +125,7 @@ async def _(bot: Bot, event: GroupRequestEvent, state: dict):
|
||||
|
||||
|
||||
@x.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: dict):
|
||||
async def _(event: MessageEvent):
|
||||
await asyncio.sleep(0.1)
|
||||
r = re.search(r'groupcode="(.*?)"', str(event.get_message()))
|
||||
if r:
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, PrivateMessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from models.friend_user import FriendUser
|
||||
import random
|
||||
from models.ban_user import BanUser
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME, Config
|
||||
|
||||
from nonebot.params import CommandArg
|
||||
import random
|
||||
|
||||
__zx_plugin_name__ = "昵称系统"
|
||||
__plugin_usage__ = f"""
|
||||
@@ -48,8 +47,8 @@ cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=Tru
|
||||
|
||||
|
||||
@nickname.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if not msg:
|
||||
await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True)
|
||||
if len(msg) > 10:
|
||||
@@ -103,7 +102,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
|
||||
|
||||
@my_nickname.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
try:
|
||||
nickname_ = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
@@ -124,7 +123,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
)
|
||||
)
|
||||
else:
|
||||
nickname_ = event.sender.card if event.sender.card else event.sender.nickname
|
||||
nickname_ = event.sender.card or event.sender.nickname
|
||||
await my_nickname.send(
|
||||
random.choice(
|
||||
["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
|
||||
@@ -158,7 +157,7 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
|
||||
|
||||
@cancel_nickname.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
nickname_ = await GroupInfoUser.get_group_member_nickname(
|
||||
event.user_id, event.group_id
|
||||
)
|
||||
@@ -181,7 +180,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
|
||||
|
||||
@cancel_nickname.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
async def _(event: PrivateMessageEvent):
|
||||
nickname_ = await FriendUser.get_friend_nickname(event.user_id)
|
||||
if nickname_:
|
||||
await cancel_nickname.send(
|
||||
|
||||
@@ -7,14 +7,13 @@ from nonebot import Driver
|
||||
from services.db_context import db
|
||||
from models.group_info import GroupInfo
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from services.log import logger
|
||||
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 scheduler
|
||||
from pathlib import Path
|
||||
import nonebot
|
||||
|
||||
try:
|
||||
@@ -32,7 +31,7 @@ async def update_city():
|
||||
部分插件需要中国省份城市
|
||||
这里直接更新,避免插件内代码重复
|
||||
"""
|
||||
china_city = Path(TEXT_PATH) / "china_city.json"
|
||||
china_city = TEXT_PATH / "china_city.json"
|
||||
data = {}
|
||||
if not china_city.exists():
|
||||
try:
|
||||
@@ -93,6 +92,22 @@ async def _():
|
||||
"ALTER TABLE bag_users ADD property json NOT NULL DEFAULT '{}';",
|
||||
"bag_users",
|
||||
), # bag_users 新增字段 property 替代 props
|
||||
(
|
||||
"ALTER TABLE genshin ADD auto_sign_time timestamp with time zone;",
|
||||
"genshin"
|
||||
), # 新增原神自动签到字段
|
||||
(
|
||||
"ALTER TABLE genshin ADD resin_remind boolean DEFAULT False;",
|
||||
"genshin"
|
||||
), # 新增原神自动签到字段
|
||||
(
|
||||
"ALTER TABLE genshin ADD resin_recovery_time timestamp with time zone;",
|
||||
"genshin"
|
||||
), # 新增原神自动签到字段
|
||||
(
|
||||
"ALTER TABLE genshin ADD bind_group Integer;",
|
||||
"genshin"
|
||||
), # 新增原神群号绑定字段
|
||||
]
|
||||
for sql in sql_str:
|
||||
try:
|
||||
|
||||
+25
-20
@@ -1,12 +1,13 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import get_message_text, is_number
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from utils.utils import is_number
|
||||
from models.bag_user import BagUser
|
||||
from services.db_context import db
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from models.goods_info import GoodsInfo
|
||||
import time
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 购买道具"
|
||||
@@ -20,7 +21,7 @@ usage:
|
||||
""".strip()
|
||||
__plugin_des__ = "商店 - 购买道具"
|
||||
__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"]
|
||||
__plugin_type__ = ('商店',)
|
||||
__plugin_type__ = ("商店",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
@@ -29,39 +30,43 @@ __plugin_settings__ = {
|
||||
"limit_superuser": False,
|
||||
"cmd": ["商店", "购买道具"],
|
||||
}
|
||||
__plugin_cd_limit__ = {
|
||||
"cd": 3
|
||||
}
|
||||
__plugin_cd_limit__ = {"cd": 3}
|
||||
|
||||
|
||||
buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@buy.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
goods = None
|
||||
if get_message_text(event.json()) in ["神秘药水"]:
|
||||
if arg.extract_plain_text().strip() in ["神秘药水"]:
|
||||
await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True)
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
goods_name_lst = [x.goods_name for x in goods_lst]
|
||||
msg = get_message_text(event.json()).split()
|
||||
goods_list = [
|
||||
x
|
||||
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
|
||||
]
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
num = 1
|
||||
if len(msg) > 1:
|
||||
if is_number(msg[1]) and int(msg[1]) > 0:
|
||||
num = int(msg[1])
|
||||
else:
|
||||
await buy.finish("购买的数量要是数字且大于0!", at_sender=True)
|
||||
# print(msg, num)
|
||||
if is_number(msg[0]):
|
||||
msg = int(msg[0])
|
||||
if msg > len(goods_lst) or msg < 1:
|
||||
if msg > len(goods_name_list) or msg < 1:
|
||||
await buy.finish("请输入正确的商品id!", at_sender=True)
|
||||
goods = goods_lst[msg - 1]
|
||||
goods = goods_list[msg - 1]
|
||||
else:
|
||||
if msg[0] in goods_name_lst:
|
||||
for i in range(len(goods_name_lst)):
|
||||
if msg[0] == goods_name_lst[i]:
|
||||
goods = goods_lst[i]
|
||||
if msg[0] in goods_name_list:
|
||||
for i in range(len(goods_name_list)):
|
||||
if msg[0] == goods_name_list[i]:
|
||||
goods = goods_list[i]
|
||||
break
|
||||
else:
|
||||
await buy.finish("请输入正确的商品名称!")
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from utils.data_utils import init_rank
|
||||
from models.bag_user import BagUser
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.utils import is_number
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的金币"
|
||||
__plugin_usage__ = """
|
||||
@@ -33,13 +33,13 @@ gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_gold.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
await my_gold.finish(await BagUser.get_user_total_gold(event.user_id, event.group_id))
|
||||
|
||||
|
||||
@gold_rank.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
num = get_message_text(event.json())
|
||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
num = arg.extract_plain_text().strip()
|
||||
if is_number(num) and 51 > int(num) > 10:
|
||||
num = int(num)
|
||||
else:
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
|
||||
|
||||
__zx_plugin_name__ = "商店 - 我的道具"
|
||||
@@ -30,7 +29,7 @@ my_props = on_command("我的道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@my_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
props = await BagUser.get_property(event.user_id, event.group_id)
|
||||
if props:
|
||||
rst = ""
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, Message
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.utils import is_number
|
||||
from nonebot.params import CommandArg
|
||||
from nonebot.plugin import export
|
||||
from services.log import logger
|
||||
import os
|
||||
@@ -67,13 +67,13 @@ shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER,
|
||||
|
||||
|
||||
@shop_help.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _():
|
||||
await shop_help.send(image(b64=await create_shop_help()))
|
||||
|
||||
|
||||
@shop_add_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if msg:
|
||||
data = parse_goods_info(msg)
|
||||
if isinstance(data, str):
|
||||
@@ -94,8 +94,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@shop_del_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if msg:
|
||||
name = ""
|
||||
id_ = 0
|
||||
@@ -115,8 +115,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@shop_update_goods.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if msg:
|
||||
data = parse_goods_info(msg)
|
||||
if isinstance(data, str):
|
||||
|
||||
@@ -217,11 +217,12 @@ async def update_goods(**kwargs) -> "str, str, int":
|
||||
tmp += f'折扣:{discount} --> {kwargs["discount"]}\n'
|
||||
discount = kwargs["discount"]
|
||||
if kwargs.get("limit_time"):
|
||||
kwargs["limit_time"] = float(kwargs["limit_time"])
|
||||
new_time = time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
time.localtime(time.time() + int(kwargs["limit_time"] * 60 * 60)),
|
||||
time.localtime(time.time() + kwargs["limit_time"] * 60 * 60),
|
||||
)
|
||||
tmp += f"折扣至: {new_time}\n"
|
||||
tmp += f"限时至: {new_time}\n"
|
||||
limit_time = kwargs["limit_time"]
|
||||
return (
|
||||
await GoodsInfo.update_goods(
|
||||
@@ -249,7 +250,6 @@ def parse_goods_info(msg: str) -> Union[dict, str]:
|
||||
sp = x.split(":", maxsplit=1)
|
||||
if str(sp[1]).strip():
|
||||
sp[1] = sp[1].strip()
|
||||
print(sp)
|
||||
if sp[0] == "name":
|
||||
data["name"] = sp[1]
|
||||
elif sp[0] == "price":
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from nonebot import on_command
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.utils import is_number, get_message_text
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from utils.utils import is_number
|
||||
from models.bag_user import BagUser
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
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
|
||||
@@ -38,10 +38,8 @@ use_props = on_command("使用道具", priority=5, block=True, permission=GROUP)
|
||||
|
||||
|
||||
@use_props.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg in ["", "帮助"]:
|
||||
await use_props.finish(__plugin_usage__)
|
||||
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
num = 1
|
||||
msg_sp = msg.split()
|
||||
if len(msg_sp) > 1 and is_number(msg_sp[-1]) and int(msg_sp[-1]) > 0:
|
||||
@@ -66,9 +64,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
await use_props.finish(f"该道具单次只能使用 {n} 个!")
|
||||
if await BagUser.delete_property(
|
||||
event.user_id, event.group_id, name, num
|
||||
) and await effect(bot, event, name, num):
|
||||
):
|
||||
if func_manager.check_send_success_message(name):
|
||||
await use_props.send(f"使用道具 {name} {num} 次成功!", at_sender=True)
|
||||
if msg := await effect(bot, event, name, num):
|
||||
await use_props.send(msg, at_sender=True)
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次成功"
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from nonebot.adapters.cqhttp import GroupMessageEvent
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from typing import Optional, Union
|
||||
import asyncio
|
||||
|
||||
|
||||
@@ -32,7 +33,7 @@ class GoodsUseFuncManager:
|
||||
return self._data[goods_name]["kwargs"]["_max_num_limit"]
|
||||
return 1
|
||||
|
||||
async def use(self, **kwargs):
|
||||
async def use(self, **kwargs) -> Optional[Union[str, MessageSegment]]:
|
||||
"""
|
||||
使用道具
|
||||
:param kwargs: kwargs
|
||||
@@ -40,11 +41,11 @@ class GoodsUseFuncManager:
|
||||
goods_name = kwargs.get("goods_name")
|
||||
if self.exists(goods_name):
|
||||
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
|
||||
await self._data[goods_name]["func"](
|
||||
return await self._data[goods_name]["func"](
|
||||
**kwargs,
|
||||
)
|
||||
else:
|
||||
self._data[goods_name]["func"](
|
||||
return self._data[goods_name]["func"](
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@@ -70,7 +71,9 @@ class GoodsUseFuncManager:
|
||||
func_manager = GoodsUseFuncManager()
|
||||
|
||||
|
||||
async def effect(bot: Bot, event: GroupMessageEvent, goods_name: str, num: int) -> bool:
|
||||
async def effect(
|
||||
bot: Bot, event: GroupMessageEvent, goods_name: str, num: int
|
||||
) -> Optional[Union[str, MessageSegment]]:
|
||||
"""
|
||||
商品生效
|
||||
:param bot: Bot
|
||||
@@ -83,7 +86,7 @@ async def effect(bot: Bot, event: GroupMessageEvent, goods_name: str, num: int)
|
||||
try:
|
||||
if func_manager.exists(goods_name):
|
||||
_kwargs = func_manager.get_kwargs(goods_name)
|
||||
await func_manager.use(
|
||||
return await func_manager.use(
|
||||
**{
|
||||
**_kwargs,
|
||||
"_bot": bot,
|
||||
@@ -94,10 +97,9 @@ async def effect(bot: Bot, event: GroupMessageEvent, goods_name: str, num: int)
|
||||
"goods_name": goods_name,
|
||||
}
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
return None
|
||||
|
||||
|
||||
def register_use(goods_name: str, func, **kwargs):
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
|
||||
from nonebot.adapters.onebot.v11 import Bot, Message
|
||||
from nonebot.params import Command, CommandArg
|
||||
from typing import Tuple
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.utils import is_number
|
||||
from utils.manager import requests_manager
|
||||
from utils.message_builder import image
|
||||
from models.group_info import GroupInfo
|
||||
@@ -57,37 +58,30 @@ cls_request = on_command("查看所有请求", permission=SUPERUSER, priority=1,
|
||||
|
||||
|
||||
@cls_group.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
gl = await bot.get_group_list(self_id=int(bot.self_id))
|
||||
async def _(bot: Bot):
|
||||
gl = await bot.get_group_list()
|
||||
msg = ["{group_id} {group_name}".format_map(g) for g in gl]
|
||||
msg = "\n".join(msg)
|
||||
msg = f"bot:{bot.self_id}\n| 群号 | 群名 | 共{len(gl)}个群\n" + msg
|
||||
await bot.send_private_msg(
|
||||
self_id=int(bot.self_id),
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=msg,
|
||||
)
|
||||
await cls_group.send(msg)
|
||||
|
||||
|
||||
@cls_friend.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
gl = await bot.get_friend_list(self_id=int(bot.self_id))
|
||||
async def _(bot: Bot):
|
||||
gl = await bot.get_friend_list()
|
||||
msg = ["{user_id} {nickname}".format_map(g) for g in gl]
|
||||
msg = "\n".join(msg)
|
||||
msg = f"| QQ号 | 昵称 | 共{len(gl)}个好友\n" + msg
|
||||
await bot.send_private_msg(
|
||||
self_id=int(bot.self_id),
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=msg,
|
||||
)
|
||||
await cls_friend.send(msg)
|
||||
|
||||
|
||||
@friend_handle.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
id_ = get_message_text(event.json())
|
||||
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
id_ = arg.extract_plain_text().strip()
|
||||
if is_number(id_):
|
||||
id_ = int(id_)
|
||||
if state["_prefix"]["raw_command"][:2] == "同意":
|
||||
if cmd[:2] == "同意":
|
||||
if await requests_manager.approve(bot, id_, "private"):
|
||||
await friend_handle.send("同意好友请求成功..")
|
||||
else:
|
||||
@@ -102,12 +96,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@group_handle.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
id_ = get_message_text(event.json())
|
||||
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
id_ = arg.extract_plain_text().strip()
|
||||
if is_number(id_):
|
||||
id_ = int(id_)
|
||||
if state["_prefix"]["raw_command"][:2] == "同意":
|
||||
rid = await requests_manager.approve(bot, id_, "group")
|
||||
if cmd[:2] == "同意":
|
||||
rid = requests_manager.get_group_id(id_)
|
||||
if rid:
|
||||
await friend_handle.send("同意群聊请求成功..")
|
||||
if await GroupInfo.get_group_info(rid):
|
||||
@@ -121,6 +116,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group_info["member_count"],
|
||||
1
|
||||
)
|
||||
await requests_manager.approve(bot, id_, "group")
|
||||
else:
|
||||
await friend_handle.send("同意群聊请求失败,可能是未找到此id的请求..")
|
||||
else:
|
||||
@@ -133,7 +129,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@cls_request.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
_str = ""
|
||||
for type_ in ["private", "group"]:
|
||||
msg = await requests_manager.show(type_)
|
||||
@@ -147,6 +143,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@clear_request.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
requests_manager.clear()
|
||||
await cls_request.send("已清空所有好友/群聊请求..")
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from configs.path_config import TEMP_PATH
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import scheduler
|
||||
@@ -35,7 +33,7 @@ resources_manager.add_temp_dir(TEMP_PATH)
|
||||
|
||||
|
||||
@clear_data.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
await clear_data.send("开始清理临时数据....")
|
||||
size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
|
||||
await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
|
||||
@@ -47,13 +45,14 @@ def _clear_data() -> float:
|
||||
if dir_.exists():
|
||||
for file in os.listdir(dir_):
|
||||
file = dir_ / file
|
||||
try:
|
||||
if time.time() - os.path.getatime(file) > 300:
|
||||
file_size = os.path.getsize(file)
|
||||
file.unlink()
|
||||
size += file_size
|
||||
except Exception as e:
|
||||
logger.error(f"清理临时数据错误...{type(e)}:{e}")
|
||||
if file.is_file():
|
||||
try:
|
||||
if time.time() - os.path.getatime(file) > 300:
|
||||
file_size = os.path.getsize(file)
|
||||
file.unlink()
|
||||
size += file_size
|
||||
except Exception as e:
|
||||
logger.error(f"清理临时数据错误...{type(e)}:{e}")
|
||||
return float(size)
|
||||
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
|
||||
|
||||
# async def open_remind(group: int, name: str) -> str:
|
||||
# _name = ""
|
||||
# if name == "zwa":
|
||||
# _name = "早晚安"
|
||||
# if name == "dz":
|
||||
# _name = "地震播报"
|
||||
# if name == "hy":
|
||||
# _name = "群欢迎"
|
||||
# if name == "kxcz":
|
||||
# _name = "开箱重置提醒"
|
||||
# if name == "gb":
|
||||
# _name = "广播"
|
||||
# if await GroupRemind.get_status(group, name):
|
||||
# return f"该群已经开启过 {_name} 通知,请勿重复开启!"
|
||||
# if await GroupRemind.set_status(group, name, True):
|
||||
# return f"成功开启 {_name} 通知!0v0"
|
||||
# else:
|
||||
# return f"开启 {_name} 通知失败了..."
|
||||
#
|
||||
#
|
||||
# async def close_remind(group: int, name: str) -> str:
|
||||
# _name = ""
|
||||
# if name == "zwa":
|
||||
# _name = "早晚安"
|
||||
# if name == "dz":
|
||||
# _name = "地震播报"
|
||||
# if name == "hy":
|
||||
# _name = "群欢迎"
|
||||
# if name == "kxcz":
|
||||
# _name = "开箱重置提醒"
|
||||
# if name == "gb":
|
||||
# _name = "广播"
|
||||
# if not await GroupRemind.get_status(group, name):
|
||||
# return f"该群已经取消过 {_name} 通知,请勿重复取消!"
|
||||
# if await GroupRemind.set_status(group, name, False):
|
||||
# return f"成功关闭 {_name} 通知!0v0"
|
||||
# else:
|
||||
# return f"关闭 {_name} 通知失败了..."
|
||||
|
||||
|
||||
# cmd_list = ['总开关', '签到', '发送图片', '色图', '黑白草图', 'coser', '鸡汤/语录', '骂我', '开箱', '鲁迅说', '假消息', '商店系统',
|
||||
# '操作图片', '查询皮肤', '天气', '疫情', '识番', '搜番', '点歌', 'pixiv', 'rss', '方舟一井', '查干员', '骰子娘', '原神一井']
|
||||
#
|
||||
#
|
||||
# def check_group_switch_json(group_id):
|
||||
# if not os.path.exists(DATA_PATH + f'rule/group_switch/'):
|
||||
# os.mkdir(DATA_PATH + f'rule/group_switch/')
|
||||
# if not os.path.exists(DATA_PATH + f'rule/group_switch/{group_id}.json'):
|
||||
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as f:
|
||||
# data = {}
|
||||
# for cmd in cmd_list:
|
||||
# data[cmd] = True
|
||||
# f.write(json.dumps(data, ensure_ascii=False))
|
||||
# else:
|
||||
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'r', encoding='utf8') as f:
|
||||
# try:
|
||||
# data = json.load(f)
|
||||
# except ValueError:
|
||||
# data = {}
|
||||
# if len(data.keys()) - 1 != len(cmd_list):
|
||||
# for cmd in cmd_list:
|
||||
# if cmd not in data.keys():
|
||||
# data[cmd] = True
|
||||
# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as wf:
|
||||
# wf.write(json.dumps(data, ensure_ascii=False))
|
||||
# reload(data)
|
||||
# for file in os.listdir(DATA_PATH + 'group_help'):
|
||||
# os.remove(DATA_PATH + f'group_help/{file}')
|
||||
|
||||
|
||||
def reload(data):
|
||||
static_group_dict = data
|
||||
@@ -1,10 +1,9 @@
|
||||
from nonebot.adapters.onebot.v11 import Message
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from services.db_context import db
|
||||
from utils.utils import get_message_text
|
||||
from nonebot.params import CommandArg
|
||||
from services.log import logger
|
||||
|
||||
__zx_plugin_name__ = "执行sql [Superuser]"
|
||||
@@ -26,8 +25,8 @@ exec_ = on_command("exec", rule=to_me(), permission=SUPERUSER, priority=1, block
|
||||
|
||||
|
||||
@exec_.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
sql = get_message_text(event.json())
|
||||
async def _(arg: Message = CommandArg()):
|
||||
sql = arg.extract_plain_text().strip()
|
||||
async with db.transaction():
|
||||
try:
|
||||
query = db.text(sql)
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GROUP, GroupMessageEvent, Message
|
||||
from nonebot import on_command, on_regex
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GROUP, GroupMessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.utils import is_number
|
||||
from utils.manager import group_manager, plugins2settings_manager
|
||||
from models.group_info import GroupInfo
|
||||
from services.log import logger
|
||||
from configs.config import NICKNAME
|
||||
from nonebot.adapters.cqhttp.exception import ActionFailed
|
||||
from nonebot.adapters.onebot.v11.exception import ActionFailed
|
||||
from nonebot.params import Command, CommandArg
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
__zx_plugin_name__ = "管理群操作 [Superuser]"
|
||||
@@ -65,8 +67,8 @@ group_auth = on_command(
|
||||
|
||||
|
||||
@del_group.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group_id = get_message_text(event.json())
|
||||
async def _(bot: Bot, arg: Message = CommandArg()):
|
||||
group_id = arg.extract_plain_text().strip()
|
||||
if group_id:
|
||||
if is_number(group_id):
|
||||
try:
|
||||
@@ -84,8 +86,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@add_group_level.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
group_id = 0
|
||||
level = 0
|
||||
if not msg:
|
||||
@@ -109,7 +111,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@my_group_level.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
level = group_manager.get_group_level(event.group_id)
|
||||
tmp = ""
|
||||
data = plugins2settings_manager.get_data()
|
||||
@@ -125,17 +127,18 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
|
||||
|
||||
@what_up_group_level.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _():
|
||||
await what_up_group_level.finish(
|
||||
f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限"
|
||||
)
|
||||
|
||||
|
||||
@manager_group_whitelist.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json()).split()
|
||||
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
msg = arg.extract_plain_text().strip()
|
||||
all_group = [
|
||||
g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id))
|
||||
g["group_id"] for g in await bot.get_group_list()
|
||||
]
|
||||
group_list = []
|
||||
for group in msg:
|
||||
@@ -143,20 +146,20 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group_list.append(int(group))
|
||||
if group_list:
|
||||
for group in group_list:
|
||||
if state["_prefix"]["raw_command"] in ["添加群白名单"]:
|
||||
if cmd in ["添加群白名单"]:
|
||||
group_manager.add_group_white_list(group)
|
||||
else:
|
||||
group_manager.delete_group_white_list(group)
|
||||
group_list = [str(x) for x in group_list]
|
||||
await manager_group_whitelist.send(
|
||||
"已成功将 " + "\n".join(group_list) + " " + state["_prefix"]["raw_command"]
|
||||
"已成功将 " + "\n".join(group_list) + " " + cmd
|
||||
)
|
||||
else:
|
||||
await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名")
|
||||
|
||||
|
||||
@show_group_whitelist.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
x = group_manager.get_group_white_list()
|
||||
x = [str(g) for g in x]
|
||||
if x:
|
||||
@@ -166,13 +169,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@group_auth.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json()).split()
|
||||
async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
for group_id in msg:
|
||||
if not is_number(group_id):
|
||||
await group_auth.send(f"{group_id}非纯数字,已跳过该项..")
|
||||
group_id = int(group_id)
|
||||
if state["_prefix"]["raw_command"][:2] == "添加":
|
||||
if cmd[:2] == "添加":
|
||||
if await GroupInfo.get_group_info(group_id):
|
||||
await GroupInfo.set_group_flag(group_id, 1)
|
||||
else:
|
||||
@@ -196,5 +200,5 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
if await GroupInfo.get_group_info(group_id):
|
||||
await GroupInfo.set_group_flag(group_id, 0)
|
||||
await group_auth.send(
|
||||
f'已为 {group_id} {state["_prefix"]["raw_command"][:2]}群认证..'
|
||||
f'已为 {group_id} {cmd[:2]}群认证..'
|
||||
)
|
||||
|
||||
@@ -7,8 +7,9 @@ from utils.manager import (
|
||||
plugins2block_manager,
|
||||
group_manager,
|
||||
)
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from configs.config import Config
|
||||
from services.log import logger
|
||||
from utils.utils import scheduler
|
||||
|
||||
|
||||
__zx_plugin_name__ = "重载插件配置 [Superuser]"
|
||||
@@ -28,6 +29,18 @@ __plugin_cmd__ = [
|
||||
]
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_configs__ = {
|
||||
"AUTO_RELOAD": {
|
||||
"value": False,
|
||||
"help": "自动重载配置文件",
|
||||
"default_value": False
|
||||
},
|
||||
"AUTO_RELOAD_TIME": {
|
||||
"value": 180,
|
||||
"help": "控制自动重载配置文件时长",
|
||||
"default_value": 180
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
reload_plugins_manager = on_command(
|
||||
@@ -36,9 +49,24 @@ reload_plugins_manager = on_command(
|
||||
|
||||
|
||||
@reload_plugins_manager.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
plugins2settings_manager.reload()
|
||||
plugins2cd_manager.reload()
|
||||
plugins2block_manager.reload()
|
||||
group_manager.reload()
|
||||
Config.reload()
|
||||
await reload_plugins_manager.send("重载完成...")
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
'interval',
|
||||
seconds=Config.get_config("reload_setting", "AUTO_RELOAD_TIME", 180),
|
||||
)
|
||||
async def _():
|
||||
if Config.get_config("reload_setting", "AUTO_RELOAD"):
|
||||
plugins2settings_manager.reload()
|
||||
plugins2cd_manager.reload()
|
||||
plugins2block_manager.reload()
|
||||
group_manager.reload()
|
||||
Config.reload()
|
||||
logger.debug("已自动重载所有配置文件...")
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from models.level_user import LevelUser
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, Message
|
||||
from utils.utils import get_message_at, get_message_text, is_number
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from utils.utils import get_message_at, is_number
|
||||
from services.log import logger
|
||||
from utils.message_builder import at
|
||||
from nonebot.params import Command, CommandArg
|
||||
from typing import Tuple
|
||||
|
||||
__zx_plugin_name__ = "用户权限管理 [Superuser]"
|
||||
__plugin_usage__ = """
|
||||
@@ -36,40 +37,49 @@ super_cmd = on_command(
|
||||
|
||||
|
||||
@super_cmd.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
group_id = -1
|
||||
level = 0
|
||||
async def _(
|
||||
bot: Bot,
|
||||
event: MessageEvent,
|
||||
cmd: Tuple[str, ...] = Command(),
|
||||
arg: Message = CommandArg(),
|
||||
):
|
||||
group_id = event.group_id if isinstance(event, GroupMessageEvent) else -1
|
||||
level = None
|
||||
args = arg.extract_plain_text().strip().split()
|
||||
qq = get_message_at(event.json())
|
||||
flag = 2
|
||||
try:
|
||||
args = get_message_text(event.json()).split()
|
||||
qq = get_message_at(event.json())
|
||||
flag = -1
|
||||
if not qq:
|
||||
if len(args) > 2:
|
||||
if is_number(args[0]) and is_number(args[1]) and is_number(args[2]):
|
||||
if qq:
|
||||
qq = qq[0]
|
||||
if cmd[0][:2] == "添加" and args and is_number(args[0]):
|
||||
level = int(args[0])
|
||||
else:
|
||||
if cmd[0][:2] == "添加":
|
||||
if (
|
||||
len(args) > 2
|
||||
and is_number(args[0])
|
||||
and is_number(args[1])
|
||||
and is_number(args[2])
|
||||
):
|
||||
qq = int(args[0])
|
||||
group_id = int(args[1])
|
||||
level = int(args[2])
|
||||
flag = 1
|
||||
else:
|
||||
await super_cmd.finish("所有参数必须是数字!", at_sender=True)
|
||||
else:
|
||||
await super_cmd.finish(
|
||||
"权限参数不完全\n\t格式:添加/删除权限 [at] [level]"
|
||||
"\n\t格式:添加/删除权限 [qq] [group_id] [level]",
|
||||
at_sender=True,
|
||||
)
|
||||
else:
|
||||
if not is_number(args[0]):
|
||||
await super_cmd.finish("所有参数必须是数字!", at_sender=True)
|
||||
level = int(args[0])
|
||||
qq = qq[0]
|
||||
group_id = event.group_id
|
||||
flag = 2
|
||||
if state["_prefix"]["raw_command"][:2] == "添加":
|
||||
if len(args) > 1 and is_number(args[0]) and is_number(args[1]):
|
||||
qq = int(args[0])
|
||||
group_id = int(args[1])
|
||||
flag = 1
|
||||
level = -1 if cmd[0][:2] == "删除" else level
|
||||
if group_id == -1 or not level or not qq:
|
||||
raise IndexError()
|
||||
except IndexError:
|
||||
await super_cmd.finish(__plugin_usage__)
|
||||
try:
|
||||
if cmd[0][:2] == "添加":
|
||||
if await LevelUser.set_level(qq, group_id, level, 1):
|
||||
result = "添加管理成功, 权限: " + str(level)
|
||||
result = f"添加管理成功, 权限: {level}"
|
||||
else:
|
||||
result = "管理已存在, 更新权限: " + str(level)
|
||||
result = f"管理已存在, 更新权限: {level}"
|
||||
else:
|
||||
if await LevelUser.delete_level(qq, event.group_id):
|
||||
result = "删除管理成功!"
|
||||
@@ -80,7 +90,10 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
elif flag == 1:
|
||||
await bot.send_group_msg(
|
||||
group_id=group_id,
|
||||
message=Message(f"{at(qq)}管理员修改了你的权限" f"\n--------\n你当前的权限等级:{level}"),
|
||||
message=Message(
|
||||
f"{at(qq)}管理员修改了你的权限"
|
||||
f"\n--------\n你当前的权限等级:{level if level != -1 else 0}"
|
||||
),
|
||||
)
|
||||
await super_cmd.send("修改成功")
|
||||
except Exception as e:
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_message_text, is_number
|
||||
from utils.utils import is_number
|
||||
from services.log import logger
|
||||
from utils.manager import group_manager
|
||||
from nonebot.params import Command, CommandArg
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
__zx_plugin_name__ = "超级用户被动开关 [Superuser]"
|
||||
@@ -34,8 +35,9 @@ oc_gb = on_command(
|
||||
|
||||
|
||||
@oc_gb.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
|
||||
cmd = cmd[0]
|
||||
group = arg.extract_plain_text().strip()
|
||||
if group:
|
||||
if is_number(group):
|
||||
group = int(group)
|
||||
@@ -44,7 +46,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
break
|
||||
else:
|
||||
await oc_gb.finish("没有加入这个群...", at_sender=True)
|
||||
if state["_prefix"]["raw_command"] == "开启广播通知":
|
||||
if cmd == "开启广播通知":
|
||||
logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播")
|
||||
await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True)
|
||||
else:
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from utils.utils import get_bot
|
||||
from services.log import logger
|
||||
@@ -34,7 +32,7 @@ update_friend_info = on_command(
|
||||
|
||||
|
||||
@update_group_info.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
bot = get_bot()
|
||||
gl = await bot.get_group_list()
|
||||
gl = [g["group_id"] for g in gl]
|
||||
@@ -57,7 +55,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@update_friend_info.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
num = 0
|
||||
rst = ""
|
||||
fl = await get_bot().get_friend_list()
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.rule import to_me
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from .data_source import create_help_image
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
__zx_plugin_name__ = '超级用户帮助 [Superuser]'
|
||||
|
||||
|
||||
superuser_help_image = Path(IMAGE_PATH) / 'superuser_help.png'
|
||||
superuser_help_image = IMAGE_PATH / 'superuser_help.png'
|
||||
|
||||
if superuser_help_image.exists():
|
||||
superuser_help_image.unlink()
|
||||
@@ -23,7 +20,7 @@ super_help = on_command(
|
||||
|
||||
|
||||
@super_help.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
async def _():
|
||||
if not superuser_help_image.exists():
|
||||
await create_help_image()
|
||||
x = image(superuser_help_image)
|
||||
|
||||
@@ -2,8 +2,7 @@ from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from services.log import logger
|
||||
from utils.utils import get_matchers
|
||||
from nonebot.adapters.cqhttp import Bot
|
||||
from pathlib import Path
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot import Driver
|
||||
import asyncio
|
||||
import nonebot
|
||||
@@ -11,9 +10,9 @@ import nonebot
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
background = Path(IMAGE_PATH) / "background" / "0.png"
|
||||
background = IMAGE_PATH / "background" / "0.png"
|
||||
|
||||
superuser_help_image = Path(IMAGE_PATH) / "superuser_help.png"
|
||||
superuser_help_image = IMAGE_PATH / "superuser_help.png"
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
@@ -36,7 +35,7 @@ def _create_help_image():
|
||||
for matcher in _matchers:
|
||||
plugin_name = ""
|
||||
try:
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.module)
|
||||
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
|
||||
_module = _plugin.module
|
||||
try:
|
||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
||||
@@ -68,7 +67,7 @@ def _create_help_image():
|
||||
width = width if width > x else x
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"获取超级用户插件 {matcher.module}: {plugin_name} 设置失败... {type(e)}:{e}"
|
||||
f"获取超级用户插件 {matcher.plugin_name}: {plugin_name} 设置失败... {type(e)}:{e}"
|
||||
)
|
||||
height = len(help_str.split("\n")) * 33
|
||||
width += 500
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.typing import T_State
|
||||
from utils.message_builder import image
|
||||
|
||||
|
||||
@@ -27,7 +25,7 @@ update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, b
|
||||
|
||||
|
||||
@update_info.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
async def _():
|
||||
img = image("update_info.png")
|
||||
if img:
|
||||
await update_info.finish(image("update_info.png"))
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import nonebot
|
||||
from nonebot.adapters.cqhttp import Bot as CQHTTPBot
|
||||
from nonebot.adapters.onebot.v11 import Adapter
|
||||
from services.db_context import init, disconnect
|
||||
|
||||
|
||||
nonebot.init()
|
||||
driver = nonebot.get_driver()
|
||||
driver.register_adapter("cqhttp", CQHTTPBot)
|
||||
driver.register_adapter(Adapter)
|
||||
config = driver.config
|
||||
driver.on_startup(init)
|
||||
driver.on_shutdown(disconnect)
|
||||
|
||||
+25
-21
@@ -1,41 +1,45 @@
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
# 图片路径
|
||||
IMAGE_PATH = Path("resources/img/")
|
||||
# 音频路径
|
||||
VOICE_PATH = Path("resources/voice/")
|
||||
IMAGE_PATH = Path() / "resources" / "image"
|
||||
# 语音路径
|
||||
RECORD_PATH = Path() / "resources" / "record"
|
||||
# 文本路径
|
||||
TEXT_PATH = Path("resources/txt/")
|
||||
TEXT_PATH = Path() / "resources" / "text"
|
||||
# 日志路径
|
||||
LOG_PATH = Path("log/")
|
||||
LOG_PATH = Path() / "log"
|
||||
# 字体路径
|
||||
FONT_PATH = Path("resources/ttf/")
|
||||
FONT_PATH = Path() / "resources" / "font"
|
||||
# 数据路径
|
||||
DATA_PATH = Path("data/")
|
||||
# 临时图片路径
|
||||
TEMP_PATH = Path("resources/img/temp/")
|
||||
DATA_PATH = Path() / "data"
|
||||
# 临时数据路径
|
||||
TEMP_PATH = Path() / "resources" / "temp"
|
||||
|
||||
|
||||
def init_path():
|
||||
global IMAGE_PATH, VOICE_PATH, TEXT_PATH, LOG_PATH, FONT_PATH, DATA_PATH, TEMP_PATH
|
||||
def load_path():
|
||||
old_img_dir = Path() / "resources" / "img"
|
||||
if not IMAGE_PATH.exists() and old_img_dir.exists():
|
||||
os.rename(old_img_dir, IMAGE_PATH)
|
||||
old_voice_dir = Path() / "resources" / "voice"
|
||||
if not RECORD_PATH.exists() and old_voice_dir.exists():
|
||||
os.rename(old_voice_dir, RECORD_PATH)
|
||||
old_ttf_dir = Path() / "resources" / "ttf"
|
||||
if not FONT_PATH.exists() and old_ttf_dir.exists():
|
||||
os.rename(old_ttf_dir, FONT_PATH)
|
||||
old_txt_dir = Path() / "resources" / "txt"
|
||||
if not TEXT_PATH.exists() and old_txt_dir.exists():
|
||||
os.rename(old_txt_dir, TEXT_PATH)
|
||||
IMAGE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
VOICE_PATH.mkdir(parents=True, exist_ok=True)
|
||||
RECORD_PATH.mkdir(parents=True, exist_ok=True)
|
||||
TEXT_PATH.mkdir(parents=True, exist_ok=True)
|
||||
LOG_PATH.mkdir(parents=True, exist_ok=True)
|
||||
FONT_PATH.mkdir(parents=True, exist_ok=True)
|
||||
DATA_PATH.mkdir(parents=True, exist_ok=True)
|
||||
TEMP_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
IMAGE_PATH = str(IMAGE_PATH.absolute()) + '/'
|
||||
VOICE_PATH = str(VOICE_PATH.absolute()) + '/'
|
||||
TEXT_PATH = str(TEXT_PATH.absolute()) + '/'
|
||||
LOG_PATH = str(LOG_PATH.absolute()) + '/'
|
||||
FONT_PATH = str(FONT_PATH.absolute()) + '/'
|
||||
DATA_PATH = str(DATA_PATH.absolute()) + '/'
|
||||
TEMP_PATH = str(TEMP_PATH.absolute()) + '/'
|
||||
|
||||
|
||||
init_path()
|
||||
load_path()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -153,6 +153,20 @@ class ConfigsManager:
|
||||
self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||
)
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
重新加载配置文件
|
||||
"""
|
||||
_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]
|
||||
self.save()
|
||||
|
||||
def get_admin_level_data(self):
|
||||
"""
|
||||
获取管理插件等级
|
||||
|
||||
@@ -131,8 +131,10 @@ class GroupInfoUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_all_group(cls, user_qq: int) -> List[int]:
|
||||
"""
|
||||
获取该用户所在的所有群聊
|
||||
:param user_qq: 用户qq
|
||||
说明:
|
||||
获取该用户所在的所有群聊
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
|
||||
if query:
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
from nonebot import on_regex
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
from pathlib import Path
|
||||
|
||||
@@ -29,7 +27,7 @@ about = on_regex("^关于$", priority=5, block=True, rule=to_me())
|
||||
|
||||
|
||||
@about.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
ver_file = Path() / '__version__'
|
||||
version = None
|
||||
if ver_file.exists():
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import random
|
||||
from nonebot import on_keyword
|
||||
import os
|
||||
from utils.message_builder import image
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from nonebot import on_command
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.adapters.cqhttp.permission import GROUP
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from utils.utils import FreqLimiter
|
||||
from configs.config import NICKNAME
|
||||
import random
|
||||
from nonebot import on_keyword
|
||||
import os
|
||||
|
||||
|
||||
__zx_plugin_name__ = "基本设置 [Hidden]"
|
||||
@@ -25,12 +24,12 @@ config_play_game = on_keyword({"打游戏"}, permission=GROUP, priority=1, block
|
||||
|
||||
|
||||
@config_play_game.handle()
|
||||
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
|
||||
async def _(event: GroupMessageEvent):
|
||||
if not _flmt.check(event.group_id):
|
||||
return
|
||||
_flmt.start_cd(event.group_id)
|
||||
await config_play_game.finish(
|
||||
image(random.choice(os.listdir(IMAGE_PATH + "dayouxi/")), "dayouxi")
|
||||
image(random.choice(os.listdir(IMAGE_PATH / "dayouxi")), "dayouxi")
|
||||
)
|
||||
|
||||
|
||||
@@ -40,7 +39,7 @@ self_introduction = on_command(
|
||||
|
||||
|
||||
@self_introduction.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
if NICKNAME.find('真寻') != -1:
|
||||
result = (
|
||||
"我叫绪山真寻\n"
|
||||
@@ -57,6 +56,6 @@ my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True)
|
||||
|
||||
|
||||
@my_wife.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
await my_wife.finish(image("laopo.jpg", "other"))
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
from nonebot import on_message
|
||||
from nonebot.adapters.cqhttp import (
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
Bot,
|
||||
GroupMessageEvent,
|
||||
Message,
|
||||
MessageEvent,
|
||||
)
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
|
||||
from models.friend_user import FriendUser
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from services.log import logger
|
||||
from utils.utils import get_message_text, get_message_img
|
||||
from utils.utils import get_message_img, get_message_text
|
||||
from .data_source import get_chat_result, hello, no_result
|
||||
from configs.config import NICKNAME, Config
|
||||
|
||||
@@ -36,14 +34,14 @@ __plugin_configs__ = {
|
||||
},
|
||||
}
|
||||
Config.add_plugin_config(
|
||||
"alapi", "ALAPI_TOKEN", None, help_="在https://admin.alapi.cn/user/login登录后获取token"
|
||||
"alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token"
|
||||
)
|
||||
|
||||
ai = on_message(rule=to_me(), priority=8)
|
||||
|
||||
|
||||
@ai.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
msg = get_message_text(event.json())
|
||||
img = get_message_img(event.json())
|
||||
if "CQ:xml" in str(event.get_message()):
|
||||
@@ -69,7 +67,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
nickname = await FriendUser.get_friend_nickname(event.user_id)
|
||||
if not nickname:
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
nickname = event.sender.card or event.sender.nickname
|
||||
else:
|
||||
nickname = event.sender.nickname
|
||||
result = await get_chat_result(msg, img, event.user_id, nickname)
|
||||
|
||||
@@ -20,7 +20,7 @@ check_url = "https://v2.alapi.cn/api/censor/text"
|
||||
|
||||
index = 0
|
||||
|
||||
anime_data = json.load(open(DATA_PATH + "anime.json", "r", encoding="utf8"))
|
||||
anime_data = json.load(open(DATA_PATH / "anime.json", "r", encoding="utf8"))
|
||||
|
||||
|
||||
async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) -> str:
|
||||
@@ -57,7 +57,7 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str)
|
||||
if random.random() < 0.2:
|
||||
if nickname.find("大人") == -1:
|
||||
nickname += "大~人~"
|
||||
rst = rst.replace("小主人", nickname).replace("小朋友", nickname)
|
||||
rst = str(rst).replace("小主人", nickname).replace("小朋友", nickname)
|
||||
ai_message_manager.add_result(user_id, rst)
|
||||
return rst
|
||||
|
||||
@@ -139,7 +139,7 @@ async def xie_ai(text: str) -> str:
|
||||
content = content.replace("{br}", "\n")
|
||||
if "提示" in content:
|
||||
content = content[: content.find("提示")]
|
||||
if "淘宝" in content:
|
||||
if "淘宝" in content or "taobao.com" in content:
|
||||
return ""
|
||||
while True:
|
||||
r = re.search("{face:(.*)}", content)
|
||||
@@ -170,7 +170,7 @@ def hello() -> str:
|
||||
"呼呼,叫俺干嘛",
|
||||
)
|
||||
)
|
||||
img = random.choice(os.listdir(IMAGE_PATH + "zai/"))
|
||||
img = random.choice(os.listdir(IMAGE_PATH / "zai"))
|
||||
if img[-4:] == ".gif":
|
||||
result += image(img, "zai")
|
||||
else:
|
||||
@@ -193,7 +193,7 @@ def no_result() -> str:
|
||||
"我!不!知!道!",
|
||||
]
|
||||
)
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH + "noresult/")), "noresult")
|
||||
+ image(random.choice(os.listdir(IMAGE_PATH / "noresult")), "noresult")
|
||||
)
|
||||
|
||||
|
||||
|
||||
Executable → Regular
+49
-49
@@ -1,49 +1,49 @@
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.message_builder import image
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional
|
||||
from configs.config import Config
|
||||
from utils.http_utils import AsyncHttpx
|
||||
|
||||
|
||||
async def get_data(url: str, params: Optional[dict] = None) -> "Union[dict, str], int":
|
||||
"""
|
||||
获取ALAPI数据
|
||||
:param url: 请求链接
|
||||
:param params: 参数
|
||||
"""
|
||||
if not params:
|
||||
params = {}
|
||||
params["token"] = Config.get_config("alapi", "ALAPI_TOKEN")
|
||||
try:
|
||||
data = (await AsyncHttpx.get(url, params=params, timeout=5)).json()
|
||||
if data["code"] == 200:
|
||||
if not data["data"]:
|
||||
return "没有搜索到...", 997
|
||||
return data, 200
|
||||
else:
|
||||
return f'发生了错误...code:{data["code"]}', 999
|
||||
except TimeoutError:
|
||||
return "超时了....", 998
|
||||
|
||||
|
||||
def gen_wbtop_pic(data: dict) -> MessageSegment:
|
||||
"""
|
||||
生成微博热搜图片
|
||||
:param data: 微博热搜数据
|
||||
"""
|
||||
bk = BuildImage(700, 32 * 50 + 280, 700, 32, color="#797979")
|
||||
wbtop_bk = BuildImage(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
|
||||
bk.paste(wbtop_bk)
|
||||
text_bk = BuildImage(700, 32 * 50, 700, 32, color="#797979")
|
||||
for i, data in enumerate(data):
|
||||
title = f"{i+1}. {data['hot_word']}"
|
||||
hot = data["hot_word_num"]
|
||||
img = BuildImage(700, 30, font_size=20)
|
||||
w, h = img.getsize(title)
|
||||
img.text((10, int((30 - h) / 2)), title)
|
||||
img.text((580, int((30 - h) / 2)), hot)
|
||||
text_bk.paste(img)
|
||||
bk.paste(text_bk, (0, 280))
|
||||
return image(b64=bk.pic2bs4())
|
||||
from nonebot.adapters.onebot.v11 import MessageSegment
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.message_builder import image
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional, Tuple, Union
|
||||
from configs.config import Config
|
||||
from utils.http_utils import AsyncHttpx
|
||||
|
||||
|
||||
async def get_data(url: str, params: Optional[dict] = None) -> Tuple[Union[dict, str], int]:
|
||||
"""
|
||||
获取ALAPI数据
|
||||
:param url: 请求链接
|
||||
:param params: 参数
|
||||
"""
|
||||
if not params:
|
||||
params = {}
|
||||
params["token"] = Config.get_config("alapi", "ALAPI_TOKEN")
|
||||
try:
|
||||
data = (await AsyncHttpx.get(url, params=params, timeout=5)).json()
|
||||
if data["code"] == 200:
|
||||
if not data["data"]:
|
||||
return "没有搜索到...", 997
|
||||
return data, 200
|
||||
else:
|
||||
return f'发生了错误...code:{data["code"]}', 999
|
||||
except TimeoutError:
|
||||
return "超时了....", 998
|
||||
|
||||
|
||||
def gen_wbtop_pic(data: dict) -> MessageSegment:
|
||||
"""
|
||||
生成微博热搜图片
|
||||
:param data: 微博热搜数据
|
||||
"""
|
||||
bk = BuildImage(700, 32 * 50 + 280, 700, 32, color="#797979")
|
||||
wbtop_bk = BuildImage(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
|
||||
bk.paste(wbtop_bk)
|
||||
text_bk = BuildImage(700, 32 * 50, 700, 32, color="#797979")
|
||||
for i, data in enumerate(data):
|
||||
title = f"{i+1}. {data['hot_word']}"
|
||||
hot = data["hot_word_num"]
|
||||
img = BuildImage(700, 30, font_size=20)
|
||||
w, h = img.getsize(title)
|
||||
img.text((10, int((30 - h) / 2)), title)
|
||||
img.text((580, int((30 - h) / 2)), hot)
|
||||
text_bk.paste(img)
|
||||
bk.paste(text_bk, (0, 280))
|
||||
return image(b64=bk.pic2bs4())
|
||||
@@ -1,7 +1,6 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from .data_source import get_data
|
||||
from nonebot import on_regex
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from ._data_source import get_data
|
||||
from services.log import logger
|
||||
|
||||
__zx_plugin_name__ = "网易云热评"
|
||||
@@ -23,8 +22,8 @@ __plugin_settings__ = {
|
||||
}
|
||||
|
||||
|
||||
comments_163 = on_command(
|
||||
"网易云热评", aliases={"网易云评论", "到点了", "12点了"}, priority=5, block=True
|
||||
comments_163 = on_regex(
|
||||
"^(网易云热评|网易云评论|到点了|12点了)$", priority=5, block=True
|
||||
)
|
||||
|
||||
|
||||
@@ -32,7 +31,7 @@ comments_163_url = "https://v2.alapi.cn/api/comment"
|
||||
|
||||
|
||||
@comments_163.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(event: MessageEvent):
|
||||
data, code = await get_data(comments_163_url)
|
||||
if code != 200:
|
||||
await comments_163.finish(data, at_sender=True)
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent
|
||||
from utils.message_builder import image
|
||||
from utils.utils import get_message_text
|
||||
from .data_source import get_data
|
||||
from nonebot.params import CommandArg
|
||||
from ._data_source import get_data
|
||||
from services.log import logger
|
||||
|
||||
__zx_plugin_name__ = "b封面"
|
||||
@@ -32,8 +31,8 @@ cover_url = "https://v2.alapi.cn/api/bilibili/cover"
|
||||
|
||||
|
||||
@cover.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
params = {"c": msg}
|
||||
data, code = await get_data(cover_url, params)
|
||||
if code != 200:
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
from nonebot import on_command
|
||||
from nonebot import on_regex
|
||||
from services.log import logger
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from configs.config import Config
|
||||
from .data_source import get_data
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from ._data_source import get_data
|
||||
|
||||
|
||||
__zx_plugin_name__ = "鸡汤"
|
||||
@@ -28,11 +25,11 @@ __plugin_settings__ = {
|
||||
url = "https://v2.alapi.cn/api/soul"
|
||||
|
||||
|
||||
jitang = on_command("鸡汤", aliases={"毒鸡汤"}, priority=5, block=True)
|
||||
jitang = on_regex("^毒?鸡汤$", priority=5, block=True)
|
||||
|
||||
|
||||
@jitang.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(event: MessageEvent):
|
||||
try:
|
||||
data, code = await get_data(url)
|
||||
if code != 200:
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
|
||||
from services.log import logger
|
||||
from .data_source import get_data
|
||||
from ._data_source import get_data
|
||||
|
||||
__zx_plugin_name__ = "古诗"
|
||||
__plugin_usage__ = """usage:
|
||||
@@ -27,7 +26,7 @@ poetry_url = "https://v2.alapi.cn/api/shici"
|
||||
|
||||
|
||||
@poetry.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(event: MessageEvent):
|
||||
data, code = await get_data(poetry_url)
|
||||
if code != 200:
|
||||
await poetry.finish(data, at_sender=True)
|
||||
|
||||
+16
-17
@@ -1,11 +1,10 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
|
||||
from nonebot.params import CommandArg
|
||||
from services.log import logger
|
||||
from .data_source import get_data, gen_wbtop_pic
|
||||
from utils.utils import get_message_text, is_number
|
||||
from ._data_source import get_data, gen_wbtop_pic
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from utils.http_utils import AsyncPlaywright
|
||||
import asyncio
|
||||
|
||||
@@ -38,9 +37,9 @@ wbtop_data = []
|
||||
|
||||
|
||||
@wbtop.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
global wbtop_data
|
||||
msg = get_message_text(event.json())
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if not wbtop_data or not msg:
|
||||
data, code = await get_data(wbtop_url)
|
||||
if code != 200:
|
||||
@@ -57,15 +56,15 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
)
|
||||
if is_number(msg) and 0 < int(msg) <= 50:
|
||||
url = wbtop_data[int(msg) - 1]["url"]
|
||||
try:
|
||||
await wbtop.send("开始截取数据...")
|
||||
img = await AsyncPlaywright.screenshot(
|
||||
url,
|
||||
f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png",
|
||||
"#pl_feedlist_index",
|
||||
sleep=5
|
||||
)
|
||||
await wbtop.send("开始截取数据...")
|
||||
img = await AsyncPlaywright.screenshot(
|
||||
url,
|
||||
f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png",
|
||||
"#pl_feedlist_index",
|
||||
wait_time=5
|
||||
)
|
||||
if img:
|
||||
await wbtop.send(img)
|
||||
except Exception as e:
|
||||
logger.error(f"微博热搜截图出错... {type(e)}: {e}")
|
||||
else:
|
||||
await wbtop.send("发生了一些错误.....")
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
|
||||
from .data_source import (
|
||||
add_live_sub,
|
||||
delete_sub,
|
||||
@@ -13,10 +13,11 @@ from .data_source import (
|
||||
)
|
||||
from models.level_user import LevelUser
|
||||
from configs.config import Config
|
||||
from utils.utils import get_message_text, is_number, scheduler, get_bot
|
||||
from utils.utils import is_number, scheduler, get_bot
|
||||
from typing import Optional
|
||||
from services.log import logger
|
||||
from nonebot import Driver
|
||||
from nonebot.params import CommandArg, ArgStr
|
||||
import nonebot
|
||||
|
||||
__zx_plugin_name__ = "B站订阅"
|
||||
@@ -68,18 +69,9 @@ async def _():
|
||||
sub_manager = SubManager()
|
||||
|
||||
|
||||
@add_sub.args_parser
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
season_data = state["season_data"]
|
||||
msg = get_message_text(event.json())
|
||||
if not is_number(msg) or int(msg) < 1 or int(msg) > len(season_data):
|
||||
await add_sub.reject("Id必须为数字且在范围内!请重新输入...")
|
||||
state["id"] = season_data[int(msg) - 1]["media_id"]
|
||||
|
||||
|
||||
@add_sub.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json()).split()
|
||||
async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
if len(msg) < 2:
|
||||
await add_sub.finish("参数不完全,请查看订阅帮助...")
|
||||
sub_type = msg[0]
|
||||
@@ -120,11 +112,22 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
state["id"] = int(id_)
|
||||
|
||||
|
||||
@add_sub.got("sub_type")
|
||||
@add_sub.got("sub_user")
|
||||
@add_sub.got("id")
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
sub_type = state["sub_type"]
|
||||
sub_user = state["sub_user"]
|
||||
id_ = state["id"]
|
||||
async def _(
|
||||
event: MessageEvent,
|
||||
state: T_State,
|
||||
id_: str = ArgStr("id"),
|
||||
sub_type: str = ArgStr("sub_type"),
|
||||
sub_user: str = ArgStr("sub_user"),
|
||||
):
|
||||
if sub_type in ["season", "动漫", "番剧"] and state.get("season_data"):
|
||||
season_data = state["season_data"]
|
||||
if not is_number(id_) or int(id_) < 1 or int(id_) > len(season_data):
|
||||
await add_sub.reject_arg("id", "Id必须为数字且在范围内!请重新输入...")
|
||||
id_ = season_data[int(id_) - 1]["media_id"]
|
||||
id_ = int(id_)
|
||||
if sub_type in ["主播", "直播"]:
|
||||
await add_sub.send(await add_live_sub(id_, sub_user))
|
||||
elif sub_type.lower() in ["up", "用户"]:
|
||||
@@ -141,8 +144,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@del_sub.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
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)
|
||||
id_ = (
|
||||
@@ -162,7 +165,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@show_sub_info.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(event: MessageEvent):
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
id_ = f"{event.group_id}"
|
||||
else:
|
||||
@@ -208,7 +211,7 @@ async def _():
|
||||
await sub_manager.reload_sub_data()
|
||||
sub = await sub_manager.random_sub_data()
|
||||
if sub:
|
||||
logger.info(f"Bilibili订阅开始检测:{sub.sub_id}")
|
||||
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":
|
||||
|
||||
@@ -8,7 +8,6 @@ from utils.message_builder import image
|
||||
from bilibili_api.user import User
|
||||
from bilibili_api import user
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from datetime import datetime
|
||||
from utils.browser import get_browser
|
||||
@@ -20,7 +19,7 @@ import random
|
||||
|
||||
bilibili_search_url = "https://api.bilibili.com/x/web-interface/search/all/v2"
|
||||
|
||||
dynamic_path = Path(IMAGE_PATH) / "bilibili_sub" / "dynamic"
|
||||
dynamic_path = IMAGE_PATH / "bilibili_sub" / "dynamic"
|
||||
dynamic_path.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
|
||||
@@ -193,7 +192,6 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
||||
获取订阅状态
|
||||
:param id_: 订阅 id
|
||||
:param sub_type: 订阅类型
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
if sub_type == "live":
|
||||
@@ -203,7 +201,7 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
||||
elif sub_type == "season":
|
||||
return await _get_season_status(id_)
|
||||
except ResponseCodeException:
|
||||
return "获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||
# except Exception as e:
|
||||
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
|
||||
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
|
||||
@@ -313,28 +311,32 @@ async def get_user_dynamic(
|
||||
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
||||
if local_user.dynamic_upload_time < dynamic_upload_time:
|
||||
page = await browser.new_page()
|
||||
await page.goto(
|
||||
f"https://space.bilibili.com/{local_user.uid}/dynamic",
|
||||
wait_until="networkidle",
|
||||
timeout=10000,
|
||||
)
|
||||
await page.set_viewport_size({"width": 2560, "height": 1080})
|
||||
# 删除置顶
|
||||
await page.evaluate(
|
||||
try:
|
||||
await page.goto(
|
||||
f"https://space.bilibili.com/{local_user.uid}/dynamic",
|
||||
wait_until="networkidle",
|
||||
timeout=10000,
|
||||
)
|
||||
await page.set_viewport_size({"width": 2560, "height": 1080})
|
||||
# 删除置顶
|
||||
await page.evaluate(
|
||||
"""
|
||||
xs = document.getElementsByClassName('first-card-with-title');
|
||||
for (x of xs) {
|
||||
x.remove();
|
||||
}
|
||||
"""
|
||||
xs = document.getElementsByClassName('first-card-with-title');
|
||||
for (x of xs) {
|
||||
x.remove();
|
||||
}
|
||||
"""
|
||||
)
|
||||
card = await page.query_selector(".card")
|
||||
# 截图并保存
|
||||
await card.screenshot(
|
||||
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||
timeout=100000,
|
||||
)
|
||||
await page.close()
|
||||
)
|
||||
card = await page.query_selector(".card")
|
||||
# 截图并保存
|
||||
await card.screenshot(
|
||||
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||
timeout=100000,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
|
||||
finally:
|
||||
await page.close()
|
||||
return (
|
||||
image(
|
||||
f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from pathlib import Path
|
||||
from bilibili_api import user
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
BORDER_PATH = Path(IMAGE_PATH) / "border"
|
||||
BORDER_PATH = IMAGE_PATH / "border"
|
||||
BORDER_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
|
||||
+27
-36
@@ -1,12 +1,12 @@
|
||||
from nonebot import on_command
|
||||
from .data_source import get_bt_info
|
||||
from services.log import logger
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.adapters.cqhttp import PrivateMessageEvent
|
||||
from utils.utils import get_message_text
|
||||
from nonebot.adapters.cqhttp.permission import PRIVATE
|
||||
from nonebot.adapters.onebot.v11 import PrivateMessageEvent, Message
|
||||
from nonebot.adapters.onebot.v11.permission import PRIVATE
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from utils.utils import is_number
|
||||
from nonebot.params import CommandArg, ArgStr
|
||||
from nonebot.typing import T_State
|
||||
|
||||
__zx_plugin_name__ = "磁力搜索"
|
||||
__plugin_usage__ = """
|
||||
@@ -28,9 +28,7 @@ __plugin_settings__ = {
|
||||
"limit_superuser": False,
|
||||
"cmd": ["bt", "磁力搜索", "Bt", "BT"],
|
||||
}
|
||||
__plugin_block_limit__ = {
|
||||
"rst": "您有bt任务正在进行,请等待结束."
|
||||
}
|
||||
__plugin_block_limit__ = {"rst": "您有bt任务正在进行,请等待结束."}
|
||||
__plugin_configs__ = {
|
||||
"BT_MAX_NUM": {
|
||||
"value": 10,
|
||||
@@ -43,44 +41,37 @@ __plugin_configs__ = {
|
||||
bt = on_command("bt", permission=PRIVATE, priority=5, block=True)
|
||||
|
||||
|
||||
@bt.args_parser
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
if str(event.get_message()) in ["取消", "算了"]:
|
||||
await bt.finish("已取消操作..", at_sender=True)
|
||||
msg = get_message_text(event.json())
|
||||
if not msg:
|
||||
await bt.reject("你想搜索什么呢?", at_sender=True)
|
||||
state["keyword"] = msg
|
||||
state["page"] = "1"
|
||||
|
||||
|
||||
@bt.handle()
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
mp = get_message_text(event.json())
|
||||
if not mp:
|
||||
return
|
||||
mp = mp.split()
|
||||
if len(mp) == 2:
|
||||
state["keyword"] = mp[0]
|
||||
state["page"] = mp[1]
|
||||
async def _(state: T_State, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip().split()
|
||||
if msg:
|
||||
keyword = None
|
||||
page = 1
|
||||
if n := len(msg):
|
||||
keyword = msg[0]
|
||||
if n > 1 and is_number(msg[1]) and int(msg[1]) > 0:
|
||||
page = int(msg[1])
|
||||
state["keyword"] = keyword
|
||||
state["page"] = page
|
||||
else:
|
||||
state["keyword"] = mp[0]
|
||||
state["page"] = "1"
|
||||
state["page"] = 1
|
||||
|
||||
|
||||
@bt.got("keyword", prompt="虚空磁力?查什么GKD")
|
||||
async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
|
||||
keyword = state["keyword"]
|
||||
page = state["page"]
|
||||
await bt.send("开始搜索....", at_sender=True)
|
||||
@bt.got("keyword", prompt="请输入要查询的内容!")
|
||||
async def _(
|
||||
event: PrivateMessageEvent,
|
||||
state: T_State,
|
||||
keyword: str = ArgStr("keyword"),
|
||||
page: str = ArgStr("page"),
|
||||
):
|
||||
send_flag = False
|
||||
try:
|
||||
async for title, itype, create_time, file_size, link in get_bt_info(
|
||||
async for title, type_, create_time, file_size, link in get_bt_info(
|
||||
keyword, page
|
||||
):
|
||||
await bt.send(
|
||||
f"标题:{title}\n"
|
||||
f"类型:{itype}\n"
|
||||
f"类型:{type_}\n"
|
||||
f"创建时间:{create_time}\n"
|
||||
f"文件大小:{file_size}\n"
|
||||
f"种子:{link}"
|
||||
|
||||
@@ -9,10 +9,10 @@ if platform.system() == "Windows":
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
|
||||
|
||||
url = "http://www.eclzz.world"
|
||||
url = "http://www.eclzz.mobi"
|
||||
|
||||
|
||||
async def get_bt_info(keyword: str, page: str):
|
||||
async def get_bt_info(keyword: str, page: int):
|
||||
"""
|
||||
获取资源信息
|
||||
:param keyword: 关键词
|
||||
@@ -34,11 +34,11 @@ async def get_bt_info(keyword: str, page: str):
|
||||
.strip()
|
||||
)
|
||||
spans = divs[2].find_all("span")
|
||||
itype = spans[0].text
|
||||
type_ = spans[0].text
|
||||
create_time = spans[1].find("b").text
|
||||
file_size = spans[2].find("b").text
|
||||
link = await get_download_link(divs[0].find("a")["href"])
|
||||
yield title, itype, create_time, file_size, link
|
||||
yield title, type_, create_time, file_size, link
|
||||
|
||||
|
||||
async def get_download_link(_url: str) -> str:
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
from .music_163 import get_song_id, get_song_info
|
||||
from nonebot.adapters.cqhttp import Bot, Event, GroupMessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from services.log import logger
|
||||
from nonebot import on_command
|
||||
|
||||
|
||||
__zx_plugin_name__ = "点歌"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
在线点歌
|
||||
指令:
|
||||
点歌 [歌名]
|
||||
""".strip()
|
||||
__plugin_des__ = "为你点播了一首曾经的歌"
|
||||
__plugin_cmd__ = ["点歌 [歌名]"]
|
||||
__plugin_type__ = ("一些工具",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["点歌"],
|
||||
}
|
||||
|
||||
|
||||
music = on_command("点歌", priority=5, block=True)
|
||||
|
||||
|
||||
@music.handle()
|
||||
async def handle_first_receive(bot: Bot, event: Event, state: T_State):
|
||||
args = str(event.get_message()).strip()
|
||||
if args:
|
||||
state["song_name"] = args
|
||||
|
||||
|
||||
@music.got("song_name", prompt="歌名是?")
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
song = state["song_name"]
|
||||
song_id = await get_song_id(song)
|
||||
if not song_id:
|
||||
await music.finish("没有找到这首歌!", at_sender=True)
|
||||
for _ in range(3):
|
||||
song_content = [{"type": "music", "data": {"type": 163, "id": song_id}}]
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 点歌 :{song}"
|
||||
)
|
||||
await music.finish(song_content)
|
||||
else:
|
||||
await music.finish("网易云繁忙...")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from nonebot import on_command
|
||||
from .data_source import Check
|
||||
from nonebot.adapters.cqhttp import Bot, Event
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.message_builder import image
|
||||
@@ -29,5 +27,5 @@ check_ = on_command(
|
||||
|
||||
|
||||
@check_.handle()
|
||||
async def _(bot: Bot, event: Event, state: T_State):
|
||||
async def _():
|
||||
await check_.send(image(b64=await check.show()))
|
||||
|
||||
@@ -4,7 +4,6 @@ from datetime import datetime
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from pathlib import Path
|
||||
import asyncio
|
||||
from services.log import logger
|
||||
|
||||
@@ -73,6 +72,6 @@ class Check:
|
||||
A.transparent(1)
|
||||
A.text((10, 10), rst)
|
||||
_x = max(width, height)
|
||||
bk = BuildImage(_x + 100, _x + 100, background=Path(IMAGE_PATH) / "background" / "check" / "0.jpg")
|
||||
bk = BuildImage(_x + 100, _x + 100, background=IMAGE_PATH / "background" / "check" / "0.jpg")
|
||||
bk.paste(A, alpha=True, center_type='center')
|
||||
return bk.pic2bs4()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot import on_command
|
||||
from .data_source import check_update, get_latest_version_data
|
||||
@@ -8,6 +7,7 @@ from utils.utils import scheduler, get_bot
|
||||
from pathlib import Path
|
||||
from configs.config import Config
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.params import ArgStr
|
||||
import platform
|
||||
import os
|
||||
|
||||
@@ -45,7 +45,7 @@ restart = on_command(
|
||||
|
||||
|
||||
@update_zhenxun.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _(bot: Bot):
|
||||
try:
|
||||
code, error = await check_update(bot)
|
||||
if error:
|
||||
@@ -67,14 +67,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
|
||||
|
||||
@restart.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
async def _():
|
||||
if str(platform.system()).lower() == "windows":
|
||||
await restart.finish("暂无windows重启脚本...")
|
||||
|
||||
|
||||
@restart.got("flag", prompt="确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)")
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
flag = state["flag"]
|
||||
async def _(flag: str = ArgStr("flag")):
|
||||
if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
|
||||
await restart.send("开始重启真寻..请稍等...")
|
||||
open("is_restart", "w")
|
||||
@@ -107,8 +106,7 @@ async def _():
|
||||
await bot.send_private_msg(
|
||||
user_id=int(list(bot.config.superusers)[0]),
|
||||
message=f"检测到真寻版本更新\n"
|
||||
f"当前版本:{_version},最新版本:{latest_version}\n"
|
||||
f"尝试自动更新...",
|
||||
f"当前版本:{_version},最新版本:{latest_version}",
|
||||
)
|
||||
# try:
|
||||
# code = await check_update(bot)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from nonebot.adapters.cqhttp import Bot, Message
|
||||
from nonebot.adapters.onebot.v11 import Bot, Message
|
||||
from utils.image_utils import BuildImage
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from nonebot import on_command
|
||||
from nonebot import on_regex
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
|
||||
from utils.message_builder import image
|
||||
from services.log import logger
|
||||
from utils.manager import withdraw_message_manager
|
||||
@@ -31,12 +31,10 @@ __plugin_configs__ = {
|
||||
},
|
||||
}
|
||||
|
||||
coser = on_command(
|
||||
"cos", aliases={"coser", "括丝", "COS", "Cos", "cOS", "coS"}, priority=5, block=True
|
||||
)
|
||||
coser = on_regex("^(cos|COS|coser|括丝)$", priority=5, block=True)
|
||||
|
||||
|
||||
url = "http://iw233.cn/API/cos.php"
|
||||
url = "https://api.iyk0.com/cos"
|
||||
|
||||
|
||||
@coser.handle()
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import get_message_text, is_number, get_message_img
|
||||
from utils.utils import is_number, get_message_img
|
||||
from utils.message_builder import image
|
||||
from utils.message_builder import text as _text
|
||||
from services.log import logger
|
||||
from utils.message_builder import at
|
||||
from nonebot.params import CommandArg
|
||||
|
||||
|
||||
__zx_plugin_name__ = "联系管理员"
|
||||
@@ -58,10 +58,8 @@ reply = on_command("/t", priority=1, permission=SUPERUSER, block=True)
|
||||
|
||||
|
||||
@dialogue.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
uid = event.user_id
|
||||
coffee = int(list(bot.config.superusers)[0])
|
||||
text = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
text = arg.extract_plain_text().strip()
|
||||
img_msg = _text("")
|
||||
for img in get_message_img(event.json()):
|
||||
img_msg += image(img)
|
||||
@@ -76,17 +74,18 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
group_name = (await bot.get_group_info(group_id=event.group_id))[
|
||||
"group_name"
|
||||
]
|
||||
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
await bot.send_private_msg(
|
||||
user_id=coffee,
|
||||
message=_text(
|
||||
f"*****一份交流报告*****\n"
|
||||
f"昵称:{nickname}({uid})\n"
|
||||
f"群聊:{group_name}({group_id})\n"
|
||||
f"消息:{text}"
|
||||
nickname = event.sender.card or event.sender.nickname
|
||||
for coffee in bot.config.superusers:
|
||||
await bot.send_private_msg(
|
||||
user_id=int(coffee),
|
||||
message=_text(
|
||||
f"*****一份交流报告*****\n"
|
||||
f"昵称:{nickname}({event.user_id})\n"
|
||||
f"群聊:{group_name}({group_id})\n"
|
||||
f"消息:{text}"
|
||||
)
|
||||
+ img_msg,
|
||||
)
|
||||
+ img_msg,
|
||||
)
|
||||
await dialogue.send(
|
||||
_text(f"您的话已发送至管理员!\n======\n{text}") + img_msg, at_sender=True
|
||||
)
|
||||
@@ -99,12 +98,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
"msg": _text(text) + img_msg,
|
||||
}
|
||||
# print(dialogue_data)
|
||||
logger.info(f"Q{uid}@群{group_id} 联系管理员:{coffee} text:{text}")
|
||||
logger.info(f"Q{event.user_id}@群{group_id} 联系管理员:text:{text}")
|
||||
|
||||
|
||||
@reply.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if not msg:
|
||||
result = "*****待回复消息总览*****\n"
|
||||
for key in dialogue_data.keys():
|
||||
|
||||
Executable → Regular
+171
-391
@@ -1,53 +1,46 @@
|
||||
from nonebot import on_regex, on_keyword
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_State
|
||||
from .genshin_handle import (
|
||||
genshin_draw,
|
||||
update_genshin_info,
|
||||
reset_count,
|
||||
reload_genshin_pool,
|
||||
)
|
||||
from .prts_handle import update_prts_info, prts_draw, reload_prts_pool
|
||||
from .pretty_handle import update_pretty_info, pretty_draw, reload_pretty_pool
|
||||
from .guardian_handle import update_guardian_info, guardian_draw
|
||||
from .pcr_handle import update_pcr_info, pcr_draw
|
||||
from .azur_handle import update_azur_info, azur_draw
|
||||
from .fgo_handle import update_fgo_info, fgo_draw
|
||||
from .onmyoji_handle import update_onmyoji_info, onmyoji_draw
|
||||
from .update_game_info import update_info
|
||||
from .util import is_number, check_num
|
||||
from .rule import is_switch
|
||||
from .config import (
|
||||
PRTS_FLAG,
|
||||
PRETTY_FLAG,
|
||||
GUARDIAN_FLAG,
|
||||
GENSHIN_FLAG,
|
||||
PCR_FLAG,
|
||||
AZUR_FLAG,
|
||||
FGO_FLAG,
|
||||
ONMYOJI_FLAG,
|
||||
)
|
||||
from .async_update_game_info import async_update_game
|
||||
import re
|
||||
import asyncio
|
||||
from utils.utils import scheduler
|
||||
from services.log import logger
|
||||
import traceback
|
||||
from cn2an import cn2an
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Set, Tuple
|
||||
|
||||
import nonebot
|
||||
from nonebot import on_regex, on_keyword
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||
from nonebot.log import logger
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.params import RegexGroup
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.typing import T_Handler
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
|
||||
from .handles.base_handle import BaseHandle
|
||||
from .handles.azur_handle import AzurHandle
|
||||
from .handles.fgo_handle import FgoHandle
|
||||
from .handles.genshin_handle import GenshinHandle
|
||||
from .handles.guardian_handle import GuardianHandle
|
||||
from .handles.onmyoji_handle import OnmyojiHandle
|
||||
from .handles.pcr_handle import PcrHandle
|
||||
from .handles.pretty_handle import PrettyHandle
|
||||
from .handles.prts_handle import PrtsHandle
|
||||
|
||||
from .config import draw_config
|
||||
|
||||
|
||||
__zx_plugin_name__ = "游戏抽卡"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
模拟赛马娘,原神,明日方舟,坎公骑冠剑,公主连结(国/台),碧蓝航线,FGO,阴阳师进行抽卡
|
||||
指令:
|
||||
原神[1-300]抽: 原神常驻池
|
||||
原神角色[1-300]抽: 原神角色UP池子
|
||||
原神武器[1-300]抽: 原神武器UP池子
|
||||
原神[1-180]抽: 原神常驻池
|
||||
原神角色[1-180]抽: 原神角色UP池子
|
||||
原神武器[1-180]抽: 原神武器UP池子
|
||||
重置原神抽卡: 清空当前卡池的抽卡次数[即从0开始计算UP概率]
|
||||
方舟[1-300]抽: 方舟卡池,当有当期UP时指向UP池
|
||||
赛马娘[1-200]抽: 赛马娘卡池,当有当期UP时指向UP池
|
||||
坎公骑冠剑[1-300]抽: 坎公骑冠剑卡池,当有当期UP时指向UP池
|
||||
pcr/公主连接[1-300]抽: 公主连接卡池
|
||||
碧蓝航线/碧蓝[重型/轻型/特型][1-300]抽: 碧蓝航线重型/轻型/特型卡池
|
||||
碧蓝航线/碧蓝[重型/轻型/特型/活动][1-300]抽: 碧蓝航线重型/轻型/特型/活动卡池
|
||||
fgo[1-300]抽: fgo卡池
|
||||
阴阳师[1-300]抽: 阴阳师卡池
|
||||
* 以上指令可以通过 XX一井 来指定最大抽取数量 *
|
||||
@@ -70,9 +63,9 @@ usage:
|
||||
""".strip()
|
||||
__plugin_des__ = "就算是模拟抽卡也不能改变自己是个非酋"
|
||||
__plugin_cmd__ = [
|
||||
"原神[1-300]抽",
|
||||
"原神角色[1-300]抽",
|
||||
"原神武器[1-300]抽",
|
||||
"原神[1-180]抽",
|
||||
"原神角色[1-180]抽",
|
||||
"原神武器[1-180]抽",
|
||||
"重置原神抽卡",
|
||||
"方舟[1-300]抽",
|
||||
"赛马娘[1-200]抽",
|
||||
@@ -102,314 +95,137 @@ __plugin_settings__ = {
|
||||
}
|
||||
|
||||
|
||||
prts = on_regex(
|
||||
r".*?方舟[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("prts"), priority=5, block=True
|
||||
)
|
||||
prts_update = on_keyword(
|
||||
{"更新方舟信息", "更新明日方舟信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
prts_up_reload = on_keyword({"重载方舟卡池"}, priority=1, block=True)
|
||||
@dataclass
|
||||
class Game:
|
||||
keywords: Set[str]
|
||||
handle: BaseHandle
|
||||
flag: bool
|
||||
max_count: int = 300 # 一次最大抽卡数
|
||||
reload_time: Optional[int] = None # 重载UP池时间(小时)
|
||||
|
||||
genshin = on_regex(
|
||||
".*?原神(武器|角色)?池?[1-9|一][0-9]{0,2}[抽|井]",
|
||||
rule=is_switch("genshin"),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
genshin_update = on_keyword({"更新原神信息"}, permission=SUPERUSER, priority=1, block=True)
|
||||
genshin_reset = on_keyword({"重置原神抽卡"}, priority=1, block=True)
|
||||
genshin_up_reload = on_keyword({"重载原神卡池"}, priority=1, block=True)
|
||||
|
||||
pretty = on_regex(
|
||||
".*?马娘卡?[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("pretty"), priority=5, block=True
|
||||
)
|
||||
pretty_update = on_keyword(
|
||||
{"更新马娘信息", "更新赛马娘信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
pretty_up_reload = on_keyword({"重载赛马娘卡池"}, priority=1, block=True)
|
||||
|
||||
guardian = on_regex(
|
||||
".*?坎公骑冠剑武?器?[1-9|一][0-9]{0,2}[抽|井]",
|
||||
rule=is_switch("guardian"),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
guardian_update = on_keyword(
|
||||
{"更新坎公骑冠剑信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
games = (
|
||||
Game({"azur", "碧蓝", "碧蓝航线"}, AzurHandle(), draw_config.AZUR_FLAG),
|
||||
Game({"fgo", "命运冠位指定"}, FgoHandle(), draw_config.FGO_FLAG),
|
||||
Game(
|
||||
{"genshin", "原神"},
|
||||
GenshinHandle(),
|
||||
draw_config.GENSHIN_FLAG,
|
||||
max_count=180,
|
||||
reload_time=18,
|
||||
),
|
||||
Game(
|
||||
{"guardian", "坎公骑冠剑"},
|
||||
GuardianHandle(),
|
||||
draw_config.GUARDIAN_FLAG,
|
||||
reload_time=4,
|
||||
),
|
||||
Game({"onmyoji", "阴阳师"}, OnmyojiHandle(), draw_config.ONMYOJI_FLAG),
|
||||
Game({"pcr", "公主连结", "公主连接", "公主链接", "公主焊接"}, PcrHandle(), draw_config.PCR_FLAG),
|
||||
Game(
|
||||
{"pretty", "马娘", "赛马娘"},
|
||||
PrettyHandle(),
|
||||
draw_config.PRETTY_FLAG,
|
||||
max_count=200,
|
||||
reload_time=4,
|
||||
),
|
||||
Game({"prts", "方舟", "明日方舟"}, PrtsHandle(), draw_config.PRTS_FLAG, reload_time=4),
|
||||
)
|
||||
|
||||
pcr = on_regex(
|
||||
".*?(pcr|公主连结|公主连接|公主链接|公主焊接)[1-9|一][0-9]{0,2}[抽|井]",
|
||||
rule=is_switch("pcr"),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
pcr_update = on_keyword(
|
||||
{"更新pcr信息", "更新公主连结信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
azur = on_regex(
|
||||
".*?碧蓝航?线?(轻型|重型|特型)池?[1-9|一][0-9]{0,2}[抽]",
|
||||
rule=is_switch("azur"),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
azur_update = on_keyword(
|
||||
{"更新碧蓝信息", "更新碧蓝航线信息"}, permission=SUPERUSER, priority=1, block=True
|
||||
)
|
||||
|
||||
fgo = on_regex(
|
||||
".*?fgo[1-9|一][0-9]{0,2}[抽]", rule=is_switch("fgo"), priority=5, block=True
|
||||
)
|
||||
fgo_update = on_keyword({"更新fgo信息"}, permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
onmyoji = on_regex(
|
||||
".*?阴阳师[1-9|一][0-9]{0,2}[抽]", rule=is_switch("onmyoji"), priority=5, block=True
|
||||
)
|
||||
onmyoji_update = on_keyword({"更新阴阳师信息"}, permission=SUPERUSER, priority=1, block=True)
|
||||
|
||||
|
||||
@prts.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
if msg in ["方舟一井", "方舟1井"]:
|
||||
num = 300
|
||||
else:
|
||||
rmsg = re.search(r".*?方舟(.*)抽", msg)
|
||||
if rmsg:
|
||||
num, flag = check_num(rmsg.group(1), 300)
|
||||
if not flag:
|
||||
await prts.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await prts.send(await prts_draw(int(num)), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 方舟 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@prts_up_reload.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = await reload_prts_pool()
|
||||
await prts_up_reload.finish(Message(f"重载完成!\n{text}"))
|
||||
|
||||
|
||||
@genshin.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
rmsg = re.search(r".*?原神(武器|角色)?池?(.*)[抽|井]", msg)
|
||||
if rmsg:
|
||||
pool_name = rmsg.group(1)
|
||||
if pool_name == "武器":
|
||||
pool_name = "arms"
|
||||
elif pool_name == "角色":
|
||||
pool_name = "char"
|
||||
else:
|
||||
pool_name = ""
|
||||
num = rmsg.group(2)
|
||||
if msg.find("一井") != -1 or msg.find("1井") != -1:
|
||||
num = 180
|
||||
else:
|
||||
num, flag = check_num(num, 180)
|
||||
if not flag:
|
||||
await genshin.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await genshin.send(
|
||||
await genshin_draw(event.user_id, int(num), pool_name), at_sender=True
|
||||
)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 原神 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@genshin_up_reload.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = await reload_genshin_pool()
|
||||
await genshin_reset.finish(Message(f"重载成功!\n{text}"))
|
||||
|
||||
|
||||
@genshin_reset.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
reset_count(event.user_id)
|
||||
await genshin_reset.send("重置了原神抽卡次数", at_sender=True)
|
||||
|
||||
|
||||
@pretty.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
if msg.find("1井") != -1 or msg.find("一井") != -1:
|
||||
num = 200
|
||||
if msg.find("卡") == -1:
|
||||
pool_name = "char"
|
||||
else:
|
||||
pool_name = "card"
|
||||
else:
|
||||
rmsg = re.search(r".*?马娘(.*)抽", msg)
|
||||
if rmsg:
|
||||
num = rmsg.group(1)
|
||||
if num[0] == "卡":
|
||||
num = num[1:]
|
||||
pool_name = "card"
|
||||
def create_matchers():
|
||||
def draw_handler(game: Game) -> T_Handler:
|
||||
async def handler(
|
||||
matcher: Matcher, event: MessageEvent, args: Tuple[str, ...] = RegexGroup()
|
||||
):
|
||||
pool_name, num, unit = args
|
||||
if num == "单":
|
||||
num = 1
|
||||
else:
|
||||
pool_name = "char"
|
||||
num, flag = check_num(num, 200)
|
||||
if not flag:
|
||||
await pretty.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await pretty.send(await pretty_draw(int(num), pool_name), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 赛马娘 {num}抽"
|
||||
)
|
||||
try:
|
||||
num = int(cn2an(num, mode="smart"))
|
||||
except ValueError:
|
||||
await matcher.finish("必!须!是!数!字!")
|
||||
if unit == "井":
|
||||
num *= game.max_count
|
||||
if num < 1:
|
||||
await matcher.finish("虚空抽卡???")
|
||||
elif num > game.max_count:
|
||||
await matcher.finish("一井都满不足不了你嘛!快爬开!")
|
||||
pool_name = (
|
||||
pool_name.replace("池", "")
|
||||
.replace("武器", "arms")
|
||||
.replace("角色", "char")
|
||||
.replace("卡牌", "card")
|
||||
.replace("卡", "card")
|
||||
)
|
||||
try:
|
||||
res = await game.handle.draw(num, pool_name=pool_name, user_id=event.user_id)
|
||||
except:
|
||||
logger.warning(traceback.format_exc())
|
||||
await matcher.finish("出错了...")
|
||||
await matcher.finish(res, at_sender=True)
|
||||
|
||||
return handler
|
||||
|
||||
def update_handler(game: Game) -> T_Handler:
|
||||
async def handler(matcher: Matcher):
|
||||
await game.handle.update_info()
|
||||
await matcher.finish("更新完成!")
|
||||
|
||||
return handler
|
||||
|
||||
def reload_handler(game: Game) -> T_Handler:
|
||||
async def handler(matcher: Matcher):
|
||||
res = await game.handle.reload_pool()
|
||||
if res:
|
||||
await matcher.finish(res)
|
||||
|
||||
return handler
|
||||
|
||||
def reset_handler(game: Game) -> T_Handler:
|
||||
async def handler(matcher: Matcher, event: MessageEvent):
|
||||
if game.handle.reset_count(event.user_id):
|
||||
await matcher.finish("重置成功!")
|
||||
|
||||
return handler
|
||||
|
||||
def scheduled_job(game: Game) -> T_Handler:
|
||||
async def handler():
|
||||
await game.handle.reload_pool()
|
||||
|
||||
return handler
|
||||
|
||||
for game in games:
|
||||
pool_pattern = r"([^\s单0-9零一二三四五六七八九百十]{0,3})"
|
||||
num_pattern = r"(单|[0-9零一二三四五六七八九百十]{1,3})"
|
||||
unit_pattern = r"([抽|井|连])"
|
||||
draw_regex = r".*?(?:{})\s*{}\s*{}\s*{}".format(
|
||||
"|".join(game.keywords), pool_pattern, num_pattern, unit_pattern
|
||||
)
|
||||
update_keywords = {f"更新{keyword}信息" for keyword in game.keywords}
|
||||
reload_keywords = {f"重载{keyword}卡池" for keyword in game.keywords}
|
||||
reset_keywords = {f"重置{keyword}抽卡" for keyword in game.keywords}
|
||||
if game.flag:
|
||||
on_regex(draw_regex, priority=5, block=True).append_handler(
|
||||
draw_handler(game)
|
||||
)
|
||||
on_keyword(
|
||||
update_keywords, permission=SUPERUSER, priority=1, block=True
|
||||
).append_handler(update_handler(game))
|
||||
on_keyword(reload_keywords, priority=1, block=True).append_handler(
|
||||
reload_handler(game)
|
||||
)
|
||||
on_keyword(reset_keywords, priority=1, block=True).append_handler(
|
||||
reset_handler(game)
|
||||
)
|
||||
if game.reload_time:
|
||||
scheduler.add_job(
|
||||
scheduled_job(game), trigger="cron", hour=game.reload_time, minute=1
|
||||
)
|
||||
|
||||
|
||||
@pretty_up_reload.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
text = await reload_pretty_pool()
|
||||
await genshin_reset.finish(Message(f"重载成功!\n{text}"))
|
||||
|
||||
|
||||
@guardian.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
pool_name = "char"
|
||||
if msg.find("1井") != -1 or msg.find("一井") != -1:
|
||||
num = 300
|
||||
if msg.find("武器") != -1:
|
||||
pool_name = "arms"
|
||||
else:
|
||||
rmsg = re.search(r".*?坎公骑冠剑(.*)抽", msg)
|
||||
if rmsg:
|
||||
num = rmsg.group(1)
|
||||
if num.find("武器") != -1:
|
||||
pool_name = "arms"
|
||||
num = num.replace("武器", "")
|
||||
num, flag = check_num(num, 300)
|
||||
if not flag:
|
||||
await guardian.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await guardian.send(await guardian_draw(int(num), pool_name), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 坎公骑冠剑 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@pcr.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
if msg.find("1井") != -1 or msg.find("一井") != -1:
|
||||
num = 300
|
||||
else:
|
||||
rmsg = re.search(r".*?(pcr|公主连结)(.*)[抽|井]", msg)
|
||||
if rmsg:
|
||||
num, flag = check_num(rmsg.group(2), 300)
|
||||
if not flag:
|
||||
await pcr.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await pcr.send(await pcr_draw(int(num)), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 公主连结 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@azur.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
rmsg = re.search(".*?碧蓝航?线?(轻型|重型|特型)池?(.*)[抽]", msg)
|
||||
if rmsg:
|
||||
pool_name = rmsg.group(1)
|
||||
num, flag = check_num(rmsg.group(2), 300)
|
||||
if not flag:
|
||||
await azur.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await azur.send(await azur_draw(int(num), pool_name), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 碧蓝航线 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@fgo.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
rmsg = re.search(".*?fgo(.*)抽", msg)
|
||||
if rmsg:
|
||||
num, flag = check_num(rmsg.group(1), 300)
|
||||
if not flag:
|
||||
await fgo.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await fgo.send(await fgo_draw(int(num)), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) fgo {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@onmyoji.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = str(event.get_message()).strip()
|
||||
rmsg = re.search(".*?阴阳师(.*)抽", msg)
|
||||
if rmsg:
|
||||
num, flag = check_num(rmsg.group(1), 300)
|
||||
if not flag:
|
||||
await onmyoji.finish(num, at_sender=True)
|
||||
else:
|
||||
return
|
||||
await onmyoji.send(await onmyoji_draw(int(num)), at_sender=True)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 阴阳师 {num}抽"
|
||||
)
|
||||
|
||||
|
||||
@prts_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_prts_info()
|
||||
await prts_update.finish("更新完成!")
|
||||
|
||||
|
||||
@genshin_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_genshin_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@pretty_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_pretty_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@guardian_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_guardian_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@pcr_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_pcr_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@azur_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_azur_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@fgo_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_fgo_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
|
||||
|
||||
@onmyoji_update.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
await update_onmyoji_info()
|
||||
await genshin_update.finish("更新完成!")
|
||||
create_matchers()
|
||||
|
||||
|
||||
# 更新资源
|
||||
@@ -420,57 +236,21 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
)
|
||||
async def _():
|
||||
tasks = []
|
||||
if PRTS_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_prts_info()))
|
||||
if GENSHIN_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_genshin_info()))
|
||||
if PRETTY_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_pretty_info()))
|
||||
if GUARDIAN_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_guardian_info()))
|
||||
if PCR_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_pcr_info()))
|
||||
if AZUR_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_azur_info()))
|
||||
if FGO_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_fgo_info()))
|
||||
if ONMYOJI_FLAG:
|
||||
tasks.append(asyncio.ensure_future(update_onmyoji_info()))
|
||||
for game in games:
|
||||
if game.flag:
|
||||
tasks.append(asyncio.ensure_future(game.handle.update_info()))
|
||||
await asyncio.gather(*tasks)
|
||||
logger.info("draw_card 抽卡自动更新完成...")
|
||||
|
||||
|
||||
# 每天四点重载方舟up卡池
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=4,
|
||||
minute=1,
|
||||
)
|
||||
driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
if PRTS_FLAG:
|
||||
await reload_prts_pool()
|
||||
logger.info("自动重载方舟卡池UP成功")
|
||||
|
||||
|
||||
# 每天四点重载赛马娘up卡池
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=4,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
if PRETTY_FLAG:
|
||||
await reload_pretty_pool()
|
||||
logger.info("自动重载赛马娘UP成功")
|
||||
|
||||
|
||||
# 每天下午六点点重载原神up卡池
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=18,
|
||||
minute=1,
|
||||
)
|
||||
async def _():
|
||||
if PRTS_FLAG:
|
||||
await reload_genshin_pool()
|
||||
logger.info("自动重载原神卡池UP成功")
|
||||
tasks = []
|
||||
for game in games:
|
||||
if game.flag:
|
||||
game.handle.init_data()
|
||||
if not game.handle.data_exists():
|
||||
tasks.append(asyncio.ensure_future(game.handle.update_info()))
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
@@ -1,390 +0,0 @@
|
||||
from bs4 import BeautifulSoup
|
||||
from datetime import datetime, timedelta
|
||||
from .config import DRAW_PATH
|
||||
from pathlib import Path
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from services.log import logger
|
||||
from utils.http_utils import AsyncHttpx
|
||||
import re
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
headers = {'User-Agent': '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"'}
|
||||
|
||||
prts_up_char = Path(DRAW_PATH + "/draw_card_up/prts_up_char.json")
|
||||
genshin_up_char = Path(DRAW_PATH + "/draw_card_up/genshin_up_char.json")
|
||||
pretty_up_char = Path(DRAW_PATH + "/draw_card_up/pretty_up_char.json")
|
||||
guardian_up_char = Path(DRAW_PATH + "/draw_card_up/guardian_up_char.json")
|
||||
|
||||
prts_url = "https://ak.hypergryph.com/news.html"
|
||||
genshin_url = "https://wiki.biligame.com/ys/%E7%A5%88%E6%84%BF"
|
||||
pretty_url = "https://wiki.biligame.com/umamusume/%E5%85%AC%E5%91%8A"
|
||||
guardian_url = "https://wiki.biligame.com/gt/%E9%A6%96%E9%A1%B5"
|
||||
|
||||
|
||||
# 是否过时
|
||||
def is_expired(data: dict):
|
||||
try:
|
||||
times = data['time'].split('-')
|
||||
for i in range(len(times)):
|
||||
times[i] = str(datetime.now().year) + '-' + times[i].split('日')[0].strip().replace('月', '-')
|
||||
start_date = datetime.strptime(times[0], '%Y-%m-%d').date()
|
||||
end_date = datetime.strptime(times[1], '%Y-%m-%d').date()
|
||||
now = datetime.now().date()
|
||||
except ValueError:
|
||||
return False
|
||||
return not start_date <= now <= end_date
|
||||
|
||||
|
||||
# 检查写入
|
||||
def check_write(data: dict, up_char_file):
|
||||
if is_expired(data['char']):
|
||||
for x in list(data.keys()):
|
||||
data[x]['title'] = ''
|
||||
else:
|
||||
with open(up_char_file, 'w', encoding='utf8') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
if not up_char_file.exists():
|
||||
with open(up_char_file, 'w', encoding='utf8') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
else:
|
||||
with open(up_char_file, 'r', encoding='utf8') as f:
|
||||
old_data = json.load(f)
|
||||
if is_expired(old_data['char']):
|
||||
return old_data
|
||||
else:
|
||||
with open(up_char_file, 'w', encoding='utf8') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
return data
|
||||
|
||||
|
||||
class PrtsAnnouncement:
|
||||
|
||||
def __init__(self):
|
||||
self.game_name = '明日方舟'
|
||||
|
||||
async def _get_announcement_text(self):
|
||||
text = (await AsyncHttpx.get(prts_url)).text
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
ol = soup.find('ol', {'class': 'articleList active', 'data-category-key': 'LATEST'})
|
||||
for li in ol:
|
||||
itype = li.find('span', {'class': 'articleItemCate'}).text
|
||||
if itype == '活动':
|
||||
a = li.find('a')['href']
|
||||
return (await AsyncHttpx.get(f'https://ak.hypergryph.com{a}')).text
|
||||
|
||||
async def update_up_char(self):
|
||||
prts_up_char.parent.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
data = {'char': {'up_char': {'6': {}, '5': {}, '4': {}}, 'title': '', 'time': '', 'pool_img': ''}}
|
||||
text = await self._get_announcement_text()
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
content = soup.find('div', {'class': 'article-content'})
|
||||
contents = [x for x in content.contents if x.text or str(x).find('img') != -1]
|
||||
start_index = -1
|
||||
end_index = -1
|
||||
for i in range(len(contents)):
|
||||
if str(contents[i]).startswith('<p>'):
|
||||
r = re.search('(.*)(寻访|复刻).*?开启', contents[i].text)
|
||||
if r:
|
||||
if str(contents[i+3].text).find('★') != -1:
|
||||
img = contents[i-1].find('img')
|
||||
if img:
|
||||
data['char']['pool_img'] = img['src']
|
||||
start_index = i
|
||||
for j in range(i, len(contents)):
|
||||
if str(contents[j]).find('注意') != -1:
|
||||
end_index = j
|
||||
break
|
||||
break
|
||||
contents = contents[start_index: end_index]
|
||||
title = contents[0].text
|
||||
data['char']['title'] = title[title.find('【'): title.find('】') + 1]
|
||||
data['char']['time'] = str(contents[1].text).split(':', maxsplit=1)[1]
|
||||
for p in contents[2:]:
|
||||
p = str(p.text)
|
||||
r = None
|
||||
if p.find('★') != -1:
|
||||
if p.find('权值') == -1:
|
||||
r = re.search(r'.*?:(.*)(占(.*)★.*?的(.*)%)', p)
|
||||
else:
|
||||
r = re.search(r'.*?:(.*)(在(.*)★.*?以(.*)倍权值.*?)', p)
|
||||
star = r.group(2)
|
||||
if r:
|
||||
chars = r.group(1)
|
||||
if chars.find('/') != -1:
|
||||
chars = chars.strip().split('/')
|
||||
elif chars.find('\\') != -1:
|
||||
chars = chars.strip().split('\\')
|
||||
else:
|
||||
chars = chars.split('\n')
|
||||
chars = [x.replace('[限定]', '').strip() for x in chars]
|
||||
probability = r.group(3)
|
||||
probability = probability if int(probability) > 10 else f'权{probability}'
|
||||
for char in chars:
|
||||
if char.strip():
|
||||
data['char']['up_char'][star][char.strip()] = probability
|
||||
except TimeoutError:
|
||||
logger.warning(f'更新明日方舟UP池信息超时...')
|
||||
if prts_up_char.exists():
|
||||
with open(prts_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f'更新明日方舟未知错误 e:{e}')
|
||||
if prts_up_char.exists():
|
||||
with open(prts_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
return check_write(data, prts_up_char)
|
||||
|
||||
|
||||
class GenshinAnnouncement:
|
||||
|
||||
def __init__(self):
|
||||
self.game_name = '原神'
|
||||
|
||||
async def _get_announcement_text(self):
|
||||
return (await AsyncHttpx.get(genshin_url)).text
|
||||
|
||||
async def update_up_char(self):
|
||||
genshin_up_char.parent.mkdir(exist_ok=True, parents=True)
|
||||
data = {
|
||||
'char': {'up_char': {'5': {}, '4': {}}, 'title': '', 'time': '', 'pool_img': ''},
|
||||
'arms': {'up_char': {'5': {}, '4': {}}, 'title': '', 'time': '', 'pool_img': ''}
|
||||
}
|
||||
text = await self._get_announcement_text()
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
try:
|
||||
div = soup.find_all('div', {'class': 'row'})[1]
|
||||
tables = div.find_all('table', {'class': 'wikitable'})
|
||||
for table in tables:
|
||||
trs = table.find('tbody').find_all('tr')
|
||||
pool_img = trs[0].find('th').find('img')
|
||||
if pool_img['title'].find('角色活动') == -1:
|
||||
itype = 'arms'
|
||||
else:
|
||||
itype = 'char'
|
||||
try:
|
||||
data[itype]['pool_img'] = str(pool_img['srcset']).split(' ')[0]
|
||||
except KeyError:
|
||||
data[itype]['pool_img'] = pool_img['src']
|
||||
data[itype]['title'] = str(pool_img['title']).split(f'期{"角色" if itype == "char" else "武器"}')[0][:-3]
|
||||
data[itype]['time'] = trs[1].find('td').text
|
||||
if data[itype]['time'][-1] == '\n':
|
||||
data[itype]['time'] = data[itype]['time'][:-1]
|
||||
if '版本更新后' in data[itype]['time']:
|
||||
sp = data[itype]['time'].split('~')
|
||||
end_time = datetime.strptime(sp[1].strip(), "%Y/%m/%d %H:%M")
|
||||
start_time = end_time - timedelta(days=20)
|
||||
data[itype]['time'] = start_time.strftime('%Y/%m/%d') + ' ~ ' + end_time.strftime('%Y/%m/%d')
|
||||
tmp = ''
|
||||
for tm in data[itype]['time'].split('~'):
|
||||
date_time_sp = tm.split('/')
|
||||
date_time_sp[2] = date_time_sp[2].strip().replace(' ', '日 ')
|
||||
tmp += date_time_sp[1] + '月' + date_time_sp[2] + ' - '
|
||||
data[itype]['time'] = tmp[:-2].strip()
|
||||
for a in trs[2].find('td').find_all('a'):
|
||||
char_name = a['title']
|
||||
data[itype]['up_char']['5'][char_name] = "50"
|
||||
for a in trs[3].find('td').find_all('a'):
|
||||
char_name = a['title']
|
||||
data[itype]['up_char']['4'][char_name] = "50"
|
||||
except TimeoutError:
|
||||
logger.warning(f'更新原神UP池信息超时...')
|
||||
if genshin_up_char.exists():
|
||||
with open(genshin_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f'更新原神UP失败,疑似UP池已结束, e:{e}')
|
||||
if genshin_up_char.exists():
|
||||
with open(genshin_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
data['char']['title'] = ''
|
||||
data['arms']['title'] = ''
|
||||
with open(genshin_up_char, 'w', encoding='utf8') as wf:
|
||||
json.dump(data, wf, ensure_ascii=False, indent=4)
|
||||
return data
|
||||
return check_write(data, genshin_up_char)
|
||||
|
||||
|
||||
class PrettyAnnouncement:
|
||||
|
||||
def __init__(self):
|
||||
self.game_name = '赛马娘'
|
||||
|
||||
async def _get_announcement_text(self):
|
||||
text = (await AsyncHttpx.get(pretty_url)).text
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
divs = soup.find('div', {'id': 'mw-content-text'}).find('div').find_all('div')
|
||||
title = " "
|
||||
for div in divs:
|
||||
a = div.find('a')
|
||||
try:
|
||||
title = a['title']
|
||||
except (KeyError, TypeError):
|
||||
continue
|
||||
if title.find('新角色追加') != -1:
|
||||
url = a['href']
|
||||
break
|
||||
return (await AsyncHttpx.get(f'https://wiki.biligame.com/{url}')).text, title[:-2]
|
||||
|
||||
async def update_up_char(self):
|
||||
pretty_up_char.parent.mkdir(exist_ok=True, parents=True)
|
||||
data = {
|
||||
'char': {'up_char': {'3': {}, '2': {}, '1': {}}, 'title': '', 'time': '', 'pool_img': ''},
|
||||
'card': {'up_char': {'3': {}, '2': {}, '1': {}}, 'title': '', 'time': '', 'pool_img': ''}
|
||||
}
|
||||
try:
|
||||
text, title = await self._get_announcement_text()
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
context = soup.find('div', {'class': 'toc-sticky'})
|
||||
if not context:
|
||||
context = soup.find('div', {'class': 'mw-parser-output'})
|
||||
data['char']['title'] = title
|
||||
data['card']['title'] = title
|
||||
r = re.search(r'(\d{1,2}/\d{1,2} \d{1,2}:\d{1,2} ~ \d{1,2}/\d{1,2} \d{1,2}:\d{1,2})', str(context.text))
|
||||
if r:
|
||||
time = str(r.group(1))
|
||||
else:
|
||||
logger.error('赛马娘UP无法找到活动日期....取消更新UP池子...')
|
||||
return check_write(data, pretty_up_char)
|
||||
time = time.replace('~', '-').replace('/', '月').split(' ')
|
||||
time = time[0] + '日 ' + time[1] + ' - ' + time[3] + '日 ' + time[4]
|
||||
data['char']['time'] = time
|
||||
data['card']['time'] = time
|
||||
for p in context.find_all('p'):
|
||||
if str(p).find('当期UP赛马娘') != -1 and str(p).find('■') != -1:
|
||||
if not data['char']['pool_img']:
|
||||
try:
|
||||
data['char']['pool_img'] = p.find('img')['src']
|
||||
except TypeError:
|
||||
for center in context.find_all('center'):
|
||||
try:
|
||||
img = center.find('img')
|
||||
if img and str(img['alt']).find('新马娘') != -1 and str(img['alt']).find('总览') == 1:
|
||||
data['char']['pool_img'] = img['src']
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
r = re.findall(r'.*?当期UP赛马娘([\s\S]*)<奖励内容>.*?', str(p))
|
||||
if r:
|
||||
for x in r:
|
||||
x = str(x).split('\n')
|
||||
for msg in x:
|
||||
if msg.find('★') != -1:
|
||||
msg = msg.replace('<br/>', '')
|
||||
char_name = msg[msg.find('['):].strip()
|
||||
if (star := len(msg[:msg.find('[')].strip())) == 3:
|
||||
data['char']['up_char']['3'][char_name] = '70'
|
||||
elif star == 2:
|
||||
data['char']['up_char']['2'][char_name] = '70'
|
||||
elif star == 1:
|
||||
data['char']['up_char']['1'][char_name] = '70'
|
||||
if str(p).find('(当期UP对象)') != -1 and str(p).find('赛马娘') == -1 and str(p).find('■') != -1:
|
||||
# data['card']['pool_img'] = p.find('img')['src']
|
||||
if not data['char']['pool_img']:
|
||||
try:
|
||||
data['char']['pool_img'] = p.find('img')['src']
|
||||
except TypeError:
|
||||
for center in context.find_all('center'):
|
||||
try:
|
||||
img = center.find('img')
|
||||
if img and str(img['alt']).find('新卡') != -1 and str(img['alt']).find('总览') == 1:
|
||||
data['card']['pool_img'] = img['src']
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
r = re.search(r'■全?新?支援卡(当期UP对象)([\s\S]*)</p>', str(p))
|
||||
if r:
|
||||
rmsg = r.group(1).strip()
|
||||
rmsg = rmsg.split('<br/>')
|
||||
rmsg = [x for x in rmsg if x]
|
||||
for x in rmsg:
|
||||
x = x.replace('\n', '').replace('・', '')
|
||||
star = x[:x.find('[')].strip()
|
||||
char_name = x[x.find('['):].strip()
|
||||
if star == 'SSR':
|
||||
data['card']['up_char']['3'][char_name] = '70'
|
||||
if star == 'SR':
|
||||
data['card']['up_char']['2'][char_name] = '70'
|
||||
if star == 'R':
|
||||
data['card']['up_char']['1'][char_name] = '70'
|
||||
# 日文->中文
|
||||
with open(DRAW_PATH + 'pretty_card.json', 'r', encoding='utf8') as f:
|
||||
all_data = json.load(f)
|
||||
for star in data['card']['up_char'].keys():
|
||||
for name in list(data['card']['up_char'][star].keys()):
|
||||
char_name = name.split(']')[1].strip()
|
||||
tp_name = name[name.find('['): name.find(']') + 1].strip().replace('[', '【').replace(']', '】')
|
||||
for x in all_data.keys():
|
||||
if all_data[x]['名称'].find(tp_name) != -1 and all_data[x]['关联角色'] == char_name:
|
||||
data['card']['up_char'][star].pop(name)
|
||||
data['card']['up_char'][star][all_data[x]['中文名']] = '70'
|
||||
except TimeoutError:
|
||||
logger.warning(f'更新赛马娘UP池信息超时...')
|
||||
if pretty_up_char.exists():
|
||||
with open(pretty_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f'赛马娘up更新未知错误 {type(e)}:{e}')
|
||||
if pretty_up_char.exists():
|
||||
with open(pretty_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
return check_write(data, pretty_up_char)
|
||||
|
||||
|
||||
class GuardianAnnouncement:
|
||||
|
||||
def __init__(self):
|
||||
self.game_name = '坎公骑冠剑'
|
||||
|
||||
async def _get_announcement_text(self):
|
||||
return (await AsyncHttpx.get(guardian_url)).text
|
||||
|
||||
async def update_up_char(self):
|
||||
data = {
|
||||
'char': {'up_char': {'3': {}}, 'title': '', 'time': '', 'pool_img': ''},
|
||||
'arms': {'up_char': {'5': {}}, 'title': '', 'time': '', 'pool_img': ''}
|
||||
}
|
||||
try:
|
||||
text = await self._get_announcement_text()
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
context = soup.select('div.col-sm-3:nth-child(3) > div:nth-child(2) > div:nth-child(1) '
|
||||
'> div:nth-child(2) > div:nth-child(3) > font:nth-child(1)')[0]
|
||||
title = context.find('p').find('b').text
|
||||
tmp = title.split(',')
|
||||
time = ''
|
||||
for msg in tmp:
|
||||
r = re.search(r'[从|至](.*)(开始|结束)', msg)
|
||||
if r:
|
||||
time += r.group(1).strip() + ' - '
|
||||
time = time[:-3]
|
||||
title = time.split(' - ')[0] + 'UP卡池'
|
||||
data['char']['title'] = title
|
||||
data['arms']['title'] = title
|
||||
data['char']['time'] = time
|
||||
data['arms']['time'] = time
|
||||
start_idx = -1
|
||||
end_idx = -1
|
||||
index = 0
|
||||
divs = context.find_all('div')
|
||||
for x in divs:
|
||||
if x.text == '角色':
|
||||
start_idx = index
|
||||
if x.text == '武器':
|
||||
end_idx = index
|
||||
break
|
||||
index += 1
|
||||
for x in divs[start_idx + 1: end_idx]:
|
||||
name = x.find('p').find_all('a')[-1].text
|
||||
data['char']['up_char']['3'][name] = '0'
|
||||
for x in divs[end_idx + 1:]:
|
||||
name = x.find('p').find_all('a')[-1].text
|
||||
data['arms']['up_char']['5'][name] = '0'
|
||||
except TimeoutError:
|
||||
logger.warning(f'更新坎公骑冠剑UP池信息超时...')
|
||||
if guardian_up_char.exists():
|
||||
with open(guardian_up_char, 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f'坎公骑冠剑up更新未知错误 {type(e)}:{e}')
|
||||
return check_write(data, guardian_up_char)
|
||||
@@ -1,70 +0,0 @@
|
||||
import asyncio
|
||||
import nonebot
|
||||
import os
|
||||
from services.log import logger
|
||||
from .pcr_handle import update_pcr_info, init_pcr_data
|
||||
from .azur_handle import update_azur_info, init_azur_data
|
||||
from .prts_handle import update_prts_info, init_prts_data
|
||||
from .pretty_handle import update_pretty_info, init_pretty_data
|
||||
from .guardian_handle import update_guardian_info, init_guardian_data
|
||||
from .genshin_handle import update_genshin_info, init_genshin_data
|
||||
from .fgo_handle import update_fgo_info, init_fgo_data
|
||||
from .onmyoji_handle import update_onmyoji_info, init_onmyoji_data
|
||||
from .config import DRAW_PATH, PRTS_FLAG, PRETTY_FLAG, GUARDIAN_FLAG, PCR_FLAG, AZUR_FLAG, GENSHIN_FLAG, FGO_FLAG, \
|
||||
ONMYOJI_FLAG
|
||||
|
||||
|
||||
driver: nonebot.Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def async_update_game():
|
||||
tasks = []
|
||||
init_lst = [init_pcr_data, init_pretty_data, init_azur_data, init_prts_data, init_genshin_data, init_guardian_data,
|
||||
init_fgo_data, init_onmyoji_data]
|
||||
if PRTS_FLAG and not os.path.exists(DRAW_PATH + 'prts.json'):
|
||||
tasks.append(asyncio.ensure_future(update_prts_info()))
|
||||
init_lst.remove(init_prts_data)
|
||||
|
||||
if PRETTY_FLAG and (not os.path.exists(DRAW_PATH + 'pretty.json') or
|
||||
not os.path.exists(DRAW_PATH + 'pretty_card.json')):
|
||||
tasks.append(asyncio.ensure_future(update_pretty_info()))
|
||||
init_lst.remove(init_pretty_data)
|
||||
|
||||
if GUARDIAN_FLAG and not os.path.exists(DRAW_PATH + 'guardian.json'):
|
||||
tasks.append(asyncio.ensure_future(update_guardian_info()))
|
||||
|
||||
if PCR_FLAG and not os.path.exists(DRAW_PATH + 'pcr.json'):
|
||||
tasks.append(asyncio.ensure_future(update_pcr_info()))
|
||||
init_lst.remove(init_pcr_data)
|
||||
|
||||
if GENSHIN_FLAG and (not os.path.exists(DRAW_PATH + 'genshin.json') or
|
||||
not os.path.exists(DRAW_PATH + 'genshin_arms.json')):
|
||||
tasks.append(asyncio.ensure_future(update_genshin_info()))
|
||||
init_lst.remove(init_genshin_data)
|
||||
|
||||
if AZUR_FLAG and not os.path.exists(DRAW_PATH + 'azur.json'):
|
||||
tasks.append(asyncio.ensure_future(update_azur_info()))
|
||||
init_lst.remove(init_azur_data)
|
||||
|
||||
if FGO_FLAG and (not os.path.exists(DRAW_PATH + 'fgo.json') or
|
||||
not os.path.exists(DRAW_PATH + 'fgo_card.json')):
|
||||
tasks.append(asyncio.ensure_future(update_fgo_info()))
|
||||
init_lst.remove(init_fgo_data)
|
||||
|
||||
if ONMYOJI_FLAG and not os.path.exists(DRAW_PATH + 'onmyoji.json'):
|
||||
tasks.append(asyncio.ensure_future(update_onmyoji_info()))
|
||||
init_lst.remove(init_onmyoji_data)
|
||||
|
||||
try:
|
||||
await asyncio.gather(*tasks)
|
||||
for func in init_lst:
|
||||
await func()
|
||||
except asyncio.exceptions.CancelledError:
|
||||
logger.info('更新异常:CancelledError,再次更新...')
|
||||
await async_update_game()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
import random
|
||||
from .update_game_simple_info import update_simple_info
|
||||
from .util import generate_img, init_star_rst, BaseData, set_list, get_star, max_card, format_card_information
|
||||
from .config import AZUR_ONE_P, AZUR_TWO_P, AZUR_THREE_P, AZUR_FOUR_P, AZUR_FLAG, DRAW_PATH
|
||||
from dataclasses import dataclass
|
||||
from .init_card_pool import init_game_pool
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
ALL_CHAR = []
|
||||
|
||||
|
||||
@dataclass
|
||||
class AzurChar(BaseData):
|
||||
itype: str # 舰娘类型
|
||||
|
||||
|
||||
async def azur_draw(count: int, pool_name: str):
|
||||
# 0 1 2
|
||||
cnlist = ['金', '紫', '蓝', '白']
|
||||
star_list = [0, 0, 0, 0]
|
||||
char_list, char_dict, max_star_list, star_list, max_star_index_list = \
|
||||
format_card_information(count, star_list, _get_azur_card, pool_name, guaranteed=False)
|
||||
rst = init_star_rst(star_list, cnlist, max_star_list, max_star_index_list)
|
||||
if count > 90:
|
||||
char_list = set_list(char_list)
|
||||
return MessageSegment.image("base64://" + await generate_img(char_list, 'azur', star_list)) \
|
||||
+ '\n' + rst[:-1] + '\n' + max_card(char_dict)
|
||||
|
||||
|
||||
async def update_azur_info():
|
||||
global ALL_CHAR
|
||||
url = 'https://wiki.biligame.com/blhx/舰娘图鉴'
|
||||
data, code = await update_simple_info(url, 'azur')
|
||||
if code == 200:
|
||||
ALL_CHAR = init_game_pool('azur', data, AzurChar)
|
||||
|
||||
|
||||
async def init_azur_data():
|
||||
global ALL_CHAR
|
||||
if AZUR_FLAG:
|
||||
with open(DRAW_PATH + 'azur.json', 'r', encoding='utf8') as f:
|
||||
azur_dict = json.load(f)
|
||||
ALL_CHAR = init_game_pool('azur', azur_dict, AzurChar)
|
||||
|
||||
|
||||
# 抽取卡池
|
||||
def _get_azur_card(pool_name: str):
|
||||
global ALL_CHAR
|
||||
if pool_name == '轻型':
|
||||
itype = ['驱逐', '轻巡', '维修']
|
||||
elif pool_name == '重型':
|
||||
itype = ['重巡', '战列', '战巡', '重炮']
|
||||
else:
|
||||
itype = ['维修', '潜艇', '重巡', '轻航', '航母']
|
||||
star = get_star([4, 3, 2, 1], [AZUR_FOUR_P, AZUR_THREE_P, AZUR_TWO_P, AZUR_ONE_P])
|
||||
chars = [x for x in ALL_CHAR if x.star == star and x.itype in itype and not x.limited]
|
||||
return random.choice(chars), 4 - star
|
||||
|
||||
Executable → Regular
+123
-367
@@ -1,7 +1,9 @@
|
||||
import nonebot
|
||||
from pathlib import Path
|
||||
from nonebot.log import logger
|
||||
from pydantic import BaseModel, Extra
|
||||
from configs.config import Config as AConfig
|
||||
from configs.path_config import DATA_PATH
|
||||
from configs.config import Config
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
@@ -9,9 +11,115 @@ except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
DRAW_PATH = DATA_PATH + "/draw_card/"
|
||||
# 原神
|
||||
class GenshinConfig(BaseModel, extra=Extra.ignore):
|
||||
GENSHIN_FIVE_P: float = 0.006
|
||||
GENSHIN_FOUR_P: float = 0.051
|
||||
GENSHIN_THREE_P: float = 0.43
|
||||
GENSHIN_G_FIVE_P: float = 0.016
|
||||
GENSHIN_G_FOUR_P: float = 0.13
|
||||
I72_ADD: float = 0.0585
|
||||
|
||||
_draw_config = Path(rf"{DRAW_PATH}/draw_card_config/draw_card_config.json")
|
||||
|
||||
# 明日方舟
|
||||
class PrtsConfig(BaseModel, extra=Extra.ignore):
|
||||
PRTS_SIX_P: float = 0.02
|
||||
PRTS_FIVE_P: float = 0.08
|
||||
PRTS_FOUR_P: float = 0.48
|
||||
PRTS_THREE_P: float = 0.42
|
||||
|
||||
|
||||
# 赛马娘
|
||||
class PrettyConfig(BaseModel, extra=Extra.ignore):
|
||||
PRETTY_THREE_P: float = 0.03
|
||||
PRETTY_TWO_P: float = 0.18
|
||||
PRETTY_ONE_P: float = 0.79
|
||||
|
||||
|
||||
# 坎公骑冠剑
|
||||
class GuardianConfig(BaseModel, extra=Extra.ignore):
|
||||
GUARDIAN_THREE_CHAR_P: float = 0.0275
|
||||
GUARDIAN_TWO_CHAR_P: float = 0.19
|
||||
GUARDIAN_ONE_CHAR_P: float = 0.7825
|
||||
GUARDIAN_THREE_CHAR_UP_P: float = 0.01375
|
||||
GUARDIAN_THREE_CHAR_OTHER_P: float = 0.01375
|
||||
GUARDIAN_EXCLUSIVE_ARMS_P: float = 0.03
|
||||
GUARDIAN_FIVE_ARMS_P: float = 0.03
|
||||
GUARDIAN_FOUR_ARMS_P: float = 0.09
|
||||
GUARDIAN_THREE_ARMS_P: float = 0.27
|
||||
GUARDIAN_TWO_ARMS_P: float = 0.58
|
||||
GUARDIAN_EXCLUSIVE_ARMS_UP_P: float = 0.01
|
||||
GUARDIAN_EXCLUSIVE_ARMS_OTHER_P: float = 0.02
|
||||
|
||||
|
||||
# 公主连结
|
||||
class PcrConfig(BaseModel, extra=Extra.ignore):
|
||||
PCR_THREE_P: float = 0.025
|
||||
PCR_TWO_P: float = 0.18
|
||||
PCR_ONE_P: float = 0.795
|
||||
PCR_G_THREE_P: float = 0.025
|
||||
PCR_G_TWO_P: float = 0.975
|
||||
|
||||
|
||||
# 碧蓝航线
|
||||
class AzurConfig(BaseModel, extra=Extra.ignore):
|
||||
AZUR_FIVE_P: float = 0.012
|
||||
AZUR_FOUR_P: float = 0.07
|
||||
AZUR_THREE_P: float = 0.12
|
||||
AZUR_TWO_P: float = 0.51
|
||||
AZUR_ONE_P: float = 0.3
|
||||
|
||||
|
||||
# 命运-冠位指定
|
||||
class FgoConfig(BaseModel, extra=Extra.ignore):
|
||||
FGO_SERVANT_FIVE_P: float = 0.01
|
||||
FGO_SERVANT_FOUR_P: float = 0.03
|
||||
FGO_SERVANT_THREE_P: float = 0.4
|
||||
FGO_CARD_FIVE_P: float = 0.04
|
||||
FGO_CARD_FOUR_P: float = 0.12
|
||||
FGO_CARD_THREE_P: float = 0.4
|
||||
|
||||
|
||||
# 阴阳师
|
||||
class OnmyojiConfig(BaseModel, extra=Extra.ignore):
|
||||
ONMYOJI_SP: float = 0.0025
|
||||
ONMYOJI_SSR: float = 0.01
|
||||
ONMYOJI_SR: float = 0.2
|
||||
ONMYOJI_R: float = 0.7875
|
||||
|
||||
|
||||
class Config(BaseModel, extra=Extra.ignore):
|
||||
# 开关
|
||||
PRTS_FLAG: bool = AConfig.get_config("draw_card", "PRTS_FLAG")
|
||||
GENSHIN_FLAG: bool = AConfig.get_config("draw_card", "GENSHIN_FLAG")
|
||||
PRETTY_FLAG: bool = AConfig.get_config("draw_card", "PRETTY_FLAG")
|
||||
GUARDIAN_FLAG: bool = AConfig.get_config("draw_card", "GUARDIAN_FLAG")
|
||||
PCR_FLAG: bool = AConfig.get_config("draw_card", "PCR_FLAG")
|
||||
AZUR_FLAG: bool = AConfig.get_config("draw_card", "AZUR_FLAG")
|
||||
FGO_FLAG: bool = AConfig.get_config("draw_card", "FGO_FLAG")
|
||||
ONMYOJI_FLAG: bool = AConfig.get_config("draw_card", "ONMYOJI_FLAG")
|
||||
|
||||
# 其他配置
|
||||
PCR_TAI: bool = AConfig.get_config("draw_card", "PCR_TAI")
|
||||
SEMAPHORE: int = AConfig.get_config("draw_card", "SEMAPHORE")
|
||||
|
||||
# 抽卡概率
|
||||
prts: PrtsConfig = PrtsConfig()
|
||||
genshin: GenshinConfig = GenshinConfig()
|
||||
pretty: PrettyConfig = PrettyConfig()
|
||||
guardian: GuardianConfig = GuardianConfig()
|
||||
pcr: PcrConfig = PcrConfig()
|
||||
azur: AzurConfig = AzurConfig()
|
||||
fgo: FgoConfig = FgoConfig()
|
||||
onmyoji: OnmyojiConfig = OnmyojiConfig()
|
||||
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
|
||||
DRAW_PATH = DATA_PATH / "draw_card"
|
||||
config_path = DRAW_PATH / "draw_card_config" / "draw_card_config.json"
|
||||
|
||||
draw_config: Config = Config()
|
||||
|
||||
|
||||
for game_flag, game_name in zip(
|
||||
@@ -28,7 +136,7 @@ for game_flag, game_name in zip(
|
||||
],
|
||||
["明日方舟", "原神", "赛马娘", "坎公骑冠剑", "公主连结", "碧蓝航线", "命运-冠位指定(FGO)", "阴阳师", "pcr台服卡池"],
|
||||
):
|
||||
Config.add_plugin_config(
|
||||
AConfig.add_plugin_config(
|
||||
"draw_card",
|
||||
game_flag,
|
||||
True,
|
||||
@@ -36,376 +144,24 @@ for game_flag, game_name in zip(
|
||||
help_=f"{game_name} 抽卡开关",
|
||||
default_value=True,
|
||||
)
|
||||
Config.add_plugin_config(
|
||||
AConfig.add_plugin_config(
|
||||
"draw_card", "SEMAPHORE", 5, help_=f"异步数据下载数量限制", default_value=5
|
||||
)
|
||||
PRTS_FLAG = Config.get_config("draw_card", "PRTS_FLAG")
|
||||
GENSHIN_FLAG = Config.get_config("draw_card", "GENSHIN_FLAG")
|
||||
PRETTY_FLAG = Config.get_config("draw_card", "PRETTY_FLAG")
|
||||
GUARDIAN_FLAG = Config.get_config("draw_card", "GUARDIAN_FLAG")
|
||||
PCR_FLAG = Config.get_config("draw_card", "PCR_FLAG")
|
||||
AZUR_FLAG = Config.get_config("draw_card", "AZUR_FLAG")
|
||||
FGO_FLAG = Config.get_config("draw_card", "FGO_FLAG")
|
||||
ONMYOJI_FLAG = Config.get_config("draw_card", "ONMYOJI_FLAG")
|
||||
|
||||
PCR_TAI = Config.get_config("draw_card", "PCR_TAI")
|
||||
SEMAPHORE = Config.get_config("draw_card", "SEMAPHORE")
|
||||
|
||||
|
||||
# 方舟概率
|
||||
PRTS_SIX_P = 0.02
|
||||
PRTS_FIVE_P = 0.08
|
||||
PRTS_FOUR_P = 0.48
|
||||
PRTS_THREE_P = 0.42
|
||||
|
||||
# 原神概率
|
||||
GENSHIN_FIVE_P = 0.006
|
||||
GENSHIN_FOUR_P = 0.051
|
||||
GENSHIN_THREE_P = 0.43
|
||||
# 保底概率
|
||||
GENSHIN_G_FIVE_P = 0.016
|
||||
GENSHIN_G_FOUR_P = 0.13
|
||||
# 72抽后增加的概率
|
||||
I72_ADD = 0.0585
|
||||
|
||||
# 赛马娘概率
|
||||
PRETTY_THREE_P = 0.03
|
||||
PRETTY_TWO_P = 0.18
|
||||
PRETTY_ONE_P = 0.79
|
||||
|
||||
# 坎公骑冠剑
|
||||
# 角色概率
|
||||
GUARDIAN_THREE_CHAR_P = 0.0275
|
||||
GUARDIAN_TWO_CHAR_P = 0.19
|
||||
GUARDIAN_ONE_CHAR_P = 0.7825
|
||||
# UP角色
|
||||
GUARDIAN_THREE_CHAR_UP_P = 0.01375
|
||||
GUARDIAN_THREE_CHAR_OTHER_P = 0.01375
|
||||
# 武器概率
|
||||
GUARDIAN_EXCLUSIVE_ARMS_P = 0.03
|
||||
GUARDIAN_FIVE_ARMS_P = 0.03
|
||||
GUARDIAN_FOUR_ARMS_P = 0.09
|
||||
GUARDIAN_THREE_ARMS_P = 0.27
|
||||
GUARDIAN_TWO_ARMS_P = 0.58
|
||||
# UP武器
|
||||
GUARDIAN_EXCLUSIVE_ARMS_UP_P = 0.01
|
||||
GUARDIAN_EXCLUSIVE_ARMS_OTHER_P = 0.02
|
||||
|
||||
# PCR
|
||||
PCR_THREE_P = 0.025
|
||||
PCR_TWO_P = 0.18
|
||||
PCR_ONE_P = 0.795
|
||||
# 保底
|
||||
PCR_G_THREE_P = 0.025
|
||||
PCR_G_TWO_P = 0.975
|
||||
|
||||
# 碧蓝航线
|
||||
AZUR_FIVE_P = 0.012
|
||||
AZUR_FOUR_P = 0.07
|
||||
AZUR_THREE_P = 0.12
|
||||
AZUR_TWO_P = 0.51
|
||||
AZUR_ONE_P = 0.3
|
||||
|
||||
# FGO
|
||||
FGO_SERVANT_FIVE_P = 0.01
|
||||
FGO_SERVANT_FOUR_P = 0.03
|
||||
FGO_SERVANT_THREE_P = 0.4
|
||||
FGO_CARD_FIVE_P = 0.04
|
||||
FGO_CARD_FOUR_P = 0.12
|
||||
FGO_CARD_THREE_P = 0.4
|
||||
|
||||
# 阴阳师
|
||||
ONMYOJI_SP = 0.0025
|
||||
ONMYOJI_SSR = 0.01
|
||||
ONMYOJI_SR = 0.2
|
||||
ONMYOJI_R = 0.7875
|
||||
|
||||
|
||||
path_dict = {
|
||||
"genshin": "原神",
|
||||
"prts": "明日方舟",
|
||||
"pretty": "赛马娘",
|
||||
"guardian": "坎公骑冠剑",
|
||||
"pcr": "公主连结",
|
||||
"azur": "碧蓝航线",
|
||||
"fgo": "命运-冠位指定",
|
||||
"onmyoji": "阴阳师",
|
||||
}
|
||||
|
||||
driver: nonebot.Driver = nonebot.get_driver()
|
||||
|
||||
config_default_data = {
|
||||
"path_dict": {
|
||||
"genshin": "原神",
|
||||
"prts": "明日方舟",
|
||||
"pretty": "赛马娘",
|
||||
"guardian": "坎公骑冠剑",
|
||||
"pcr": "公主连结",
|
||||
"azur": "碧蓝航线",
|
||||
"fgo": "命运-冠位指定",
|
||||
"onmyoji": "阴阳师",
|
||||
},
|
||||
"prts": {
|
||||
"PRTS_SIX_P": 0.02,
|
||||
"PRTS_FIVE_P": 0.08,
|
||||
"PRTS_FOUR_P": 0.48,
|
||||
"PRTS_THREE_P": 0.42,
|
||||
},
|
||||
"genshin": {
|
||||
"GENSHIN_FIVE_P": 0.006,
|
||||
"GENSHIN_FOUR_P": 0.051,
|
||||
"GENSHIN_THREE_P": 0.43,
|
||||
"GENSHIN_G_FIVE_P": 0.13,
|
||||
"GENSHIN_G_FOUR_P": 0.016,
|
||||
"I72_ADD": 0.0585,
|
||||
},
|
||||
"pretty": {
|
||||
"PRETTY_THREE_P": 0.03,
|
||||
"PRETTY_TWO_P": 0.18,
|
||||
"PRETTY_ONE_P": 0.79,
|
||||
},
|
||||
"guardian": {
|
||||
"GUARDIAN_THREE_CHAR_P": 0.0275,
|
||||
"GUARDIAN_TWO_CHAR_P": 0.19,
|
||||
"GUARDIAN_ONE_CHAR_P": 0.7825,
|
||||
"GUARDIAN_THREE_CHAR_UP_P": 0.01375,
|
||||
"GUARDIAN_THREE_CHAR_OTHER_P": 0.01375,
|
||||
"GUARDIAN_EXCLUSIVE_ARMS_P": 0.03,
|
||||
"GUARDIAN_FIVE_ARMS_P": 0.03,
|
||||
"GUARDIAN_FOUR_ARMS_P": 0.09,
|
||||
"GUARDIAN_THREE_ARMS_P": 0.27,
|
||||
"GUARDIAN_TWO_ARMS_P": 0.58,
|
||||
"GUARDIAN_EXCLUSIVE_ARMS_UP_P": 0.01,
|
||||
"GUARDIAN_EXCLUSIVE_ARMS_OTHER_P": 0.02,
|
||||
},
|
||||
"pcr": {
|
||||
"PCR_THREE_P": 0.025,
|
||||
"PCR_TWO_P": 0.18,
|
||||
"PCR_ONE_P": 0.795,
|
||||
},
|
||||
"azur": {
|
||||
"AZUR_FIVE_P": 0.012,
|
||||
"AZUR_FOUR_P": 0.07,
|
||||
"AZUR_THREE_P": 0.12,
|
||||
"AZUR_TWO_P": 0.51,
|
||||
"AZUR_ONE_P": 0.3,
|
||||
},
|
||||
"fgo": {
|
||||
"FGO_SERVANT_FIVE_P": 0.01,
|
||||
"FGO_SERVANT_FOUR_P": 0.03,
|
||||
"FGO_SERVANT_THREE_P": 0.4,
|
||||
"FGO_CARD_FIVE_P": 0.04,
|
||||
"FGO_CARD_FOUR_P": 0.12,
|
||||
"FGO_CARD_THREE_P": 0.4,
|
||||
},
|
||||
"onmyoji": {
|
||||
"ONMYOJI_SP": 0.0025,
|
||||
"ONMYOJI_SSR": 0.01,
|
||||
"ONMYOJI_SR": 0.2,
|
||||
"ONMYOJI_R": 0.7875,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
def check_config():
|
||||
global PRTS_SIX_P, PRTS_FOUR_P, PRTS_FIVE_P, PRTS_THREE_P, GENSHIN_G_FIVE_P, config_default_data, GENSHIN_G_FOUR_P, GENSHIN_FOUR_P, GENSHIN_FIVE_P, I72_ADD, path_dict, PRETTY_THREE_P, PRETTY_ONE_P, PRETTY_TWO_P, GENSHIN_THREE_P, GUARDIAN_THREE_CHAR_P, GUARDIAN_TWO_CHAR_P, GUARDIAN_ONE_CHAR_P, GUARDIAN_THREE_CHAR_UP_P, GUARDIAN_THREE_CHAR_OTHER_P, GUARDIAN_EXCLUSIVE_ARMS_P, GUARDIAN_FIVE_ARMS_P, GUARDIAN_FOUR_ARMS_P, GUARDIAN_THREE_ARMS_P, GUARDIAN_TWO_ARMS_P, GENSHIN_FLAG, PRTS_FLAG, PRETTY_FLAG, GUARDIAN_FLAG, GUARDIAN_EXCLUSIVE_ARMS_UP_P, GUARDIAN_EXCLUSIVE_ARMS_OTHER_P, DRAW_PATH, PCR_THREE_P, PCR_TWO_P, PCR_ONE_P, AZUR_FOUR_P, AZUR_THREE_P, AZUR_TWO_P, AZUR_ONE_P, AZUR_FIVE_P, FGO_CARD_FIVE_P, FGO_CARD_FOUR_P, FGO_CARD_THREE_P, FGO_SERVANT_THREE_P, FGO_SERVANT_FOUR_P, FGO_SERVANT_FIVE_P, ONMYOJI_R, ONMYOJI_SP, ONMYOJI_SSR, ONMYOJI_SR
|
||||
_draw_config.parent.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
data = json.load(open(_draw_config, "r", encoding="utf8"))
|
||||
except (FileNotFoundError, ValueError):
|
||||
_draw_config.parent.mkdir(parents=True, exist_ok=True)
|
||||
global draw_config
|
||||
draw_config = Config()
|
||||
if not config_path.exists():
|
||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
draw_config = Config()
|
||||
logger.warning("draw_card:配置文件不存在,已重新生成配置文件.....")
|
||||
|
||||
with config_path.open("w", encoding="utf8") as fp:
|
||||
json.dump(
|
||||
config_default_data,
|
||||
open(_draw_config, "w", encoding="utf8"),
|
||||
draw_config.dict(),
|
||||
fp,
|
||||
indent=4,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
print("draw_card:配置文件不存在或格式错误,已重新生成配置文件.....")
|
||||
else:
|
||||
|
||||
try:
|
||||
PRTS_SIX_P = float(data["prts"]["PRTS_SIX_P"])
|
||||
PRTS_FIVE_P = float(data["prts"]["PRTS_FIVE_P"])
|
||||
PRTS_FOUR_P = float(data["prts"]["PRTS_FOUR_P"])
|
||||
PRTS_THREE_P = float(data["prts"]["PRTS_THREE_P"])
|
||||
except KeyError:
|
||||
data["prts"] = {}
|
||||
data["prts"]["PRTS_SIX_P"] = config_default_data["prts"]["PRTS_SIX_P"]
|
||||
data["prts"]["PRTS_FIVE_P"] = config_default_data["prts"]["PRTS_FIVE_P"]
|
||||
data["prts"]["PRTS_FOUR_P"] = config_default_data["prts"]["PRTS_FOUR_P"]
|
||||
data["prts"]["PRTS_THREE_P"] = config_default_data["prts"]["PRTS_THREE_P"]
|
||||
|
||||
try:
|
||||
GENSHIN_FIVE_P = float(data["genshin"]["GENSHIN_FIVE_P"])
|
||||
GENSHIN_FOUR_P = float(data["genshin"]["GENSHIN_FOUR_P"])
|
||||
GENSHIN_THREE_P = float(data["genshin"]["GENSHIN_THREE_P"])
|
||||
GENSHIN_G_FIVE_P = float(data["genshin"]["GENSHIN_G_FIVE_P"])
|
||||
GENSHIN_G_FOUR_P = float(data["genshin"]["GENSHIN_G_FOUR_P"])
|
||||
I72_ADD = float(data["genshin"]["I72_ADD"])
|
||||
except KeyError:
|
||||
data["genshin"] = {}
|
||||
data["genshin"]["GENSHIN_FIVE_P"] = config_default_data["genshin"][
|
||||
"GENSHIN_FIVE_P"
|
||||
]
|
||||
data["genshin"]["GENSHIN_FOUR_P"] = config_default_data["genshin"][
|
||||
"GENSHIN_FOUR_P"
|
||||
]
|
||||
data["genshin"]["GENSHIN_THREE_P"] = config_default_data["genshin"][
|
||||
"GENSHIN_THREE_P"
|
||||
]
|
||||
data["genshin"]["GENSHIN_G_FIVE_P"] = config_default_data["genshin"][
|
||||
"GENSHIN_G_FIVE_P"
|
||||
]
|
||||
data["genshin"]["GENSHIN_G_FOUR_P"] = config_default_data["genshin"][
|
||||
"GENSHIN_G_FOUR_P"
|
||||
]
|
||||
data["genshin"]["I72_ADD"] = config_default_data["genshin"]["I72_ADD"]
|
||||
|
||||
try:
|
||||
PRETTY_THREE_P = float(data["pretty"]["PRETTY_THREE_P"])
|
||||
PRETTY_TWO_P = float(data["pretty"]["PRETTY_TWO_P"])
|
||||
PRETTY_ONE_P = float(data["pretty"]["PRETTY_ONE_P"])
|
||||
except KeyError:
|
||||
data["pretty"] = {}
|
||||
data["pretty"]["PRETTY_THREE_P"] = config_default_data["pretty"][
|
||||
"PRETTY_THREE_P"
|
||||
]
|
||||
data["pretty"]["PRETTY_TWO_P"] = config_default_data["pretty"][
|
||||
"PRETTY_TWO_P"
|
||||
]
|
||||
data["pretty"]["PRETTY_ONE_P"] = config_default_data["pretty"][
|
||||
"PRETTY_ONE_P"
|
||||
]
|
||||
|
||||
try:
|
||||
GUARDIAN_THREE_CHAR_P = float(data["guardian"]["GUARDIAN_THREE_CHAR_P"])
|
||||
GUARDIAN_TWO_CHAR_P = float(data["guardian"]["GUARDIAN_TWO_CHAR_P"])
|
||||
GUARDIAN_ONE_CHAR_P = float(data["guardian"]["GUARDIAN_ONE_CHAR_P"])
|
||||
GUARDIAN_THREE_CHAR_UP_P = float(
|
||||
data["guardian"]["GUARDIAN_THREE_CHAR_UP_P"]
|
||||
)
|
||||
GUARDIAN_THREE_CHAR_OTHER_P = float(
|
||||
data["guardian"]["GUARDIAN_THREE_CHAR_OTHER_P"]
|
||||
)
|
||||
GUARDIAN_EXCLUSIVE_ARMS_P = float(
|
||||
data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_P"]
|
||||
)
|
||||
GUARDIAN_FIVE_ARMS_P = float(data["guardian"]["GUARDIAN_FIVE_ARMS_P"])
|
||||
GUARDIAN_FOUR_ARMS_P = float(data["guardian"]["GUARDIAN_FOUR_ARMS_P"])
|
||||
GUARDIAN_THREE_ARMS_P = float(data["guardian"]["GUARDIAN_THREE_ARMS_P"])
|
||||
GUARDIAN_TWO_ARMS_P = float(data["guardian"]["GUARDIAN_TWO_ARMS_P"])
|
||||
GUARDIAN_EXCLUSIVE_ARMS_UP_P = float(
|
||||
data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_UP_P"]
|
||||
)
|
||||
GUARDIAN_EXCLUSIVE_ARMS_OTHER_P = float(
|
||||
data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_OTHER_P"]
|
||||
)
|
||||
except KeyError:
|
||||
data["guardian"] = {}
|
||||
data["guardian"]["GUARDIAN_THREE_CHAR_P"] = config_default_data["guardian"][
|
||||
"GUARDIAN_THREE_CHAR_P"
|
||||
]
|
||||
data["guardian"]["GUARDIAN_TWO_CHAR_P"] = config_default_data["guardian"][
|
||||
"GUARDIAN_TWO_CHAR_P"
|
||||
]
|
||||
data["guardian"]["GUARDIAN_ONE_CHAR_P"] = config_default_data["guardian"][
|
||||
"GUARDIAN_ONE_CHAR_P"
|
||||
]
|
||||
data["guardian"]["GUARDIAN_THREE_CHAR_UP_P"] = config_default_data[
|
||||
"guardian"
|
||||
]["GUARDIAN_THREE_CHAR_UP_P"]
|
||||
data["guardian"]["GUARDIAN_THREE_CHAR_OTHER_P"] = config_default_data[
|
||||
"guardian"
|
||||
]["GUARDIAN_THREE_CHAR_OTHER_P"]
|
||||
data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_P"] = config_default_data[
|
||||
"guardian"
|
||||
]["GUARDIAN_EXCLUSIVE_ARMS_P"]
|
||||
data["guardian"]["GUARDIAN_FIVE_ARMS_P"] = config_default_data["guardian"][
|
||||
"GUARDIAN_FIVE_ARMS_P"
|
||||
]
|
||||
data["guardian"]["GUARDIAN_FOUR_ARMS_P"] = config_default_data["guardian"][
|
||||
"GUARDIAN_FOUR_ARMS_P"
|
||||
]
|
||||
data["guardian"]["GUARDIAN_THREE_ARMS_P"] = config_default_data["guardian"][
|
||||
"GUARDIAN_THREE_ARMS_P"
|
||||
]
|
||||
data["guardian"]["GUARDIAN_TWO_ARMS_P"] = config_default_data["guardian"][
|
||||
"GUARDIAN_TWO_ARMS_P"
|
||||
]
|
||||
data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_UP_P"] = config_default_data[
|
||||
"guardian"
|
||||
]["GUARDIAN_EXCLUSIVE_ARMS_UP_P"]
|
||||
data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_OTHER_P"] = config_default_data[
|
||||
"guardian"
|
||||
]["GUARDIAN_EXCLUSIVE_ARMS_OTHER_P"]
|
||||
|
||||
try:
|
||||
PCR_THREE_P = float(data["pcr"]["PCR_THREE_P"])
|
||||
PCR_TWO_P = float(data["pcr"]["PCR_TWO_P"])
|
||||
PCR_ONE_P = float(data["pcr"]["PCR_ONE_P"])
|
||||
except KeyError:
|
||||
data["pcr"] = {}
|
||||
data["pcr"]["PCR_THREE_P"] = config_default_data["pcr"]["PCR_THREE_P"]
|
||||
data["pcr"]["PCR_TWO_P"] = config_default_data["pcr"]["PCR_TWO_P"]
|
||||
data["pcr"]["PCR_ONE_P"] = config_default_data["pcr"]["PCR_ONE_P"]
|
||||
|
||||
try:
|
||||
AZUR_FIVE_P = float(data["azur"]["AZUR_FIVE_P"])
|
||||
AZUR_FOUR_P = float(data["azur"]["AZUR_FOUR_P"])
|
||||
AZUR_THREE_P = float(data["azur"]["AZUR_THREE_P"])
|
||||
AZUR_TWO_P = float(data["azur"]["AZUR_TWO_P"])
|
||||
AZUR_ONE_P = float(data["azur"]["AZUR_ONE_P"])
|
||||
except KeyError:
|
||||
data["azur"] = {}
|
||||
data["azur"]["AZUR_FIVE_P"] = config_default_data["azur"]["AZUR_FIVE_P"]
|
||||
data["azur"]["AZUR_FOUR_P"] = config_default_data["azur"]["AZUR_FOUR_P"]
|
||||
data["azur"]["AZUR_THREE_P"] = config_default_data["azur"]["AZUR_THREE_P"]
|
||||
data["azur"]["AZUR_TWO_P"] = config_default_data["azur"]["AZUR_TWO_P"]
|
||||
data["azur"]["AZUR_ONE_P"] = config_default_data["azur"]["AZUR_ONE_P"]
|
||||
|
||||
try:
|
||||
FGO_SERVANT_FIVE_P = float(data["fgo"]["FGO_SERVANT_FIVE_P"])
|
||||
FGO_SERVANT_FOUR_P = float(data["fgo"]["FGO_SERVANT_FOUR_P"])
|
||||
FGO_SERVANT_THREE_P = float(data["fgo"]["FGO_SERVANT_THREE_P"])
|
||||
FGO_CARD_FIVE_P = float(data["fgo"]["FGO_CARD_FIVE_P"])
|
||||
FGO_CARD_FOUR_P = float(data["fgo"]["FGO_CARD_FOUR_P"])
|
||||
FGO_CARD_THREE_P = float(data["fgo"]["FGO_CARD_THREE_P"])
|
||||
except KeyError:
|
||||
data["fgo"] = {}
|
||||
data["fgo"]["FGO_SERVANT_FIVE_P"] = config_default_data["fgo"][
|
||||
"FGO_SERVANT_FIVE_P"
|
||||
]
|
||||
data["fgo"]["FGO_SERVANT_FOUR_P"] = config_default_data["fgo"][
|
||||
"FGO_SERVANT_FOUR_P"
|
||||
]
|
||||
data["fgo"]["FGO_SERVANT_THREE_P"] = config_default_data["fgo"][
|
||||
"FGO_SERVANT_THREE_P"
|
||||
]
|
||||
data["fgo"]["FGO_CARD_FIVE_P"] = config_default_data["fgo"][
|
||||
"FGO_CARD_FIVE_P"
|
||||
]
|
||||
data["fgo"]["FGO_CARD_FOUR_P"] = config_default_data["fgo"][
|
||||
"FGO_CARD_FOUR_P"
|
||||
]
|
||||
data["fgo"]["FGO_CARD_THREE_P"] = config_default_data["fgo"][
|
||||
"FGO_CARD_THREE_P"
|
||||
]
|
||||
|
||||
try:
|
||||
ONMYOJI_SP = float(data["onmyoji"]["ONMYOJI_SP"])
|
||||
ONMYOJI_SSR = float(data["onmyoji"]["ONMYOJI_SSR"])
|
||||
ONMYOJI_SR = float(data["onmyoji"]["ONMYOJI_SR"])
|
||||
ONMYOJI_R = float(data["onmyoji"]["ONMYOJI_R"])
|
||||
except KeyError:
|
||||
data["onmyoji"] = {}
|
||||
data["onmyoji"]["ONMYOJI_SP"] = config_default_data["onmyoji"]["ONMYOJI_SP"]
|
||||
data["onmyoji"]["ONMYOJI_SSR"] = config_default_data["onmyoji"][
|
||||
"ONMYOJI_SSR"
|
||||
]
|
||||
data["onmyoji"]["ONMYOJI_SR"] = config_default_data["onmyoji"]["ONMYOJI_SR"]
|
||||
data["onmyoji"]["ONMYOJI_R"] = config_default_data["onmyoji"]["ONMYOJI_R"]
|
||||
|
||||
json.dump(
|
||||
data, open(_draw_config, "w", encoding="utf8"), indent=4, ensure_ascii=False
|
||||
)
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
import time
|
||||
|
||||
|
||||
class BaseUserCount(BaseModel):
|
||||
count: int = 1 # 当前抽卡次数
|
||||
time_: int = time.time() # 抽卡时间,当超过一定时间时将重置抽卡次数
|
||||
timeout: int = 60 # 超时时间60秒
|
||||
|
||||
|
||||
class DrawCountManager:
|
||||
"""
|
||||
抽卡统计保底
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, game_draw_count_rule: tuple, star2name: tuple, max_draw_count: int
|
||||
):
|
||||
"""
|
||||
初始化保底统计
|
||||
|
||||
例如:DrawCountManager((10, 90, 180), ("4", "5", "5"))
|
||||
|
||||
抽卡保底需要的次数和返回的对应名称,例如星级等
|
||||
|
||||
:param game_draw_count_rule:抽卡规则
|
||||
:param star2name:星级对应的名称
|
||||
:param max_draw_count:最大累计抽卡次数,当下次单次抽卡超过该次数时将会清空数据
|
||||
|
||||
"""
|
||||
# 只有保底
|
||||
self._data = {}
|
||||
self._guarantee_tuple = game_draw_count_rule
|
||||
self._star2name = star2name
|
||||
self._max_draw_count = max_draw_count
|
||||
|
||||
def increase(self, key: int, value: int = 1):
|
||||
"""
|
||||
用户抽卡次数加1
|
||||
"""
|
||||
if self._data.get(key) is None:
|
||||
self._data[key] = BaseUserCount()
|
||||
else:
|
||||
self._data[key].count += 1
|
||||
|
||||
def get_max_guarantee(self):
|
||||
"""
|
||||
获取最大保底抽卡次数
|
||||
"""
|
||||
return self._guarantee_tuple[-1]
|
||||
|
||||
def get_user_count(self, key: int) -> int:
|
||||
"""
|
||||
获取当前抽卡次数
|
||||
"""
|
||||
return self._data[key].count
|
||||
|
||||
def update_time(self, key: int):
|
||||
"""
|
||||
更新抽卡时间
|
||||
"""
|
||||
self._data[key].time_ = time.time()
|
||||
|
||||
def reset(self, key: int):
|
||||
"""
|
||||
清空记录
|
||||
"""
|
||||
del self._data[key]
|
||||
|
||||
|
||||
class GenshinCountManager(DrawCountManager):
|
||||
class UserCount(BaseUserCount):
|
||||
five_index: int = 0 # 获取五星时的抽卡次数
|
||||
four_index: int = 0 # 获取四星时的抽卡次数
|
||||
is_up: bool = False # 下次五星是否必定为up
|
||||
|
||||
def increase(self, key: int, value: int = 1):
|
||||
"""
|
||||
用户抽卡次数加1
|
||||
"""
|
||||
if self._data.get(key) is None:
|
||||
self._data[key] = self.UserCount()
|
||||
else:
|
||||
self._data[key].count += 1
|
||||
|
||||
def set_is_up(self, key: int, value: bool):
|
||||
"""
|
||||
设置下次是否必定up
|
||||
"""
|
||||
self._data[key].is_up = value
|
||||
|
||||
def is_up(self, key: int) -> bool:
|
||||
"""
|
||||
判断该次保底是否必定为up
|
||||
"""
|
||||
return self._data[key].is_up
|
||||
|
||||
def get_user_five_index(self, key: int) -> int:
|
||||
"""
|
||||
获取用户上次获取五星的次数
|
||||
"""
|
||||
return self._data[key].five_index
|
||||
|
||||
def get_user_four_index(self, key: int) -> int:
|
||||
"""
|
||||
获取用户上次获取四星的次数
|
||||
"""
|
||||
return self._data[key].four_index
|
||||
|
||||
def mark_five_index(self, key: int):
|
||||
"""
|
||||
标记用户该次次数为五星
|
||||
"""
|
||||
self._data[key].five_index = self._data[key].count
|
||||
|
||||
def mark_four_index(self, key: int):
|
||||
"""
|
||||
标记用户该次次数为四星
|
||||
"""
|
||||
self._data[key].four_index = self._data[key].count
|
||||
|
||||
def check_timeout(self, key: int):
|
||||
"""
|
||||
检查用户距离上次抽卡是否超时
|
||||
"""
|
||||
if key in self._data.keys() and self._is_timeout(key):
|
||||
del self._data[key]
|
||||
|
||||
def check_count(self, key: int, count: int):
|
||||
"""
|
||||
检查用户该次抽卡次数累计是否超过最大限制次数
|
||||
"""
|
||||
if (
|
||||
key in self._data.keys()
|
||||
and self._data[key].count + count > self._max_draw_count
|
||||
):
|
||||
del self._data[key]
|
||||
|
||||
def _is_timeout(self, key: int) -> bool:
|
||||
return time.time() - self._data[key].time_ > self._data[key].timeout
|
||||
|
||||
def get_user_guarantee_count(self, key: int) -> int:
|
||||
return (
|
||||
self.get_max_guarantee()
|
||||
- (
|
||||
(
|
||||
self._data[key].count % self.get_max_guarantee()
|
||||
if self._data[key].count > 0
|
||||
else 0
|
||||
)
|
||||
- self._data[key].five_index
|
||||
)
|
||||
) % self.get_max_guarantee() or self.get_max_guarantee()
|
||||
|
||||
def check(self, key: int) -> Optional[int]:
|
||||
"""
|
||||
是否保底
|
||||
"""
|
||||
# print(self._data)
|
||||
user: GenshinCountManager.UserCount = self._data[key]
|
||||
if user.count - user.five_index == 90:
|
||||
user.five_index = 90
|
||||
return 5
|
||||
if user.count - user.four_index == 10:
|
||||
user.four_index = user.count
|
||||
return 4
|
||||
return None
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
import random
|
||||
from .update_game_requests_info import update_requests_info
|
||||
from .util import generate_img, init_star_rst, BaseData, set_list, get_star, max_card
|
||||
from .config import FGO_CARD_FOUR_P, FGO_CARD_FIVE_P, FGO_CARD_THREE_P, FGO_SERVANT_THREE_P, \
|
||||
FGO_SERVANT_FIVE_P, FGO_SERVANT_FOUR_P, FGO_FLAG, DRAW_PATH
|
||||
from dataclasses import dataclass
|
||||
from .init_card_pool import init_game_pool
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
ALL_CHAR = []
|
||||
ALL_CARD = []
|
||||
|
||||
|
||||
@dataclass
|
||||
class FgoChar(BaseData):
|
||||
pass
|
||||
|
||||
|
||||
async def fgo_draw(count: int):
|
||||
# 0 1 2
|
||||
cnlist = ['★★★★★', '★★★★', '★★★']
|
||||
obj_list, obj_dict, max_star_list, star_list, max_star_index_list = _format_card_information(count)
|
||||
rst = init_star_rst(star_list, cnlist, max_star_list, max_star_index_list)
|
||||
if count > 90:
|
||||
obj_list = set_list(obj_list)
|
||||
return MessageSegment.image("base64://" + await generate_img(obj_list, 'fgo', star_list)) \
|
||||
+ '\n' + rst[:-1] + '\n' + max_card(obj_dict)
|
||||
|
||||
|
||||
async def update_fgo_info():
|
||||
global ALL_CHAR, ALL_CARD
|
||||
data, code = await update_requests_info('fgo')
|
||||
if code == 200:
|
||||
ALL_CHAR = init_game_pool('fgo', data, FgoChar)
|
||||
data, code = await update_requests_info('fgo_card')
|
||||
if code == 200:
|
||||
ALL_CARD = init_game_pool('fgo_card', data, FgoChar)
|
||||
|
||||
|
||||
async def init_fgo_data():
|
||||
global ALL_CHAR, ALL_CARD
|
||||
if FGO_FLAG:
|
||||
with open(DRAW_PATH + 'fgo.json', 'r', encoding='utf8') as f:
|
||||
fgo_dict = json.load(f)
|
||||
ALL_CHAR = init_game_pool('fgo', fgo_dict, FgoChar)
|
||||
with open(DRAW_PATH + 'fgo_card.json', 'r', encoding='utf8') as f:
|
||||
fgo_dict = json.load(f)
|
||||
ALL_CARD = init_game_pool('fgo', fgo_dict, FgoChar)
|
||||
|
||||
|
||||
# 抽取卡池
|
||||
def _get_fgo_card(mode: int = 1):
|
||||
global ALL_CHAR, ALL_CARD
|
||||
if mode == 1:
|
||||
star = get_star([8, 7, 6, 5, 4, 3], [FGO_SERVANT_FIVE_P, FGO_SERVANT_FOUR_P, FGO_SERVANT_THREE_P,
|
||||
FGO_CARD_FIVE_P, FGO_CARD_FOUR_P, FGO_CARD_THREE_P])
|
||||
elif mode == 2:
|
||||
star = get_star([5, 4], [FGO_CARD_FIVE_P, FGO_CARD_FOUR_P])
|
||||
else:
|
||||
star = get_star([8, 7, 6], [FGO_SERVANT_FIVE_P, FGO_SERVANT_FOUR_P, FGO_SERVANT_THREE_P])
|
||||
if star > 5:
|
||||
itype = 'servant'
|
||||
star -= 3
|
||||
chars = [x for x in ALL_CHAR if x.star == star if not x.limited]
|
||||
else:
|
||||
itype = 'card'
|
||||
chars = [x for x in ALL_CARD if x.star == star if not x.limited]
|
||||
return random.choice(chars), 5 - star, itype
|
||||
|
||||
|
||||
# 整理数据
|
||||
def _format_card_information(count: int):
|
||||
max_star_lst = [] # 获取的最高星级角色列表
|
||||
max_index_lst = [] # 获取最高星级角色的次数
|
||||
star_list = [0, 0, 0]
|
||||
obj_list = [] # 获取所有角色
|
||||
obj_dict = {} # 获取角色次数字典
|
||||
servant_count = 0 # 保底计算
|
||||
card_count = 0 # 保底计算
|
||||
for i in range(count):
|
||||
servant_count += 1
|
||||
card_count += 1
|
||||
# 四星卡片保底
|
||||
if card_count == 9:
|
||||
obj, code, itype = _get_fgo_card(2)
|
||||
# 三星从者保底
|
||||
elif servant_count == 10:
|
||||
obj, code, itype = _get_fgo_card(3)
|
||||
_count = 0
|
||||
# 普通抽
|
||||
else:
|
||||
obj, code, itype = _get_fgo_card()
|
||||
star_list[code] += 1
|
||||
if itype == 'card' and code < 2:
|
||||
card_count = 0
|
||||
if itype == 'servant':
|
||||
servant_count = 0
|
||||
if code == 0:
|
||||
max_star_lst.append(obj.name)
|
||||
max_index_lst.append(i)
|
||||
try:
|
||||
obj_dict[obj.name] += 1
|
||||
except KeyError:
|
||||
obj_dict[obj.name] = 1
|
||||
obj_list.append(obj)
|
||||
return obj_list, obj_dict, max_star_lst, star_list, max_index_lst
|
||||
@@ -1,277 +0,0 @@
|
||||
import os
|
||||
from nonebot.adapters.cqhttp import MessageSegment, Message
|
||||
import random
|
||||
from .update_game_info import update_info
|
||||
from .util import (
|
||||
generate_img,
|
||||
init_star_rst,
|
||||
BaseData,
|
||||
set_list,
|
||||
get_star,
|
||||
init_up_char,
|
||||
)
|
||||
from .config import (
|
||||
GENSHIN_FIVE_P,
|
||||
GENSHIN_FOUR_P,
|
||||
GENSHIN_G_FIVE_P,
|
||||
GENSHIN_G_FOUR_P,
|
||||
GENSHIN_THREE_P,
|
||||
I72_ADD,
|
||||
DRAW_PATH,
|
||||
GENSHIN_FLAG,
|
||||
)
|
||||
from dataclasses import dataclass
|
||||
from .init_card_pool import init_game_pool
|
||||
from .announcement import GenshinAnnouncement
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
announcement = GenshinAnnouncement()
|
||||
|
||||
genshin_five = {}
|
||||
genshin_count = {}
|
||||
genshin_pl_count = {}
|
||||
|
||||
ALL_CHAR = []
|
||||
ALL_ARMS = []
|
||||
|
||||
UP_CHAR = []
|
||||
UP_ARMS = []
|
||||
|
||||
_CURRENT_CHAR_POOL_TITLE = ""
|
||||
_CURRENT_ARMS_POOL_TITLE = ""
|
||||
POOL_IMG = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class GenshinChar(BaseData):
|
||||
pass
|
||||
|
||||
|
||||
async def genshin_draw(user_id: int, count: int, pool_name: str):
|
||||
# 0 1 2
|
||||
cnlist = ["★★★★★", "★★★★", "★★★"]
|
||||
(
|
||||
char_list,
|
||||
five_list,
|
||||
five_index_list,
|
||||
char_dict,
|
||||
star_list,
|
||||
) = _format_card_information(count, user_id, pool_name)
|
||||
temp = ""
|
||||
title = ""
|
||||
up_type = []
|
||||
up_list = []
|
||||
if pool_name == "char" and _CURRENT_CHAR_POOL_TITLE:
|
||||
up_type = UP_CHAR
|
||||
title = _CURRENT_CHAR_POOL_TITLE
|
||||
elif pool_name == "arms" and _CURRENT_ARMS_POOL_TITLE:
|
||||
up_type = UP_ARMS
|
||||
title = _CURRENT_ARMS_POOL_TITLE
|
||||
tmp = ""
|
||||
if up_type:
|
||||
for x in up_type:
|
||||
for operator in x.operators:
|
||||
up_list.append(operator)
|
||||
if x.star == 5:
|
||||
tmp += f'五星UP:{" ".join(x.operators)} \n'
|
||||
elif x.star == 4:
|
||||
tmp += f'四星UP:{" ".join(x.operators)}'
|
||||
rst = init_star_rst(star_list, cnlist, five_list, five_index_list, up_list)
|
||||
pool_info = f"当前up池:{title}\n{tmp}" if title else ""
|
||||
if count > 90:
|
||||
char_list = set_list(char_list)
|
||||
return (
|
||||
pool_info
|
||||
+ "\n"
|
||||
+ MessageSegment.image(
|
||||
"base64://" + await generate_img(char_list, "genshin", star_list)
|
||||
)
|
||||
+ "\n"
|
||||
+ rst[:-1]
|
||||
+ temp[:-1]
|
||||
+ f'\n距离保底发还剩 {90 - genshin_count[user_id] if genshin_count.get(user_id) else "^"} 抽'
|
||||
+ "\n【五星:0.6%,四星:5.1%\n第72抽开始五星概率每抽加0.585%】"
|
||||
)
|
||||
|
||||
|
||||
async def update_genshin_info():
|
||||
global ALL_CHAR, ALL_ARMS
|
||||
url = "https://wiki.biligame.com/ys/角色筛选"
|
||||
data, code = await update_info(url, "genshin")
|
||||
if code == 200:
|
||||
ALL_CHAR = init_game_pool("genshin", data, GenshinChar)
|
||||
url = "https://wiki.biligame.com/ys/武器图鉴"
|
||||
data, code = await update_info(
|
||||
url,
|
||||
"genshin_arms",
|
||||
[
|
||||
"头像",
|
||||
"名称",
|
||||
"类型",
|
||||
"稀有度.alt",
|
||||
"获取途径",
|
||||
"初始基础属性1",
|
||||
"初始基础属性2",
|
||||
"攻击力(MAX)",
|
||||
"副属性(MAX)",
|
||||
"技能",
|
||||
],
|
||||
)
|
||||
if code == 200:
|
||||
ALL_ARMS = init_game_pool("genshin_arms", data, GenshinChar)
|
||||
await _genshin_init_up_char()
|
||||
|
||||
|
||||
async def init_genshin_data():
|
||||
global ALL_CHAR, ALL_ARMS
|
||||
if GENSHIN_FLAG:
|
||||
if not os.path.exists(DRAW_PATH + "genshin.json") or not os.path.exists(
|
||||
DRAW_PATH + "genshin_arms.json"
|
||||
):
|
||||
await update_genshin_info()
|
||||
else:
|
||||
with open(DRAW_PATH + "genshin.json", "r", encoding="utf8") as f:
|
||||
genshin_dict = json.load(f)
|
||||
with open(DRAW_PATH + "genshin_arms.json", "r", encoding="utf8") as f:
|
||||
genshin_ARMS_dict = json.load(f)
|
||||
ALL_CHAR = init_game_pool("genshin", genshin_dict, GenshinChar)
|
||||
ALL_ARMS = init_game_pool("genshin_arms", genshin_ARMS_dict, GenshinChar)
|
||||
await _genshin_init_up_char()
|
||||
|
||||
|
||||
# 抽取卡池
|
||||
def _get_genshin_card(mode: int = 1, pool_name: str = "", add: float = 0.0):
|
||||
global ALL_ARMS, ALL_CHAR, UP_ARMS, UP_CHAR, _CURRENT_ARMS_POOL_TITLE, _CURRENT_CHAR_POOL_TITLE
|
||||
if mode == 1:
|
||||
star = get_star(
|
||||
[5, 4, 3], [GENSHIN_FIVE_P + add, GENSHIN_FOUR_P, GENSHIN_THREE_P]
|
||||
)
|
||||
elif mode == 2:
|
||||
star = get_star([5, 4], [GENSHIN_G_FIVE_P + add, GENSHIN_G_FOUR_P])
|
||||
else:
|
||||
star = 5
|
||||
if pool_name == "char":
|
||||
data_lst = UP_CHAR
|
||||
flag = _CURRENT_CHAR_POOL_TITLE
|
||||
itype_all_lst = ALL_CHAR + [
|
||||
x for x in ALL_ARMS if x.star == star and x.star < 5
|
||||
]
|
||||
elif pool_name == "arms":
|
||||
data_lst = UP_ARMS
|
||||
flag = _CURRENT_ARMS_POOL_TITLE
|
||||
itype_all_lst = ALL_ARMS + [
|
||||
x for x in ALL_CHAR if x.star == star and x.star < 5
|
||||
]
|
||||
else:
|
||||
data_lst = ""
|
||||
flag = ""
|
||||
itype_all_lst = ""
|
||||
all_lst = ALL_ARMS + ALL_CHAR
|
||||
# 是否UP
|
||||
try:
|
||||
if flag and star > 3 and pool_name:
|
||||
# 获取up角色列表
|
||||
up_char_lst = [x.operators for x in data_lst if x.star == star][0]
|
||||
print(up_char_lst)
|
||||
# 成功获取up角色
|
||||
if random.random() < 0.5:
|
||||
up_char_name = random.choice(up_char_lst)
|
||||
acquire_char = [x for x in all_lst if x.name == up_char_name][0]
|
||||
else:
|
||||
# 无up
|
||||
all_char_lst = [
|
||||
x
|
||||
for x in itype_all_lst
|
||||
if x.star == star and x.name not in up_char_lst and not x.limited
|
||||
]
|
||||
acquire_char = random.choice(all_char_lst)
|
||||
else:
|
||||
chars = [x for x in all_lst if x.star == star and not x.limited]
|
||||
acquire_char = random.choice(chars)
|
||||
except IndexError:
|
||||
chars = [x for x in all_lst if x.star == star and not x.limited]
|
||||
acquire_char = random.choice(chars)
|
||||
return acquire_char, 5 - star
|
||||
|
||||
|
||||
def _format_card_information(_count: int, user_id, pool_name):
|
||||
char_list = []
|
||||
star_list = [0, 0, 0]
|
||||
five_index_list = []
|
||||
five_list = []
|
||||
five_dict = {}
|
||||
_start_add_count = 72 if pool_name == "char" else 62
|
||||
_x = 90 if pool_name == "char" else 80 # 保底
|
||||
add = 0.0
|
||||
if genshin_count.get(user_id) and _count <= _x:
|
||||
f_count = genshin_count[user_id]
|
||||
else:
|
||||
f_count = 0
|
||||
if genshin_pl_count.get(user_id) and _count <= _x:
|
||||
count = genshin_pl_count[user_id]
|
||||
else:
|
||||
count = 0
|
||||
for i in range(_count):
|
||||
count += 1
|
||||
f_count += 1
|
||||
# 十连保底
|
||||
if count == 10 and f_count != _x:
|
||||
if f_count >= _start_add_count:
|
||||
add += I72_ADD
|
||||
char, code = _get_genshin_card(2, pool_name, add=add)
|
||||
count = 0
|
||||
# 大保底
|
||||
elif f_count == _x:
|
||||
char, code = _get_genshin_card(3, pool_name)
|
||||
else:
|
||||
if f_count >= _start_add_count:
|
||||
add += I72_ADD
|
||||
char, code = _get_genshin_card(pool_name=pool_name, add=add)
|
||||
if code == 1:
|
||||
count = 0
|
||||
star_list[code] += 1
|
||||
if code == 0:
|
||||
if _count <= _x:
|
||||
genshin_five[user_id] = f_count
|
||||
add = 0.0
|
||||
f_count = 0
|
||||
five_list.append(char.name)
|
||||
five_index_list.append(i)
|
||||
try:
|
||||
five_dict[char.name] += 1
|
||||
except KeyError:
|
||||
five_dict[char.name] = 1
|
||||
char_list.append(char)
|
||||
if _count <= _x:
|
||||
genshin_count[user_id] = f_count
|
||||
genshin_pl_count[user_id] = count
|
||||
return char_list, five_list, five_index_list, five_dict, star_list
|
||||
|
||||
|
||||
def reset_count(user_id: int):
|
||||
genshin_count[user_id] = 0
|
||||
genshin_pl_count[user_id] = 0
|
||||
|
||||
|
||||
# 获取up和概率
|
||||
async def _genshin_init_up_char():
|
||||
global _CURRENT_CHAR_POOL_TITLE, _CURRENT_ARMS_POOL_TITLE, UP_CHAR, UP_ARMS, POOL_IMG
|
||||
(
|
||||
_CURRENT_CHAR_POOL_TITLE,
|
||||
_CURRENT_ARMS_POOL_TITLE,
|
||||
POOL_IMG,
|
||||
UP_CHAR,
|
||||
UP_ARMS,
|
||||
) = await init_up_char(announcement)
|
||||
|
||||
|
||||
async def reload_genshin_pool():
|
||||
await _genshin_init_up_char()
|
||||
return Message(
|
||||
f"当前UP池子:{_CURRENT_CHAR_POOL_TITLE} & {_CURRENT_ARMS_POOL_TITLE} {POOL_IMG}"
|
||||
)
|
||||
@@ -1,160 +0,0 @@
|
||||
|
||||
import os
|
||||
from nonebot.adapters.cqhttp import MessageSegment, Message
|
||||
from .update_game_info import update_info
|
||||
from .announcement import GuardianAnnouncement
|
||||
from .util import init_star_rst, generate_img, max_card, BaseData,\
|
||||
set_list, get_star, format_card_information, init_up_char
|
||||
import random
|
||||
from .config import DRAW_PATH, GUARDIAN_ONE_CHAR_P, GUARDIAN_TWO_CHAR_P, GUARDIAN_THREE_CHAR_P, \
|
||||
GUARDIAN_THREE_CHAR_UP_P, GUARDIAN_TWO_ARMS_P, GUARDIAN_FIVE_ARMS_P, GUARDIAN_THREE_CHAR_OTHER_P, \
|
||||
GUARDIAN_FOUR_ARMS_P, GUARDIAN_THREE_ARMS_P, GUARDIAN_EXCLUSIVE_ARMS_P, GUARDIAN_EXCLUSIVE_ARMS_UP_P, \
|
||||
GUARDIAN_EXCLUSIVE_ARMS_OTHER_P, GUARDIAN_FLAG
|
||||
from dataclasses import dataclass
|
||||
from .init_card_pool import init_game_pool
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
announcement = GuardianAnnouncement()
|
||||
|
||||
ALL_CHAR = []
|
||||
ALL_ARMS = []
|
||||
|
||||
_CURRENT_CHAR_POOL_TITLE = ''
|
||||
_CURRENT_ARMS_POOL_TITLE = ''
|
||||
UP_CHAR = []
|
||||
UP_ARMS = []
|
||||
POOL_IMG = ''
|
||||
|
||||
|
||||
@dataclass
|
||||
class GuardianChar(BaseData):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class GuardianArms(BaseData):
|
||||
pass
|
||||
|
||||
|
||||
async def guardian_draw(count: int, pool_name):
|
||||
if pool_name == 'arms':
|
||||
cnlist = ['★★★★★', '★★★★', '★★★', '★★']
|
||||
star_list = [0, 0, 0, 0]
|
||||
else:
|
||||
cnlist = ['★★★', '★★', '★']
|
||||
star_list = [0, 0, 0]
|
||||
title = ''
|
||||
up_type = []
|
||||
up_list = []
|
||||
if pool_name == 'char' and _CURRENT_CHAR_POOL_TITLE:
|
||||
up_type = UP_CHAR
|
||||
title = _CURRENT_CHAR_POOL_TITLE
|
||||
elif pool_name == 'arms' and _CURRENT_ARMS_POOL_TITLE:
|
||||
up_type = UP_ARMS
|
||||
title = _CURRENT_ARMS_POOL_TITLE
|
||||
tmp = ''
|
||||
if up_type:
|
||||
for x in up_type:
|
||||
for operator in x.operators:
|
||||
up_list.append(operator)
|
||||
if pool_name == 'char':
|
||||
if x.star == 3:
|
||||
tmp += f'三星UP:{" ".join(x.operators)} \n'
|
||||
else:
|
||||
if x.star == 5:
|
||||
tmp += f'五星UP:{" ".join(x.operators)}'
|
||||
obj_list, obj_dict, max_list, star_list, max_index_list = format_card_information(count, star_list,
|
||||
_get_guardian_card, pool_name)
|
||||
rst = init_star_rst(star_list, cnlist, max_list, max_index_list, up_list)
|
||||
pool_info = f'当前up池:{title}\n{tmp}' if title else ''
|
||||
if count > 90:
|
||||
obj_list = set_list(obj_list)
|
||||
return pool_info + '\n' + MessageSegment.image(
|
||||
"base64://" + await generate_img(obj_list, 'guardian', star_list)) \
|
||||
+ '\n' + rst[:-1] + '\n' + max_card(obj_dict)
|
||||
|
||||
|
||||
async def update_guardian_info():
|
||||
global ALL_CHAR, ALL_ARMS
|
||||
url = 'https://wiki.biligame.com/gt/英雄筛选表'
|
||||
data, code = await update_info(url, 'guardian')
|
||||
if code == 200:
|
||||
ALL_CHAR = init_game_pool('guardian', data, GuardianChar)
|
||||
url = 'https://wiki.biligame.com/gt/武器'
|
||||
tmp, code_1 = await update_info(url, 'guardian_arms')
|
||||
url = 'https://wiki.biligame.com/gt/盾牌'
|
||||
data, code_2 = await update_info(url, 'guardian_arms')
|
||||
if code_1 == 200 and code_2 == 200:
|
||||
data.update(tmp)
|
||||
ALL_ARMS = init_game_pool('guardian_arms', data, GuardianArms)
|
||||
await _guardian_init_up_char()
|
||||
|
||||
|
||||
async def init_guardian_data():
|
||||
global ALL_CHAR, ALL_ARMS
|
||||
if GUARDIAN_FLAG:
|
||||
if not os.path.exists(DRAW_PATH + 'guardian.json') or not os.path.exists(DRAW_PATH + 'guardian_arms.json'):
|
||||
await update_guardian_info()
|
||||
else:
|
||||
with open(DRAW_PATH + 'guardian.json', 'r', encoding='utf8') as f:
|
||||
guardian_char_dict = json.load(f)
|
||||
with open(DRAW_PATH + 'guardian_arms.json', 'r', encoding='utf8') as f:
|
||||
guardian_arms_dict = json.load(f)
|
||||
ALL_CHAR = init_game_pool('guardian', guardian_char_dict, GuardianChar)
|
||||
ALL_ARMS = init_game_pool('guardian_arms', guardian_arms_dict, GuardianArms)
|
||||
await _guardian_init_up_char()
|
||||
|
||||
|
||||
# 抽取卡池
|
||||
def _get_guardian_card(pool_name: str = '', mode: int = 1):
|
||||
global ALL_ARMS, ALL_CHAR, UP_ARMS, UP_CHAR, _CURRENT_ARMS_POOL_TITLE, _CURRENT_CHAR_POOL_TITLE
|
||||
if pool_name == 'char':
|
||||
if mode == 1:
|
||||
star = get_star([3, 2, 1], [GUARDIAN_THREE_CHAR_P, GUARDIAN_TWO_CHAR_P, GUARDIAN_ONE_CHAR_P])
|
||||
else:
|
||||
star = get_star([3, 2], [GUARDIAN_THREE_CHAR_P, GUARDIAN_TWO_CHAR_P])
|
||||
up_lst = UP_CHAR
|
||||
flag = _CURRENT_CHAR_POOL_TITLE
|
||||
_max_star = 3
|
||||
all_data = ALL_CHAR
|
||||
else:
|
||||
if mode == 1:
|
||||
star = get_star([5, 4, 3, 2], [GUARDIAN_FIVE_ARMS_P, GUARDIAN_FOUR_ARMS_P,
|
||||
GUARDIAN_THREE_ARMS_P, GUARDIAN_TWO_ARMS_P])
|
||||
else:
|
||||
star = get_star([5, 4], [GUARDIAN_FIVE_ARMS_P, GUARDIAN_FOUR_ARMS_P])
|
||||
up_lst = UP_ARMS
|
||||
flag = _CURRENT_ARMS_POOL_TITLE
|
||||
_max_star = 5
|
||||
all_data = ALL_ARMS
|
||||
# 是否UP
|
||||
if flag and star == _max_star and pool_name:
|
||||
# 获取up角色列表
|
||||
up_char_lst = [x.operators for x in up_lst if x.star == star][0]
|
||||
# 成功获取up角色
|
||||
if random.random() < 0.5:
|
||||
up_char_name = random.choice(up_char_lst)
|
||||
acquire_char = [x for x in all_data if x.name == up_char_name][0]
|
||||
else:
|
||||
# 无up
|
||||
all_char_lst = [x for x in all_data if x.star == star and x.name not in up_char_lst and not x.limited]
|
||||
acquire_char = random.choice(all_char_lst)
|
||||
else:
|
||||
chars = [x for x in all_data if x.star == star and not x.limited]
|
||||
acquire_char = random.choice(chars)
|
||||
return acquire_char, _max_star - star
|
||||
|
||||
|
||||
# 获取up和概率
|
||||
async def _guardian_init_up_char():
|
||||
global _CURRENT_CHAR_POOL_TITLE, _CURRENT_ARMS_POOL_TITLE, UP_CHAR, UP_ARMS, POOL_IMG
|
||||
_CURRENT_CHAR_POOL_TITLE, _CURRENT_ARMS_POOL_TITLE, POOL_IMG, UP_CHAR, UP_ARMS = await init_up_char(announcement)
|
||||
|
||||
|
||||
async def reload_guardian_pool():
|
||||
await _guardian_init_up_char()
|
||||
return Message(f'当前UP池子:{_CURRENT_CHAR_POOL_TITLE} & {_CURRENT_ARMS_POOL_TITLE}')
|
||||
@@ -0,0 +1,317 @@
|
||||
import random
|
||||
import dateparser
|
||||
from lxml import etree
|
||||
from typing import List, Optional
|
||||
from urllib.parse import unquote
|
||||
from pydantic import ValidationError
|
||||
from nonebot.log import logger
|
||||
from nonebot.adapters.onebot.v11 import Message
|
||||
from utils.message_builder import image
|
||||
|
||||
from .base_handle import BaseHandle, BaseData, UpEvent as _UpEvent, UpChar as _UpChar
|
||||
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
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
class AzurChar(BaseData):
|
||||
type_: str # 舰娘类型
|
||||
|
||||
@property
|
||||
def star_str(self) -> str:
|
||||
return ["白", "蓝", "紫", "金"][self.star - 1]
|
||||
|
||||
|
||||
class UpChar(_UpChar):
|
||||
type_: str # 舰娘类型
|
||||
|
||||
|
||||
class UpEvent(_UpEvent):
|
||||
up_char: List[UpChar] # up对象
|
||||
|
||||
|
||||
class AzurHandle(BaseHandle[AzurChar]):
|
||||
def __init__(self):
|
||||
super().__init__("azur", "碧蓝航线")
|
||||
self.max_star = 4
|
||||
self.config = draw_config.azur
|
||||
self.ALL_CHAR: List[AzurChar] = []
|
||||
self.UP_EVENT: Optional[UpEvent] = None
|
||||
|
||||
def get_card(self, pool_name: str, **kwargs) -> AzurChar:
|
||||
if pool_name == "轻型":
|
||||
type_ = ["驱逐", "轻巡", "维修"]
|
||||
elif pool_name == "重型":
|
||||
type_ = ["重巡", "战列", "战巡", "重炮"]
|
||||
else:
|
||||
type_ = ["维修", "潜艇", "重巡", "轻航", "航母"]
|
||||
up_pool_flag = pool_name == "活动"
|
||||
# Up
|
||||
up_ship = [x for x in self.UP_EVENT.up_char if x.zoom > 0]
|
||||
# print(up_ship)
|
||||
acquire_char = None
|
||||
if up_ship and up_pool_flag:
|
||||
up_zoom = [(0, up_ship[0].zoom / 100)]
|
||||
# 初始化概率
|
||||
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
|
||||
rand = random.random()
|
||||
# 抽取up
|
||||
for i, zoom in enumerate(up_zoom):
|
||||
if zoom[0] <= rand <= zoom[1]:
|
||||
try:
|
||||
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(
|
||||
[4, 3, 2, 1],
|
||||
[
|
||||
self.config.AZUR_FOUR_P,
|
||||
self.config.AZUR_THREE_P,
|
||||
self.config.AZUR_TWO_P,
|
||||
self.config.AZUR_ONE_P,
|
||||
],
|
||||
)
|
||||
acquire_char = random.choice([
|
||||
x
|
||||
for x in self.ALL_CHAR
|
||||
if x.star == star and x.type_ in type_ and not x.limited
|
||||
])
|
||||
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]
|
||||
up_list = [x.name for x in self.UP_EVENT.up_char] if self.UP_EVENT.up_char else []
|
||||
result = self.format_result(index2card, **{**kwargs, "up_list": up_list})
|
||||
return image(b64=self.generate_img(cards).pic2bs4()) + result
|
||||
|
||||
def generate_card_img(self, card: AzurChar) -> BuildImage:
|
||||
sep_w = 5
|
||||
sep_t = 5
|
||||
sep_b = 20
|
||||
w = 100
|
||||
h = 100
|
||||
bg = BuildImage(w + sep_w * 2, h + sep_t + sep_b, font="msyh.ttf")
|
||||
frame_path = self.img_path / f"{card.star}_star.png"
|
||||
frame = BuildImage(w, h, background=frame_path)
|
||||
img_path = self.img_path / f"{cn2py(card.name)}.png"
|
||||
img = BuildImage(w, h, background=img_path)
|
||||
# 加圆角
|
||||
img.circle_corner(6)
|
||||
bg.paste(img, (sep_w, sep_t), alpha=True)
|
||||
bg.paste(frame, (sep_w, sep_t), alpha=True)
|
||||
bg.circle_corner(6)
|
||||
# 加名字
|
||||
text = card.name[:6] + "..." if len(card.name) > 7 else card.name
|
||||
text_w, text_h = bg.getsize(text)
|
||||
bg.text(
|
||||
(sep_w + (w - text_w) / 2, h + sep_t + (sep_b - text_h) / 2),
|
||||
text,
|
||||
fill=["#808080", "#3b8bff", "#8000ff", "#c90", "#ee494c"][card.star - 1],
|
||||
)
|
||||
return bg
|
||||
|
||||
def _init_data(self):
|
||||
self.ALL_CHAR = [
|
||||
AzurChar(
|
||||
name=value["名称"],
|
||||
star=int(value["星级"]),
|
||||
limited="可以建造" not in value["获取途径"],
|
||||
type_=value["类型"],
|
||||
)
|
||||
for value in self.load_data().values()
|
||||
]
|
||||
self.load_up_char()
|
||||
|
||||
def load_up_char(self):
|
||||
try:
|
||||
data = self.load_data(f"draw_card_up/{self.game_name}_up_char.json")
|
||||
self.UP_EVENT = UpEvent.parse_obj(data.get("char", {}))
|
||||
except ValidationError:
|
||||
logger.warning(f"{self.game_name}_up_char 解析出错")
|
||||
|
||||
def dump_up_char(self):
|
||||
if self.UP_EVENT:
|
||||
data = {"char": json.loads(self.UP_EVENT.json())}
|
||||
self.dump_data(data, f"draw_card_up/{self.game_name}_up_char.json")
|
||||
|
||||
async def _update_info(self):
|
||||
info = {}
|
||||
# 更新图鉴
|
||||
url = "https://wiki.biligame.com/blhx/舰娘图鉴"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
return
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
contents = dom.xpath(
|
||||
"//div[@class='resp-tabs-container']/div[@class='resp-tab-content']"
|
||||
)
|
||||
for index, content in enumerate(contents):
|
||||
char_list = content.xpath("./table/tbody/tr[2]/td/div/div/div/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]
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"名称": remove_prohibited_str(name),
|
||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||
"星级": self.parse_star(frame),
|
||||
"类型": self.parse_type(index),
|
||||
}
|
||||
info[member_dict["名称"]] = member_dict
|
||||
# 更新额外信息
|
||||
for key in info.keys():
|
||||
url = f"https://wiki.biligame.com/blhx/{key}"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
info[key]["获取途径"] = []
|
||||
logger.warning(f"{self.game_name_cn} 获取额外信息错误 {key}")
|
||||
continue
|
||||
try:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
time = dom.xpath(
|
||||
"//table[@class='wikitable sv-general']/tbody[1]/tr[4]/td[2]//text()"
|
||||
)[0]
|
||||
sources = []
|
||||
if "无法建造" in time:
|
||||
sources.append("无法建造")
|
||||
elif "活动已关闭" in time:
|
||||
sources.append("活动限定")
|
||||
else:
|
||||
sources.append("可以建造")
|
||||
info[key]["获取途径"] = sources
|
||||
except IndexError:
|
||||
info[key]["获取途径"] = []
|
||||
logger.warning(f"{self.game_name_cn} 获取额外信息错误 {key}")
|
||||
self.dump_data(info)
|
||||
logger.info(f"{self.game_name_cn} 更新成功")
|
||||
# 下载头像
|
||||
for value in info.values():
|
||||
await self.download_img(value["头像"], value["名称"])
|
||||
# 下载头像框
|
||||
idx = 1
|
||||
BLHX_URL = "https://patchwiki.biligame.com/images/blhx"
|
||||
for url in [
|
||||
"/1/15/pxho13xsnkyb546tftvh49etzdh74cf.png",
|
||||
"/a/a9/k8t7nx6c8pan5vyr8z21txp45jxeo66.png",
|
||||
"/a/a5/5whkzvt200zwhhx0h0iz9qo1kldnidj.png",
|
||||
"/a/a2/ptog1j220x5q02hytpwc8al7f229qk9.png",
|
||||
"/6/6d/qqv5oy3xs40d3055cco6bsm0j4k4gzk.png",
|
||||
]:
|
||||
await self.download_img(BLHX_URL + url, f"{idx}_star")
|
||||
idx += 1
|
||||
await self.update_up_char()
|
||||
|
||||
@staticmethod
|
||||
def parse_star(star: str) -> int:
|
||||
if star in ["舰娘头像外框普通.png", "舰娘头像外框白色.png"]:
|
||||
return 1
|
||||
elif star in ["舰娘头像外框稀有.png", "舰娘头像外框蓝色.png"]:
|
||||
return 2
|
||||
elif star in ["舰娘头像外框精锐.png", "舰娘头像外框紫色.png"]:
|
||||
return 3
|
||||
elif star in ["舰娘头像外框超稀有.png", "舰娘头像外框金色.png"]:
|
||||
return 4
|
||||
elif star in ["舰娘头像外框海上传奇.png", "舰娘头像外框彩色.png"]:
|
||||
return 5
|
||||
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)
|
||||
if not result:
|
||||
logger.warning(f"{self.game_name_cn}获取活动表出错")
|
||||
return
|
||||
try:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
dd = dom.xpath("//div[@class='timeline2']/dl/dd/a")[0]
|
||||
url = "https://wiki.biligame.com" + dd.xpath("./@href")[0]
|
||||
title = dd.xpath("string(.)")
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"{self.game_name_cn}获取活动页面出错")
|
||||
return
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
timer = dom.xpath("//span[@class='eventTimer']")[0]
|
||||
start_time = dateparser.parse(timer.xpath("./@data-start")[0])
|
||||
end_time = dateparser.parse(timer.xpath("./@data-end")[0])
|
||||
ships = dom.xpath("//table[@class='shipinfo']")
|
||||
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] # 舰船类型
|
||||
try:
|
||||
p = float(str(ship.xpath(".//sup/text()")[0]).strip("%"))
|
||||
except IndexError:
|
||||
p = 0
|
||||
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_))
|
||||
self.UP_EVENT = UpEvent(
|
||||
title=title,
|
||||
pool_img="",
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_chars,
|
||||
)
|
||||
self.dump_up_char()
|
||||
except Exception as e:
|
||||
logger.warning(f"{self.game_name_cn}UP更新出错 {type(e)}:{e}")
|
||||
|
||||
async def _reload_pool(self) -> Optional[Message]:
|
||||
await self.update_up_char()
|
||||
self.load_up_char()
|
||||
if self.UP_EVENT:
|
||||
return Message(f"重载成功!\n当前活动:{self.UP_EVENT.title}")
|
||||
@@ -0,0 +1,298 @@
|
||||
import math
|
||||
import random
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import aiofiles
|
||||
from PIL import Image
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Extra
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from typing import Dict, List, Optional, TypeVar, Generic, Tuple
|
||||
from nonebot.adapters.onebot.v11 import Message
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from nonebot.log import logger
|
||||
import asyncio
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
from utils.image_utils import BuildImage
|
||||
from ..config import DRAW_PATH, draw_config
|
||||
from ..util import cn2py, circled_number
|
||||
|
||||
|
||||
class BaseData(BaseModel, extra=Extra.ignore):
|
||||
name: str # 名字
|
||||
star: int # 星级
|
||||
limited: bool # 限定
|
||||
|
||||
def __eq__(self, other: "BaseData"):
|
||||
return self.name == other.name
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.name)
|
||||
|
||||
@property
|
||||
def star_str(self) -> str:
|
||||
return "".join(["★" for _ in range(self.star)])
|
||||
|
||||
|
||||
class UpChar(BaseData):
|
||||
zoom: float # up提升倍率
|
||||
|
||||
|
||||
class UpEvent(BaseModel):
|
||||
title: str # up池标题
|
||||
pool_img: str # up池封面
|
||||
start_time: Optional[datetime] # 开始时间
|
||||
end_time: Optional[datetime] # 结束时间
|
||||
up_char: List[UpChar] # up对象
|
||||
|
||||
|
||||
TC = TypeVar("TC", bound="BaseData")
|
||||
|
||||
|
||||
class BaseHandle(Generic[TC]):
|
||||
def __init__(self, game_name: str, game_name_cn: str, game_card_color: str = "#ffffff"):
|
||||
self.game_name = game_name
|
||||
self.game_name_cn = game_name_cn
|
||||
self.max_star = 1 # 最大星级
|
||||
self.data_path = DRAW_PATH
|
||||
self.img_path = IMAGE_PATH / f"draw_card/{self.game_name}"
|
||||
self.up_path = DRAW_PATH / "draw_card_up"
|
||||
self.img_path.mkdir(parents=True, exist_ok=True)
|
||||
self.up_path.mkdir(parents=True, exist_ok=True)
|
||||
self.data_files: List[str] = [f"{self.game_name}.json"]
|
||||
self.game_card_color: str = game_card_color
|
||||
|
||||
async def draw(self, count: int, **kwargs) -> Message:
|
||||
return await asyncio.get_event_loop().run_in_executor(None, self._draw, count)
|
||||
|
||||
def _draw(self, count: int, **kwargs) -> Message:
|
||||
index2card = self.get_cards(count, **kwargs)
|
||||
cards = [card[0] for card in index2card]
|
||||
result = self.format_result(index2card)
|
||||
return image(b64=self.generate_img(cards).pic2bs4()) + result
|
||||
|
||||
# 抽取卡池
|
||||
def get_card(self, **kwargs) -> TC:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_cards(self, count: int, **kwargs) -> List[Tuple[TC, int]]:
|
||||
return [(self.get_card(**kwargs), i) for i in range(count)]
|
||||
|
||||
# 获取星级
|
||||
@staticmethod
|
||||
def get_star(star_list: List[int], probability_list: List[float]) -> int:
|
||||
return random.choices(star_list, weights=probability_list, k=1)[0]
|
||||
|
||||
def format_result(self, index2card: List[Tuple[TC, int]], **kwargs) -> str:
|
||||
card_list = [card[0] for card in index2card]
|
||||
results = [
|
||||
self.format_star_result(card_list, **kwargs),
|
||||
self.format_max_star(index2card, **kwargs),
|
||||
self.format_max_card(card_list, **kwargs),
|
||||
]
|
||||
results = [rst for rst in results if rst]
|
||||
return "\n".join(results)
|
||||
|
||||
def format_star_result(self, card_list: List[TC], **kwargs) -> str:
|
||||
star_dict: Dict[str, int] = {} # 记录星级及其次数
|
||||
|
||||
card_list_sorted = sorted(card_list, key=lambda c: c.star, reverse=True)
|
||||
for card in card_list_sorted:
|
||||
try:
|
||||
star_dict[card.star_str] += 1
|
||||
except KeyError:
|
||||
star_dict[card.star_str] = 1
|
||||
|
||||
rst = ""
|
||||
for star_str, count in star_dict.items():
|
||||
rst += f"[{star_str}×{count}] "
|
||||
return rst.strip()
|
||||
|
||||
def format_max_star(
|
||||
self, card_list: List[Tuple[TC, int]], up_list: List[str] = [], **kwargs
|
||||
) -> str:
|
||||
up_list = up_list or kwargs.get("up_list", [])
|
||||
rst = ""
|
||||
for card, index in card_list:
|
||||
if card.star == self.max_star:
|
||||
if card.name in up_list:
|
||||
rst += f"第 {index} 抽获取UP {card.name}\n"
|
||||
else:
|
||||
rst += f"第 {index} 抽获取 {card.name}\n"
|
||||
return rst.strip()
|
||||
|
||||
def format_max_card(self, card_list: List[TC], **kwargs) -> str:
|
||||
card_dict: Dict[TC, int] = {} # 记录卡牌抽取次数
|
||||
|
||||
for card in card_list:
|
||||
try:
|
||||
card_dict[card] += 1
|
||||
except KeyError:
|
||||
card_dict[card] = 1
|
||||
|
||||
max_count = max(card_dict.values())
|
||||
max_card = list(card_dict.keys())[list(card_dict.values()).index(max_count)]
|
||||
if max_count <= 1:
|
||||
return ""
|
||||
return f"抽取到最多的是{max_card.name},共抽取了{max_count}次"
|
||||
|
||||
def generate_img(
|
||||
self,
|
||||
cards: List[TC],
|
||||
num_per_line: int = 5,
|
||||
max_per_line: Tuple[int, int] = (40, 10),
|
||||
) -> BuildImage:
|
||||
"""
|
||||
生成统计图片
|
||||
:param cards: 卡牌列表
|
||||
:param num_per_line: 单行角色显示数量
|
||||
:param max_per_line: 当card_list超过一定数值时,更改单行数量
|
||||
"""
|
||||
if len(cards) > max_per_line[0]:
|
||||
num_per_line = max_per_line[1]
|
||||
if len(cards) > 90:
|
||||
card_dict: Dict[TC, int] = {} # 记录卡牌抽取次数
|
||||
for card in cards:
|
||||
try:
|
||||
card_dict[card] += 1
|
||||
except KeyError:
|
||||
card_dict[card] = 1
|
||||
card_list = list(card_dict)
|
||||
num_list = list(card_dict.values())
|
||||
else:
|
||||
card_list = cards
|
||||
num_list = [1] * len(cards)
|
||||
|
||||
card_imgs: List[BuildImage] = []
|
||||
for card, num in zip(card_list, num_list):
|
||||
card_img = self.generate_card_img(card)
|
||||
|
||||
# 数量 > 1 时加数字上标
|
||||
if num > 1:
|
||||
label = circled_number(num)
|
||||
label_w = int(min(card_img.w, card_img.h) / 7)
|
||||
label = label.resize(
|
||||
(
|
||||
int(label_w * label.width / label.height),
|
||||
label_w,
|
||||
),
|
||||
Image.ANTIALIAS,
|
||||
)
|
||||
card_img.paste(label, alpha=True)
|
||||
|
||||
card_imgs.append(card_img)
|
||||
|
||||
img_w = card_imgs[0].w
|
||||
img_h = card_imgs[0].h
|
||||
if len(card_imgs) < num_per_line:
|
||||
w = img_w * len(card_imgs)
|
||||
else:
|
||||
w = img_w * num_per_line
|
||||
h = img_h * math.ceil(len(card_imgs) / num_per_line)
|
||||
img = BuildImage(w, h, img_w, img_h, color=self.game_card_color)
|
||||
for card_img in card_imgs:
|
||||
img.paste(card_img)
|
||||
return img
|
||||
|
||||
def generate_card_img(self, card: TC) -> BuildImage:
|
||||
img = str(self.img_path / f"{cn2py(card.name)}.png")
|
||||
return BuildImage(100, 100, background=img)
|
||||
|
||||
def load_data(self, filename: str = "") -> dict:
|
||||
if not filename:
|
||||
filename = f"{self.game_name}.json"
|
||||
filepath = self.data_path / filename
|
||||
if not filepath.exists():
|
||||
return {}
|
||||
with filepath.open("r", encoding="utf8") as f:
|
||||
return json.load(f)
|
||||
|
||||
def dump_data(self, data: dict, filename: str = ""):
|
||||
if not filename:
|
||||
filename = f"{self.game_name}.json"
|
||||
filepath = self.data_path / filename
|
||||
with filepath.open("w", encoding="utf8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
||||
|
||||
def data_exists(self) -> bool:
|
||||
for file in self.data_files:
|
||||
if not (self.data_path / file).exists():
|
||||
return False
|
||||
return True
|
||||
|
||||
def _init_data(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def init_data(self):
|
||||
try:
|
||||
self._init_data()
|
||||
except Exception as e:
|
||||
logger.warning(f"{self.game_name_cn} 导入角色数据错误:{type(e)}:{e}")
|
||||
|
||||
async def _update_info(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def client(self) -> aiohttp.ClientSession:
|
||||
headers = {
|
||||
"User-Agent": '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"'
|
||||
}
|
||||
return aiohttp.ClientSession(headers=headers)
|
||||
|
||||
async def update_info(self):
|
||||
try:
|
||||
async with asyncio.Semaphore(draw_config.SEMAPHORE):
|
||||
async with self.client() as session:
|
||||
self.session = session
|
||||
await self._update_info()
|
||||
except Exception as e:
|
||||
logger.warning(f"{self.game_name_cn} 更新数据错误:{type(e)}:{e}")
|
||||
self.init_data()
|
||||
|
||||
async def get_url(self, url: str) -> str:
|
||||
result = ""
|
||||
retry = 5
|
||||
for i in range(retry):
|
||||
try:
|
||||
async with self.session.get(url, timeout=10) as response:
|
||||
result = await response.text()
|
||||
break
|
||||
except TimeoutError:
|
||||
logger.warning(f"访问 {url} 超时, 重试 {i + 1}/{retry}")
|
||||
await asyncio.sleep(1)
|
||||
return result
|
||||
|
||||
async def download_img(self, url: str, name: str) -> bool:
|
||||
img_path = self.img_path / f"{cn2py(name)}.png"
|
||||
if img_path.exists():
|
||||
return True
|
||||
try:
|
||||
async with self.session.get(url, timeout=10) as response:
|
||||
async with aiofiles.open(str(img_path), "wb") as f:
|
||||
await f.write(await response.read())
|
||||
return True
|
||||
except TimeoutError:
|
||||
logger.warning(f"下载 {self.game_name_cn} 图片超时,名称:{name},url:{url}")
|
||||
return False
|
||||
except:
|
||||
logger.warning(f"下载 {self.game_name_cn} 链接错误,名称:{name},url:{url}")
|
||||
return False
|
||||
|
||||
async def _reload_pool(self) -> Optional[Message]:
|
||||
return None
|
||||
|
||||
async def reload_pool(self) -> Optional[Message]:
|
||||
try:
|
||||
async with self.client() as session:
|
||||
self.session = session
|
||||
return await self._reload_pool()
|
||||
except Exception as e:
|
||||
logger.warning(f"{self.game_name_cn} 重载UP池错误:{type(e)}:{e}")
|
||||
|
||||
def reset_count(self, user_id: int) -> bool:
|
||||
return False
|
||||
@@ -0,0 +1,221 @@
|
||||
import random
|
||||
from lxml import etree
|
||||
from typing import List, Tuple
|
||||
from PIL import ImageDraw
|
||||
from nonebot.log import logger
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
from .base_handle import BaseHandle, BaseData
|
||||
from ..config import draw_config
|
||||
from ..util import remove_prohibited_str, cn2py, load_font
|
||||
from utils.image_utils import BuildImage
|
||||
|
||||
|
||||
class FgoData(BaseData):
|
||||
pass
|
||||
|
||||
|
||||
class FgoChar(FgoData):
|
||||
pass
|
||||
|
||||
|
||||
class FgoCard(FgoData):
|
||||
pass
|
||||
|
||||
|
||||
class FgoHandle(BaseHandle[FgoData]):
|
||||
def __init__(self):
|
||||
super().__init__("fgo", "命运-冠位指定")
|
||||
self.data_files.append("fgo_card.json")
|
||||
self.max_star = 5
|
||||
self.config = draw_config.fgo
|
||||
self.ALL_CHAR: List[FgoChar] = []
|
||||
self.ALL_CARD: List[FgoCard] = []
|
||||
|
||||
def get_card(self, mode: int = 1) -> FgoData:
|
||||
if mode == 1:
|
||||
star = self.get_star(
|
||||
[8, 7, 6, 5, 4, 3],
|
||||
[
|
||||
self.config.FGO_SERVANT_FIVE_P,
|
||||
self.config.FGO_SERVANT_FOUR_P,
|
||||
self.config.FGO_SERVANT_THREE_P,
|
||||
self.config.FGO_CARD_FIVE_P,
|
||||
self.config.FGO_CARD_FOUR_P,
|
||||
self.config.FGO_CARD_THREE_P,
|
||||
],
|
||||
)
|
||||
elif mode == 2:
|
||||
star = self.get_star(
|
||||
[5, 4], [self.config.FGO_CARD_FIVE_P, self.config.FGO_CARD_FOUR_P]
|
||||
)
|
||||
else:
|
||||
star = self.get_star(
|
||||
[8, 7, 6],
|
||||
[
|
||||
self.config.FGO_SERVANT_FIVE_P,
|
||||
self.config.FGO_SERVANT_FOUR_P,
|
||||
self.config.FGO_SERVANT_THREE_P,
|
||||
],
|
||||
)
|
||||
if star > 5:
|
||||
star -= 3
|
||||
chars = [x for x in self.ALL_CHAR if x.star == star and not x.limited]
|
||||
else:
|
||||
chars = [x for x in self.ALL_CARD if x.star == star and not x.limited]
|
||||
return random.choice(chars)
|
||||
|
||||
def get_cards(self, count: int, **kwargs) -> List[Tuple[FgoData, int]]:
|
||||
card_list = [] # 获取所有角色
|
||||
servant_count = 0 # 保底计算
|
||||
card_count = 0 # 保底计算
|
||||
for i in range(count):
|
||||
servant_count += 1
|
||||
card_count += 1
|
||||
if card_count == 9: # 四星卡片保底
|
||||
mode = 2
|
||||
elif servant_count == 10: # 三星从者保底
|
||||
mode = 3
|
||||
else: # 普通抽
|
||||
mode = 1
|
||||
card = self.get_card(mode)
|
||||
if isinstance(card, FgoCard) and card.star > self.max_star - 2:
|
||||
card_count = 0
|
||||
if isinstance(card, FgoChar):
|
||||
servant_count = 0
|
||||
card_list.append((card, i + 1))
|
||||
return card_list
|
||||
|
||||
def generate_card_img(self, card: FgoData) -> BuildImage:
|
||||
sep_w = 5
|
||||
sep_t = 5
|
||||
sep_b = 20
|
||||
w = 128
|
||||
h = 140
|
||||
bg = BuildImage(w + sep_w * 2, h + sep_t + sep_b)
|
||||
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
|
||||
img = BuildImage(w, h, background=img_path)
|
||||
bg.paste(img, (sep_w, sep_t), alpha=True)
|
||||
# 加名字
|
||||
text = card.name[:6] + "..." if len(card.name) > 7 else card.name
|
||||
font = load_font(fontsize=16)
|
||||
text_w, text_h = font.getsize(text)
|
||||
draw = ImageDraw.Draw(bg.markImg)
|
||||
draw.text(
|
||||
(sep_w + (w - text_w) / 2, h + sep_t + (sep_b - text_h) / 2),
|
||||
text,
|
||||
font=font,
|
||||
fill="gray",
|
||||
)
|
||||
return bg
|
||||
|
||||
def _init_data(self):
|
||||
self.ALL_CHAR = [
|
||||
FgoChar(
|
||||
name=value["名称"],
|
||||
star=int(value["星级"]),
|
||||
limited=True
|
||||
if not ("圣晶石召唤" in value["入手方式"] or "圣晶石召唤(Story卡池)" in value["入手方式"])
|
||||
else False,
|
||||
)
|
||||
for value in self.load_data().values()
|
||||
]
|
||||
self.ALL_CARD = [
|
||||
FgoCard(name=value["名称"], star=int(value["星级"]), limited=False)
|
||||
for value in self.load_data("fgo_card.json").values()
|
||||
]
|
||||
|
||||
async def _update_info(self):
|
||||
# fgo.json
|
||||
fgo_info = {}
|
||||
for i in range(500):
|
||||
url = f"http://fgo.vgtime.com/servant/ajax?card=&wd=&ids=&sort=12777&o=desc&pn={i}"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} page {i} 出错")
|
||||
continue
|
||||
fgo_data = json.loads(result)
|
||||
if int(fgo_data["nums"]) <= 0:
|
||||
break
|
||||
for x in fgo_data["data"]:
|
||||
name = remove_prohibited_str(x["name"])
|
||||
member_dict = {
|
||||
"id": x["id"],
|
||||
"card_id": x["charid"],
|
||||
"头像": x["icon"],
|
||||
"名称": remove_prohibited_str(x["name"]),
|
||||
"职阶": x["classes"],
|
||||
"星级": int(x["star"]),
|
||||
"hp": x["lvmax4hp"],
|
||||
"atk": x["lvmax4atk"],
|
||||
"card_quick": x["cardquick"],
|
||||
"card_arts": x["cardarts"],
|
||||
"card_buster": x["cardbuster"],
|
||||
"宝具": x["tprop"],
|
||||
}
|
||||
fgo_info[name] = member_dict
|
||||
# 更新额外信息
|
||||
for key in fgo_info.keys():
|
||||
url = f'http://fgo.vgtime.com/servant/{fgo_info[key]["id"]}'
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
fgo_info[key]["入手方式"] = ["圣晶石召唤"]
|
||||
logger.warning(f"{self.game_name_cn} 获取额外信息错误 {key}")
|
||||
continue
|
||||
try:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
obtain = dom.xpath(
|
||||
"//table[contains(string(.),'入手方式')]/tr[8]/td[3]/text()"
|
||||
)[0]
|
||||
obtain = str(obtain).strip()
|
||||
if "限时活动免费获取 活动结束后无法获得" in obtain:
|
||||
obtain = ["活动获取"]
|
||||
elif "非限时UP无法获得" in obtain:
|
||||
obtain = ["限时召唤"]
|
||||
else:
|
||||
if "&" in obtain:
|
||||
obtain = obtain.split("&")
|
||||
else:
|
||||
obtain = obtain.split(" ")
|
||||
obtain = [s.strip() for s in obtain if s.strip()]
|
||||
fgo_info[key]["入手方式"] = obtain
|
||||
except IndexError:
|
||||
fgo_info[key]["入手方式"] = ["圣晶石召唤"]
|
||||
logger.warning(f"{self.game_name_cn} 获取额外信息错误 {key}")
|
||||
self.dump_data(fgo_info)
|
||||
logger.info(f"{self.game_name_cn} 更新成功")
|
||||
# fgo_card.json
|
||||
fgo_card_info = {}
|
||||
for i in range(500):
|
||||
url = f"http://fgo.vgtime.com/equipment/ajax?wd=&ids=&sort=12958&o=desc&pn={i}"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn}卡牌 page {i} 出错")
|
||||
continue
|
||||
fgo_data = json.loads(result)
|
||||
if int(fgo_data["nums"]) <= 0:
|
||||
break
|
||||
for x in fgo_data["data"]:
|
||||
name = remove_prohibited_str(x["name"])
|
||||
member_dict = {
|
||||
"id": x["id"],
|
||||
"card_id": x["equipid"],
|
||||
"头像": x["icon"],
|
||||
"名称": name,
|
||||
"星级": int(x["star"]),
|
||||
"hp": x["lvmax_hp"],
|
||||
"atk": x["lvmax_atk"],
|
||||
"skill_e": str(x["skill_e"]).split("<br />")[:-1],
|
||||
}
|
||||
fgo_card_info[name] = member_dict
|
||||
self.dump_data(fgo_card_info, "fgo_card.json")
|
||||
logger.info(f"{self.game_name_cn} 卡牌更新成功")
|
||||
# 下载头像
|
||||
for value in fgo_info.values():
|
||||
await self.download_img(value["头像"], value["名称"])
|
||||
for value in fgo_card_info.values():
|
||||
await self.download_img(value["头像"], value["名称"])
|
||||
@@ -0,0 +1,429 @@
|
||||
import random
|
||||
import dateparser
|
||||
from lxml import etree
|
||||
from PIL import Image, ImageDraw
|
||||
from urllib.parse import unquote
|
||||
from typing import List, Optional, Tuple
|
||||
from pydantic import ValidationError
|
||||
from datetime import datetime, timedelta
|
||||
from nonebot.adapters.onebot.v11 import Message
|
||||
from utils.message_builder import image
|
||||
from nonebot.log import logger
|
||||
import asyncio
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
from .base_handle import BaseHandle, BaseData, UpChar, UpEvent
|
||||
from ..config import draw_config
|
||||
from ..count_manager import GenshinCountManager
|
||||
from ..util import remove_prohibited_str, cn2py, load_font
|
||||
from utils.image_utils import BuildImage
|
||||
|
||||
|
||||
class GenshinData(BaseData):
|
||||
pass
|
||||
|
||||
|
||||
class GenshinChar(GenshinData):
|
||||
pass
|
||||
|
||||
|
||||
class GenshinArms(GenshinData):
|
||||
pass
|
||||
|
||||
|
||||
class GenshinHandle(BaseHandle[GenshinData]):
|
||||
def __init__(self):
|
||||
super().__init__("genshin", "原神", "#ebebeb")
|
||||
self.data_files.append("genshin_arms.json")
|
||||
self.max_star = 5
|
||||
self.config = draw_config.genshin
|
||||
|
||||
self.ALL_CHAR: List[GenshinData] = []
|
||||
self.ALL_ARMS: List[GenshinData] = []
|
||||
self.UP_CHAR: Optional[UpEvent] = None
|
||||
self.UP_ARMS: Optional[UpEvent] = None
|
||||
|
||||
self.count_manager = GenshinCountManager((10, 90), ("4", "5"), 180)
|
||||
|
||||
# 抽取卡池
|
||||
def get_card(
|
||||
self, pool_name: str, mode: int = 1, add: float = 0.0, is_up: bool = False
|
||||
):
|
||||
"""
|
||||
mode 1:普通抽 2:四星保底 3:五星保底
|
||||
"""
|
||||
if mode == 1:
|
||||
star = self.get_star(
|
||||
[5, 4, 3],
|
||||
[
|
||||
self.config.GENSHIN_FIVE_P + add,
|
||||
self.config.GENSHIN_FOUR_P,
|
||||
self.config.GENSHIN_THREE_P,
|
||||
],
|
||||
)
|
||||
elif mode == 2:
|
||||
star = self.get_star(
|
||||
[5, 4],
|
||||
[self.config.GENSHIN_G_FIVE_P + add, self.config.GENSHIN_G_FOUR_P],
|
||||
)
|
||||
else:
|
||||
star = 5
|
||||
|
||||
if pool_name == "char":
|
||||
up_event = self.UP_CHAR
|
||||
all_list = self.ALL_CHAR + [
|
||||
x for x in self.ALL_ARMS if x.star == star and x.star < 5
|
||||
]
|
||||
elif pool_name == "arms":
|
||||
up_event = self.UP_ARMS
|
||||
all_list = self.ALL_ARMS + [
|
||||
x for x in self.ALL_CHAR if x.star == star and x.star < 5
|
||||
]
|
||||
else:
|
||||
up_event = None
|
||||
all_list = self.ALL_ARMS + self.ALL_CHAR
|
||||
|
||||
acquire_char = None
|
||||
# 是否UP
|
||||
if up_event and star > 3:
|
||||
# 获取up角色列表
|
||||
up_list = [x.name for x in up_event.up_char if x.star == star]
|
||||
# 成功获取up角色
|
||||
if random.random() < 0.5 or is_up:
|
||||
up_name = random.choice(up_list)
|
||||
try:
|
||||
acquire_char = [x for x in all_list if x.name == up_name][0]
|
||||
except IndexError:
|
||||
pass
|
||||
if not acquire_char:
|
||||
chars = [x for x in all_list if x.star == star and not x.limited]
|
||||
acquire_char = random.choice(chars)
|
||||
return acquire_char
|
||||
|
||||
def get_cards(
|
||||
self, count: int, user_id: int, pool_name: str
|
||||
) -> List[Tuple[GenshinData, int]]:
|
||||
card_list = [] # 获取角色列表
|
||||
add = 0.0
|
||||
count_manager = self.count_manager
|
||||
count_manager.check_timeout(user_id) # 检查上次抽卡次数是否超时
|
||||
count_manager.check_count(user_id, count) # 检查次数累计
|
||||
pool = self.UP_CHAR if pool_name == "char" else self.UP_ARMS
|
||||
for i in range(count):
|
||||
count_manager.increase(user_id)
|
||||
star = count_manager.check(user_id) # 是否有四星或五星保底
|
||||
if (
|
||||
count_manager.get_user_count(user_id)
|
||||
- count_manager.get_user_five_index(user_id)
|
||||
) % count_manager.get_max_guarantee() >= 72:
|
||||
add += draw_config.genshin.I72_ADD
|
||||
if star:
|
||||
if star == 4:
|
||||
card = self.get_card(pool_name, 2, add=add)
|
||||
else:
|
||||
card = self.get_card(
|
||||
pool_name, 3, add, count_manager.is_up(user_id)
|
||||
)
|
||||
else:
|
||||
card = self.get_card(pool_name, 1, add, count_manager.is_up(user_id))
|
||||
# print(f"{count_manager.get_user_count(user_id)}:",
|
||||
# count_manager.get_user_five_index(user_id), star, card.star, add)
|
||||
# 四星角色
|
||||
if card.star == 4:
|
||||
count_manager.mark_four_index(user_id)
|
||||
# 五星角色
|
||||
elif card.star == self.max_star:
|
||||
add = 0
|
||||
count_manager.mark_five_index(user_id) # 记录五星保底
|
||||
count_manager.mark_four_index(user_id) # 记录四星保底
|
||||
if pool and card.name in [
|
||||
x.name for x in pool.up_char if x.star == self.max_star
|
||||
]:
|
||||
count_manager.set_is_up(user_id, True)
|
||||
else:
|
||||
count_manager.set_is_up(user_id, False)
|
||||
card_list.append((card, count_manager.get_user_count(user_id)))
|
||||
count_manager.update_time(user_id)
|
||||
return card_list
|
||||
|
||||
def generate_card_img(self, card: GenshinData) -> BuildImage:
|
||||
sep_w = 10
|
||||
sep_h = 5
|
||||
frame_w = 112
|
||||
frame_h = 132
|
||||
img_w = 106
|
||||
img_h = 106
|
||||
bg = BuildImage(frame_w + sep_w * 2, frame_h + sep_h * 2, color="#EBEBEB")
|
||||
frame_path = str(self.img_path / "avatar_frame.png")
|
||||
frame = Image.open(frame_path)
|
||||
# 加名字
|
||||
text = card.name
|
||||
font = load_font(fontsize=14)
|
||||
text_w, text_h = font.getsize(text)
|
||||
draw = ImageDraw.Draw(frame)
|
||||
draw.text(
|
||||
((frame_w - text_w) / 2, frame_h - 15 - text_h / 2),
|
||||
text,
|
||||
font=font,
|
||||
fill="gray",
|
||||
)
|
||||
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
|
||||
img = BuildImage(img_w, img_h, background=img_path)
|
||||
if isinstance(card, GenshinArms):
|
||||
# 武器卡背景不是透明的,切去上方两个圆弧
|
||||
r = 12
|
||||
circle = Image.new("L", (r * 2, r * 2), 0)
|
||||
alpha = Image.new("L", img.size, 255)
|
||||
alpha.paste(circle, (-r - 3, -r - 3)) # 左上角
|
||||
alpha.paste(circle, (img_h - r + 3, -r - 3)) # 右上角
|
||||
img.markImg.putalpha(alpha)
|
||||
star_path = str(self.img_path / f"{card.star}_star.png")
|
||||
star = Image.open(star_path)
|
||||
bg.paste(frame, (sep_w, sep_h), alpha=True)
|
||||
bg.paste(img, (sep_w + 3, sep_h + 3), alpha=True)
|
||||
bg.paste(star, (sep_w + int((frame_w - star.width) / 2), sep_h - 6), alpha=True)
|
||||
return bg
|
||||
|
||||
def format_pool_info(self, pool_name: str) -> str:
|
||||
info = ""
|
||||
up_event = None
|
||||
if pool_name == "char":
|
||||
up_event = self.UP_CHAR
|
||||
elif pool_name == "arms":
|
||||
up_event = self.UP_ARMS
|
||||
if up_event:
|
||||
star5_list = [x.name for x in up_event.up_char if x.star == 5]
|
||||
star4_list = [x.name for x in up_event.up_char if x.star == 4]
|
||||
if star5_list:
|
||||
info += f"五星UP:{' '.join(star5_list)}\n"
|
||||
if star4_list:
|
||||
info += f"四星UP:{' '.join(star4_list)}\n"
|
||||
info = f"当前up池:{up_event.title}\n{info}"
|
||||
return info.strip()
|
||||
|
||||
async def draw(self, count: int, user_id: int, pool_name: str = "", **kwargs) -> Message:
|
||||
return await asyncio.get_event_loop().run_in_executor(None, self._draw, count, user_id, pool_name)
|
||||
|
||||
def _draw(self, count: int, user_id: int, pool_name: str = "", **kwargs) -> Message:
|
||||
index2cards = self.get_cards(count, user_id, pool_name)
|
||||
cards = [card[0] for card in index2cards]
|
||||
up_event = None
|
||||
if pool_name == "char":
|
||||
up_event = self.UP_CHAR
|
||||
elif pool_name == "arms":
|
||||
up_event = self.UP_ARMS
|
||||
up_list = [x.name for x in up_event.up_char] if up_event else []
|
||||
result = self.format_star_result(cards)
|
||||
result += (
|
||||
"\n" + max_star_str
|
||||
if (max_star_str := self.format_max_star(index2cards, up_list=up_list))
|
||||
else ""
|
||||
)
|
||||
result += f"\n距离保底发还剩 {self.count_manager.get_user_guarantee_count(user_id)} 抽"
|
||||
# result += "\n【五星:0.6%,四星:5.1%,第72抽开始五星概率每抽加0.585%】"
|
||||
pool_info = self.format_pool_info(pool_name)
|
||||
img = self.generate_img(cards)
|
||||
bk = BuildImage(img.w, img.h + 50, font_size=20, color="#ebebeb")
|
||||
bk.paste(img)
|
||||
bk.text((0, img.h + 10), "【五星:0.6%,四星:5.1%,第72抽开始五星概率每抽加0.585%】")
|
||||
return pool_info + image(b64=bk.pic2bs4()) + result
|
||||
|
||||
def _init_data(self):
|
||||
self.ALL_CHAR = [
|
||||
GenshinChar(
|
||||
name=value["名称"],
|
||||
star=int(value["星级"]),
|
||||
limited=value["常驻/限定"] == "限定UP",
|
||||
)
|
||||
for key, value in self.load_data().items()
|
||||
if "旅行者" not in key
|
||||
]
|
||||
self.ALL_ARMS = [
|
||||
GenshinArms(
|
||||
name=value["名称"],
|
||||
star=int(value["星级"]),
|
||||
limited="祈愿" not in value["获取途径"],
|
||||
)
|
||||
for value in self.load_data("genshin_arms.json").values()
|
||||
]
|
||||
self.load_up_char()
|
||||
|
||||
def load_up_char(self):
|
||||
try:
|
||||
data = self.load_data(f"draw_card_up/{self.game_name}_up_char.json")
|
||||
self.UP_CHAR = UpEvent.parse_obj(data.get("char", {}))
|
||||
self.UP_ARMS = UpEvent.parse_obj(data.get("arms", {}))
|
||||
except ValidationError:
|
||||
logger.warning(f"{self.game_name}_up_char 解析出错")
|
||||
|
||||
def dump_up_char(self):
|
||||
if self.UP_CHAR and self.UP_ARMS:
|
||||
data = {
|
||||
"char": json.loads(self.UP_CHAR.json()),
|
||||
"arms": json.loads(self.UP_ARMS.json()),
|
||||
}
|
||||
self.dump_data(data, f"draw_card_up/{self.game_name}_up_char.json")
|
||||
|
||||
async def _update_info(self):
|
||||
# genshin.json
|
||||
char_info = {}
|
||||
url = "https://wiki.biligame.com/ys/角色筛选"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
else:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath("//table[@id='CardSelectTr']/tbody/tr")
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./td[1]/a/@title")[0]
|
||||
avatar = char.xpath("./td[1]/a/img/@srcset")[0]
|
||||
star = char.xpath("./td[3]/text()")[0]
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"星级": int(str(star).strip()[:1]),
|
||||
}
|
||||
char_info[member_dict["名称"]] = member_dict
|
||||
# 更新额外信息
|
||||
for key in char_info.keys():
|
||||
result = await self.get_url(f"https://wiki.biligame.com/ys/{key}")
|
||||
if not result:
|
||||
char_info[key]["常驻/限定"] = "未知"
|
||||
logger.warning(f"{self.game_name_cn} 获取额外信息错误 {key}")
|
||||
continue
|
||||
try:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
limit = dom.xpath(
|
||||
"//table[contains(string(.),'常驻/限定')]/tbody/tr[6]/td/text()"
|
||||
)[0]
|
||||
char_info[key]["常驻/限定"] = str(limit).strip()
|
||||
except IndexError:
|
||||
char_info[key]["常驻/限定"] = "未知"
|
||||
logger.warning(f"{self.game_name_cn} 获取额外信息错误 {key}")
|
||||
self.dump_data(char_info)
|
||||
logger.info(f"{self.game_name_cn} 更新成功")
|
||||
# genshin_arms.json
|
||||
arms_info = {}
|
||||
url = "https://wiki.biligame.com/ys/武器图鉴"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
else:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath("//table[@id='CardSelectTr']/tbody/tr")
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./td[1]/a/@title")[0]
|
||||
avatar = char.xpath("./td[1]/a/img/@srcset")[0]
|
||||
star = char.xpath("./td[4]/img/@alt")[0]
|
||||
sources = str(char.xpath("./td[5]/text()")[0]).split(",")
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"星级": int(str(star).strip()[:1]),
|
||||
"获取途径": [s.strip() for s in sources if s.strip()],
|
||||
}
|
||||
arms_info[member_dict["名称"]] = member_dict
|
||||
self.dump_data(arms_info, "genshin_arms.json")
|
||||
logger.info(f"{self.game_name_cn} 武器更新成功")
|
||||
# 下载头像
|
||||
for value in char_info.values():
|
||||
await self.download_img(value["头像"], value["名称"])
|
||||
for value in arms_info.values():
|
||||
await self.download_img(value["头像"], value["名称"])
|
||||
# 下载星星
|
||||
idx = 1
|
||||
YS_URL = "https://patchwiki.biligame.com/images/ys"
|
||||
for url in [
|
||||
"/1/13/7xzg7tgf8dsr2hjpmdbm5gn9wvzt2on.png",
|
||||
"/b/bc/sd2ige6d7lvj7ugfumue3yjg8gyi0d1.png",
|
||||
"/e/ec/l3mnhy56pyailhn3v7r873htf2nofau.png",
|
||||
"/9/9c/sklp02ffk3aqszzvh8k1c3139s0awpd.png",
|
||||
"/c/c7/qu6xcndgj6t14oxvv7yz2warcukqv1m.png",
|
||||
]:
|
||||
await self.download_img(YS_URL + url, f"{idx}_star")
|
||||
idx += 1
|
||||
# 下载头像框
|
||||
await self.download_img(
|
||||
YS_URL + "/2/2e/opbcst4xbtcq0i4lwerucmosawn29ti.png", f"avatar_frame"
|
||||
)
|
||||
await self.update_up_char()
|
||||
|
||||
async def update_up_char(self):
|
||||
url = "https://wiki.biligame.com/ys/祈愿"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"{self.game_name_cn}获取祈愿页面出错")
|
||||
return
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
tables = dom.xpath(
|
||||
"//div[@class='mw-parser-output']/div[@class='row']/div/table[@class='wikitable']/tbody"
|
||||
)
|
||||
if not tables or len(tables) < 2:
|
||||
logger.warning(f"{self.game_name_cn}获取活动祈愿出错")
|
||||
return
|
||||
try:
|
||||
for index, table in enumerate(tables):
|
||||
title = table.xpath("./tr[1]/th/img/@title")[0]
|
||||
title = str(title).split("」")[0] + "」" if "」" in title else title
|
||||
pool_img = str(table.xpath("./tr[1]/th/img/@srcset")[0]).split(" ")[-2]
|
||||
time = table.xpath("./tr[2]/td/text()")[0]
|
||||
star5_list = table.xpath("./tr[3]/td/a/@title")
|
||||
star4_list = table.xpath("./tr[4]/td/a/@title")
|
||||
start, end = str(time).split("~")
|
||||
start_time = dateparser.parse(start)
|
||||
end_time = dateparser.parse(end)
|
||||
if not start_time and end_time:
|
||||
start_time = end_time - timedelta(days=20)
|
||||
if start_time and end_time and start_time <= datetime.now() <= end_time:
|
||||
up_event = UpEvent(
|
||||
title=title,
|
||||
pool_img=pool_img,
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=[
|
||||
UpChar(name=name, star=5, limited=False, zoom=50)
|
||||
for name in star5_list
|
||||
]
|
||||
+ [
|
||||
UpChar(name=name, star=4, limited=False, zoom=50)
|
||||
for name in star4_list
|
||||
],
|
||||
)
|
||||
if index == 0:
|
||||
self.UP_CHAR = up_event
|
||||
elif index == 1:
|
||||
self.UP_ARMS = up_event
|
||||
if self.UP_CHAR and self.UP_ARMS:
|
||||
self.dump_up_char()
|
||||
logger.info(
|
||||
f"成功获取{self.game_name_cn}当前up信息...当前up池: {self.UP_CHAR.title} & {self.UP_ARMS.title}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"{self.game_name_cn}UP更新出错 {type(e)}:{e}")
|
||||
|
||||
def reset_count(self, user_id: int) -> bool:
|
||||
self.count_manager.reset(user_id)
|
||||
return True
|
||||
|
||||
async def _reload_pool(self) -> Optional[Message]:
|
||||
await self.update_up_char()
|
||||
self.load_up_char()
|
||||
if self.UP_CHAR and self.UP_ARMS:
|
||||
return Message(
|
||||
Message.template("重载成功!\n当前UP池子:{} & {}{:image}{:image}").format(
|
||||
self.UP_CHAR.title,
|
||||
self.UP_ARMS.title,
|
||||
self.UP_CHAR.pool_img,
|
||||
self.UP_ARMS.pool_img,
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,400 @@
|
||||
import re
|
||||
import random
|
||||
import dateparser
|
||||
from lxml import etree
|
||||
from PIL import ImageDraw
|
||||
from datetime import datetime
|
||||
from urllib.parse import unquote
|
||||
from typing import List, Optional, Tuple
|
||||
from pydantic import ValidationError
|
||||
from nonebot.adapters.onebot.v11 import Message
|
||||
from utils.message_builder import image
|
||||
from nonebot.log import logger
|
||||
import asyncio
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
from .base_handle import BaseHandle, BaseData, UpChar, UpEvent
|
||||
from ..config import draw_config
|
||||
from ..util import remove_prohibited_str, cn2py, load_font
|
||||
from utils.image_utils import BuildImage
|
||||
|
||||
|
||||
class GuardianData(BaseData):
|
||||
pass
|
||||
|
||||
|
||||
class GuardianChar(GuardianData):
|
||||
pass
|
||||
|
||||
|
||||
class GuardianArms(GuardianData):
|
||||
pass
|
||||
|
||||
|
||||
class GuardianHandle(BaseHandle[GuardianData]):
|
||||
def __init__(self):
|
||||
super().__init__("guardian", "坎公骑冠剑")
|
||||
self.data_files.append("guardian_arms.json")
|
||||
self.config = draw_config.guardian
|
||||
|
||||
self.ALL_CHAR: List[GuardianChar] = []
|
||||
self.ALL_ARMS: List[GuardianArms] = []
|
||||
self.UP_CHAR: Optional[UpEvent] = None
|
||||
self.UP_ARMS: Optional[UpEvent] = None
|
||||
|
||||
def get_card(self, pool_name: str, mode: int = 1) -> GuardianData:
|
||||
if pool_name == "char":
|
||||
if mode == 1:
|
||||
star = self.get_star(
|
||||
[3, 2, 1],
|
||||
[
|
||||
self.config.GUARDIAN_THREE_CHAR_P,
|
||||
self.config.GUARDIAN_TWO_CHAR_P,
|
||||
self.config.GUARDIAN_ONE_CHAR_P,
|
||||
],
|
||||
)
|
||||
else:
|
||||
star = self.get_star(
|
||||
[3, 2],
|
||||
[
|
||||
self.config.GUARDIAN_THREE_CHAR_P,
|
||||
self.config.GUARDIAN_TWO_CHAR_P,
|
||||
],
|
||||
)
|
||||
up_event = self.UP_CHAR
|
||||
self.max_star = 3
|
||||
all_data = self.ALL_CHAR
|
||||
else:
|
||||
if mode == 1:
|
||||
star = self.get_star(
|
||||
[5, 4, 3, 2],
|
||||
[
|
||||
self.config.GUARDIAN_FIVE_ARMS_P,
|
||||
self.config.GUARDIAN_FOUR_ARMS_P,
|
||||
self.config.GUARDIAN_THREE_ARMS_P,
|
||||
self.config.GUARDIAN_TWO_ARMS_P,
|
||||
],
|
||||
)
|
||||
else:
|
||||
star = self.get_star(
|
||||
[5, 4],
|
||||
[
|
||||
self.config.GUARDIAN_FIVE_ARMS_P,
|
||||
self.config.GUARDIAN_FOUR_ARMS_P,
|
||||
],
|
||||
)
|
||||
up_event = self.UP_ARMS
|
||||
self.max_star = 5
|
||||
all_data = self.ALL_ARMS
|
||||
|
||||
acquire_char = None
|
||||
# 是否UP
|
||||
if up_event and star == self.max_star and pool_name:
|
||||
# 获取up角色列表
|
||||
up_list = [x.name for x in up_event.up_char if x.star == star]
|
||||
# 成功获取up角色
|
||||
if random.random() < 0.5:
|
||||
up_name = random.choice(up_list)
|
||||
try:
|
||||
acquire_char = [x for x in all_data if x.name == up_name][0]
|
||||
except IndexError:
|
||||
pass
|
||||
if not acquire_char:
|
||||
chars = [x for x in all_data if x.star == star and not x.limited]
|
||||
acquire_char = random.choice(chars)
|
||||
return acquire_char
|
||||
|
||||
def get_cards(self, count: int, pool_name: str) -> List[Tuple[GuardianData, int]]:
|
||||
card_list = []
|
||||
card_count = 0 # 保底计算
|
||||
for i in range(count):
|
||||
card_count += 1
|
||||
# 十连保底
|
||||
if card_count == 10:
|
||||
card = self.get_card(pool_name, 2)
|
||||
card_count = 0
|
||||
else:
|
||||
card = self.get_card(pool_name, 1)
|
||||
if card.star > self.max_star - 2:
|
||||
card_count = 0
|
||||
card_list.append((card, i + 1))
|
||||
return card_list
|
||||
|
||||
def format_pool_info(self, pool_name: str) -> str:
|
||||
info = ""
|
||||
up_event = self.UP_CHAR if pool_name == "char" else self.UP_ARMS
|
||||
if up_event:
|
||||
if pool_name == "char":
|
||||
up_list = [x.name for x in up_event.up_char if x.star == 3]
|
||||
info += f'三星UP:{" ".join(up_list)}\n'
|
||||
else:
|
||||
up_list = [x.name for x in up_event.up_char if x.star == 5]
|
||||
info += f'五星UP:{" ".join(up_list)}\n'
|
||||
info = f"当前up池:{up_event.title}\n{info}"
|
||||
return info.strip()
|
||||
|
||||
async def draw(self, count: int, pool_name: str, **kwargs) -> Message:
|
||||
return await asyncio.get_event_loop().run_in_executor(None, self._draw, count, pool_name)
|
||||
|
||||
def _draw(self, count: int, pool_name: str, **kwargs) -> Message:
|
||||
index2card = self.get_cards(count, pool_name)
|
||||
cards = [card[0] for card in index2card]
|
||||
up_event = self.UP_CHAR if pool_name == "char" else self.UP_ARMS
|
||||
up_list = [x.name for x in up_event.up_char] if up_event else []
|
||||
result = self.format_result(index2card, up_list=up_list)
|
||||
pool_info = self.format_pool_info(pool_name)
|
||||
return pool_info + image(b64=self.generate_img(cards).pic2bs4()) + result
|
||||
|
||||
def generate_card_img(self, card: GuardianData) -> BuildImage:
|
||||
sep_w = 1
|
||||
sep_h = 1
|
||||
block_w = 170
|
||||
block_h = 90
|
||||
img_w = 90
|
||||
img_h = 90
|
||||
if isinstance(card, GuardianChar):
|
||||
block_color = "#2e2923"
|
||||
font_color = "#e2ccad"
|
||||
star_w = 90
|
||||
star_h = 30
|
||||
star_name = f"{card.star}_star.png"
|
||||
frame_path = ""
|
||||
else:
|
||||
block_color = "#EEE4D5"
|
||||
font_color = "#A65400"
|
||||
star_w = 45
|
||||
star_h = 45
|
||||
star_name = f"{card.star}_star_rank.png"
|
||||
frame_path = str(self.img_path / "avatar_frame.png")
|
||||
bg = BuildImage(block_w + sep_w * 2, block_h + sep_h * 2, color="#F6F4ED")
|
||||
block = BuildImage(block_w, block_h, color=block_color)
|
||||
star_path = str(self.img_path / star_name)
|
||||
star = BuildImage(star_w, star_h, background=star_path)
|
||||
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
|
||||
img = BuildImage(img_w, img_h, background=img_path)
|
||||
block.paste(img, (0, 0), alpha=True)
|
||||
if frame_path:
|
||||
frame = BuildImage(img_w, img_h, background=frame_path)
|
||||
block.paste(frame, (0, 0), alpha=True)
|
||||
block.paste(
|
||||
star,
|
||||
(int((block_w + img_w - star_w) / 2), block_h - star_h - 30),
|
||||
alpha=True,
|
||||
)
|
||||
# 加名字
|
||||
text = card.name[:4] + "..." if len(card.name) > 5 else card.name
|
||||
font = load_font(fontsize=14)
|
||||
text_w, _ = font.getsize(text)
|
||||
draw = ImageDraw.Draw(block.markImg)
|
||||
draw.text(
|
||||
((block_w + img_w - text_w) / 2, 55),
|
||||
text,
|
||||
font=font,
|
||||
fill=font_color,
|
||||
)
|
||||
bg.paste(block, (sep_w, sep_h))
|
||||
return bg
|
||||
|
||||
def _init_data(self):
|
||||
self.ALL_CHAR = [
|
||||
GuardianChar(name=value["名称"], star=int(value["星级"]), limited=False)
|
||||
for value in self.load_data().values()
|
||||
]
|
||||
self.ALL_ARMS = [
|
||||
GuardianArms(name=value["名称"], star=int(value["星级"]), limited=False)
|
||||
for value in self.load_data("guardian_arms.json").values()
|
||||
]
|
||||
self.load_up_char()
|
||||
|
||||
def load_up_char(self):
|
||||
try:
|
||||
data = self.load_data(f"draw_card_up/{self.game_name}_up_char.json")
|
||||
self.UP_CHAR = UpEvent.parse_obj(data.get("char", {}))
|
||||
self.UP_ARMS = UpEvent.parse_obj(data.get("arms", {}))
|
||||
except ValidationError:
|
||||
logger.warning(f"{self.game_name}_up_char 解析出错")
|
||||
|
||||
def dump_up_char(self):
|
||||
if self.UP_CHAR and self.UP_ARMS:
|
||||
data = {
|
||||
"char": json.loads(self.UP_CHAR.json()),
|
||||
"arms": json.loads(self.UP_ARMS.json()),
|
||||
}
|
||||
self.dump_data(data, f"draw_card_up/{self.game_name}_up_char.json")
|
||||
|
||||
async def _update_info(self):
|
||||
# guardian.json
|
||||
guardian_info = {}
|
||||
url = "https://wiki.biligame.com/gt/英雄筛选表"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
else:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath("//table[@id='CardSelectTr']/tbody/tr")
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./td[1]/a/@title")[0]
|
||||
avatar = char.xpath("./td[1]/a/img/@src")[0]
|
||||
star = char.xpath("./td[1]/span/img/@alt")[0]
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar)),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"星级": int(str(star).split(" ")[0].replace("Rank", "")),
|
||||
}
|
||||
guardian_info[member_dict["名称"]] = member_dict
|
||||
self.dump_data(guardian_info)
|
||||
logger.info(f"{self.game_name_cn} 更新成功")
|
||||
# guardian_arms.json
|
||||
guardian_arms_info = {}
|
||||
url = "https://wiki.biligame.com/gt/武器"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 武器出错")
|
||||
else:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath(
|
||||
"//div[@class='resp-tabs-container']/div[1]/div/table[2]/tbody/tr"
|
||||
)
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./td[2]/a/@title")[0]
|
||||
avatar = char.xpath("./td[1]/div/div/div/a/img/@src")[0]
|
||||
star = char.xpath("./td[3]/text()")[0]
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar)),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"星级": int(str(star).strip()),
|
||||
}
|
||||
guardian_arms_info[member_dict["名称"]] = member_dict
|
||||
self.dump_data(guardian_arms_info, "guardian_arms.json")
|
||||
logger.info(f"{self.game_name_cn} 武器更新成功")
|
||||
url = "https://wiki.biligame.com/gt/盾牌"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 盾牌出错")
|
||||
else:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath(
|
||||
"//div[@class='resp-tabs-container']/div[2]/div/table[1]/tbody/tr"
|
||||
)
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./td[2]/a/@title")[0]
|
||||
avatar = char.xpath("./td[1]/div/div/div/a/img/@src")[0]
|
||||
star = char.xpath("./td[3]/text()")[0]
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar)),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"星级": int(str(star).strip()),
|
||||
}
|
||||
guardian_arms_info[member_dict["名称"]] = member_dict
|
||||
self.dump_data(guardian_arms_info, "guardian_arms.json")
|
||||
logger.info(f"{self.game_name_cn} 盾牌更新成功")
|
||||
# 下载头像
|
||||
for value in guardian_info.values():
|
||||
await self.download_img(value["头像"], value["名称"])
|
||||
for value in guardian_arms_info.values():
|
||||
await self.download_img(value["头像"], value["名称"])
|
||||
# 下载星星
|
||||
idx = 1
|
||||
GT_URL = "https://patchwiki.biligame.com/images/gt"
|
||||
for url in [
|
||||
"/4/4b/ardr3bi2yf95u4zomm263tc1vke6i3i.png",
|
||||
"/5/55/6vow7lh76gzus6b2g9cfn325d1sugca.png",
|
||||
"/b/b9/du8egrd2vyewg0cuyra9t8jh0srl0ds.png",
|
||||
]:
|
||||
await self.download_img(GT_URL + url, f"{idx}_star")
|
||||
idx += 1
|
||||
# 另一种星星
|
||||
idx = 1
|
||||
for url in [
|
||||
"/6/66/4e2tfa9kvhfcbikzlyei76i9crva145.png",
|
||||
"/1/10/r9ihsuvycgvsseyneqz4xs22t53026m.png",
|
||||
"/7/7a/o0k86ru9k915y04azc26hilxead7xp1.png",
|
||||
"/c/c9/rxz99asysz0rg391j3b02ta09mnpa7v.png",
|
||||
"/2/2a/sfxz0ucv1s6ewxveycz9mnmrqs2rw60.png",
|
||||
]:
|
||||
await self.download_img(GT_URL + url, f"{idx}_star_rank")
|
||||
idx += 1
|
||||
# 头像框
|
||||
await self.download_img(
|
||||
GT_URL + "/8/8e/ogbqslbhuykjhnc8trtoa0p0nhfzohs.png", f"avatar_frame"
|
||||
)
|
||||
await self.update_up_char()
|
||||
|
||||
async def update_up_char(self):
|
||||
url = "https://wiki.biligame.com/gt/首页"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"{self.game_name_cn}获取公告出错")
|
||||
return
|
||||
try:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
announcement = dom.xpath(
|
||||
"//div[@class='mw-parser-output']/div/div[3]/div[2]/div/div[2]/div[3]"
|
||||
)[0]
|
||||
title = announcement.xpath("./font/p/b/text()")[0]
|
||||
match = re.search(r"从(.*?)开始.*?至(.*?)结束", title)
|
||||
if not match:
|
||||
logger.warning(f"{self.game_name_cn}找不到UP时间")
|
||||
return
|
||||
start, end = match.groups()
|
||||
start_time = dateparser.parse(start.replace("月", "/").replace("日", ""))
|
||||
end_time = dateparser.parse(end.replace("月", "/").replace("日", ""))
|
||||
if not (start_time and end_time) or not (
|
||||
start_time <= datetime.now() <= end_time
|
||||
):
|
||||
return
|
||||
divs = announcement.xpath("./font/div")
|
||||
char_index = 0
|
||||
arms_index = 0
|
||||
for index, div in enumerate(divs):
|
||||
if div.xpath("string(.)") == "角色":
|
||||
char_index = index
|
||||
elif div.xpath("string(.)") == "武器":
|
||||
arms_index = index
|
||||
chars = divs[char_index + 1 : arms_index]
|
||||
arms = divs[arms_index + 1 :]
|
||||
up_chars = []
|
||||
up_arms = []
|
||||
for char in chars:
|
||||
name = char.xpath("./p/a/@title")[0]
|
||||
up_chars.append(UpChar(name=name, star=3, limited=False, zoom=0))
|
||||
for arm in arms:
|
||||
name = arm.xpath("./p/a/@title")[0]
|
||||
up_arms.append(UpChar(name=name, star=5, limited=False, zoom=0))
|
||||
self.UP_CHAR = UpEvent(
|
||||
title=title,
|
||||
pool_img="",
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_chars,
|
||||
)
|
||||
self.UP_ARMS = UpEvent(
|
||||
title=title,
|
||||
pool_img="",
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_arms,
|
||||
)
|
||||
self.dump_up_char()
|
||||
logger.info(f"成功获取{self.game_name_cn}当前up信息...当前up池: {title}")
|
||||
except Exception as e:
|
||||
logger.warning(f"{self.game_name_cn}UP更新出错 {type(e)}:{e}")
|
||||
|
||||
async def _reload_pool(self) -> Optional[Message]:
|
||||
await self.update_up_char()
|
||||
self.load_up_char()
|
||||
if self.UP_CHAR and self.UP_ARMS:
|
||||
return Message(f"重载成功!\n当前UP池子:{self.UP_CHAR.title}")
|
||||
@@ -0,0 +1,179 @@
|
||||
import random
|
||||
from lxml import etree
|
||||
from typing import List, Tuple
|
||||
from nonebot.log import logger
|
||||
from PIL import Image, ImageDraw
|
||||
from PIL.Image import Image as IMG
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
from .base_handle import BaseHandle, BaseData
|
||||
from ..config import draw_config
|
||||
from ..util import remove_prohibited_str, cn2py, load_font
|
||||
from utils.image_utils import BuildImage
|
||||
|
||||
|
||||
class OnmyojiChar(BaseData):
|
||||
@property
|
||||
def star_str(self) -> str:
|
||||
return ["N", "R", "SR", "SSR", "SP"][self.star - 1]
|
||||
|
||||
|
||||
class OnmyojiHandle(BaseHandle[OnmyojiChar]):
|
||||
def __init__(self):
|
||||
super().__init__("onmyoji", "阴阳师")
|
||||
self.max_star = 5
|
||||
self.config = draw_config.onmyoji
|
||||
self.ALL_CHAR: List[OnmyojiChar] = []
|
||||
|
||||
def get_card(self, **kwargs) -> OnmyojiChar:
|
||||
star = self.get_star(
|
||||
[5, 4, 3, 2],
|
||||
[
|
||||
self.config.ONMYOJI_SP,
|
||||
self.config.ONMYOJI_SSR,
|
||||
self.config.ONMYOJI_SR,
|
||||
self.config.ONMYOJI_R,
|
||||
],
|
||||
)
|
||||
chars = [x for x in self.ALL_CHAR if x.star == star and not x.limited]
|
||||
return random.choice(chars)
|
||||
|
||||
def format_max_star(self, card_list: List[Tuple[OnmyojiChar, int]]) -> str:
|
||||
rst = ""
|
||||
for card, index in card_list:
|
||||
if card.star == self.max_star:
|
||||
rst += f"第 {index} 抽获取SP {card.name}\n"
|
||||
elif card.star == self.max_star - 1:
|
||||
rst += f"第 {index} 抽获取SSR {card.name}\n"
|
||||
return rst.strip()
|
||||
|
||||
@staticmethod
|
||||
def star_label(star: int) -> IMG:
|
||||
text, color1, color2 = [
|
||||
("N", "#7E7E82", "#F5F6F7"),
|
||||
("R", "#014FA8", "#37C6FD"),
|
||||
("SR", "#6E0AA4", "#E94EFD"),
|
||||
("SSR", "#E5511D", "#FAF905"),
|
||||
("SP", "#FA1F2D", "#FFBBAF"),
|
||||
][star - 1]
|
||||
w = 200
|
||||
h = 110
|
||||
# 制作渐变色图片
|
||||
base = Image.new("RGBA", (w, h), color1)
|
||||
top = Image.new("RGBA", (w, h), color2)
|
||||
mask = Image.new("L", (w, h))
|
||||
mask_data = []
|
||||
for y in range(h):
|
||||
mask_data.extend([int(255 * (y / h))] * w)
|
||||
mask.putdata(mask_data)
|
||||
base.paste(top, (0, 0), mask)
|
||||
# 透明图层
|
||||
font = load_font("gorga.otf", 100)
|
||||
alpha = Image.new("L", (w, h))
|
||||
draw = ImageDraw.Draw(alpha)
|
||||
draw.text((20, -30), text, fill="white", font=font)
|
||||
base.putalpha(alpha)
|
||||
# stroke
|
||||
bg = Image.new("RGBA", (w, h))
|
||||
draw = ImageDraw.Draw(bg)
|
||||
draw.text(
|
||||
(20, -30),
|
||||
text,
|
||||
font=font,
|
||||
fill="gray",
|
||||
stroke_width=3,
|
||||
stroke_fill="gray",
|
||||
)
|
||||
bg.paste(base, (0, 0), base)
|
||||
return bg
|
||||
|
||||
def generate_img(self, card_list: List[OnmyojiChar]) -> BuildImage:
|
||||
return super().generate_img(card_list, num_per_line=10)
|
||||
|
||||
def generate_card_img(self, card: OnmyojiChar) -> BuildImage:
|
||||
bg = BuildImage(73, 240, color="#F1EFE9")
|
||||
img_path = str(self.img_path / f"{cn2py(card.name)}_mark_btn.png")
|
||||
img = BuildImage(0, 0, background=img_path)
|
||||
img = Image.open(img_path).convert("RGBA")
|
||||
label = self.star_label(card.star).resize((60, 33), Image.ANTIALIAS)
|
||||
bg.paste(img, (0, 0), alpha=True)
|
||||
bg.paste(label, (0, 135), alpha=True)
|
||||
font = load_font("msyh.ttf", 16)
|
||||
draw = ImageDraw.Draw(bg.markImg)
|
||||
text = "\n".join([t for t in card.name[:4]])
|
||||
_, text_h = font.getsize_multiline(text, spacing=0)
|
||||
draw.text(
|
||||
(40, 150 + (90 - text_h) / 2), text, font=font, fill="gray", spacing=0
|
||||
)
|
||||
return bg
|
||||
|
||||
def _init_data(self):
|
||||
self.ALL_CHAR = [
|
||||
OnmyojiChar(
|
||||
name=value["名称"],
|
||||
star=["N", "R", "SR", "SSR", "SP"].index(value["星级"]) + 1,
|
||||
limited=True
|
||||
if key
|
||||
in [
|
||||
"奴良陆生",
|
||||
"卖药郎",
|
||||
"鬼灯",
|
||||
"阿香",
|
||||
"蜜桃&芥子",
|
||||
"犬夜叉",
|
||||
"杀生丸",
|
||||
"桔梗",
|
||||
"朽木露琪亚",
|
||||
"黑崎一护",
|
||||
"灶门祢豆子",
|
||||
"灶门炭治郎",
|
||||
]
|
||||
else False,
|
||||
)
|
||||
for key, value in self.load_data().items()
|
||||
]
|
||||
|
||||
async def _update_info(self):
|
||||
info = {}
|
||||
url = "https://yys.res.netease.com/pc/zt/20161108171335/js/app/all_shishen.json?v74="
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
return
|
||||
data = json.loads(result)
|
||||
for x in data:
|
||||
name = remove_prohibited_str(x["name"])
|
||||
member_dict = {
|
||||
"id": x["id"],
|
||||
"名称": name,
|
||||
"星级": x["level"],
|
||||
}
|
||||
info[name] = member_dict
|
||||
# logger.info(f"{name} is update...")
|
||||
# 更新头像
|
||||
for key in info.keys():
|
||||
url = f'https://yys.163.com/shishen/{info[key]["id"]}.html'
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
info[key]["头像"] = ""
|
||||
continue
|
||||
try:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
avatar = dom.xpath("//div[@class='pic_wrap']/img/@src")[0]
|
||||
avatar = "https:" + avatar
|
||||
info[key]["头像"] = avatar
|
||||
except IndexError:
|
||||
info[key]["头像"] = ""
|
||||
logger.warning(f"{self.game_name_cn} 获取头像错误 {key}")
|
||||
self.dump_data(info)
|
||||
logger.info(f"{self.game_name_cn} 更新成功")
|
||||
# 下载头像
|
||||
for value in info.values():
|
||||
await self.download_img(value["头像"], value["名称"])
|
||||
# 下载书签形式的头像
|
||||
url = f"https://yys.res.netease.com/pc/zt/20161108171335/data/mark_btn/{value['id']}.png"
|
||||
await self.download_img(url, value["名称"] + "_mark_btn")
|
||||
@@ -0,0 +1,147 @@
|
||||
import random
|
||||
from lxml import etree
|
||||
from typing import List, Tuple
|
||||
from PIL import ImageDraw
|
||||
from urllib.parse import unquote
|
||||
from nonebot.log import logger
|
||||
|
||||
from .base_handle import BaseHandle, BaseData
|
||||
from ..config import draw_config
|
||||
from ..util import remove_prohibited_str, cn2py, load_font
|
||||
from utils.image_utils import BuildImage
|
||||
|
||||
|
||||
class PcrChar(BaseData):
|
||||
pass
|
||||
|
||||
|
||||
class PcrHandle(BaseHandle[PcrChar]):
|
||||
def __init__(self):
|
||||
super().__init__("pcr", "公主连结")
|
||||
self.max_star = 3
|
||||
self.config = draw_config.pcr
|
||||
self.ALL_CHAR: List[PcrChar] = []
|
||||
|
||||
def get_card(self, mode: int = 1) -> PcrChar:
|
||||
if mode == 2:
|
||||
star = self.get_star(
|
||||
[3, 2], [self.config.PCR_G_THREE_P, self.config.PCR_G_TWO_P]
|
||||
)
|
||||
else:
|
||||
star = self.get_star(
|
||||
[3, 2, 1],
|
||||
[self.config.PCR_THREE_P, self.config.PCR_TWO_P, self.config.PCR_ONE_P],
|
||||
)
|
||||
chars = [x for x in self.ALL_CHAR if x.star == star and not x.limited]
|
||||
return random.choice(chars)
|
||||
|
||||
def get_cards(self, count: int, **kwargs) -> List[Tuple[PcrChar, int]]:
|
||||
card_list = []
|
||||
card_count = 0 # 保底计算
|
||||
for i in range(count):
|
||||
card_count += 1
|
||||
# 十连保底
|
||||
if card_count == 10:
|
||||
card = self.get_card(2)
|
||||
card_count = 0
|
||||
else:
|
||||
card = self.get_card(1)
|
||||
if card.star > self.max_star - 2:
|
||||
card_count = 0
|
||||
card_list.append((card, i + 1))
|
||||
return card_list
|
||||
|
||||
def generate_card_img(self, card: PcrChar) -> BuildImage:
|
||||
sep_w = 5
|
||||
sep_h = 5
|
||||
star_h = 15
|
||||
img_w = 90
|
||||
img_h = 90
|
||||
font_h = 20
|
||||
bg = BuildImage(img_w + sep_w * 2, img_h + font_h + sep_h * 2, color="#EFF2F5")
|
||||
star_path = str(self.img_path / "star.png")
|
||||
star = BuildImage(star_h, star_h, background=star_path)
|
||||
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
|
||||
img = BuildImage(img_w, img_h, background=img_path)
|
||||
bg.paste(img, (sep_w, sep_h), alpha=True)
|
||||
for i in range(card.star):
|
||||
bg.paste(star, (sep_w + img_w - star_h * (i + 1), sep_h), alpha=True)
|
||||
# 加名字
|
||||
text = card.name[:5] + "..." if len(card.name) > 6 else card.name
|
||||
font = load_font(fontsize=14)
|
||||
text_w, text_h = font.getsize(text)
|
||||
draw = ImageDraw.Draw(bg.markImg)
|
||||
draw.text(
|
||||
(sep_w + (img_w - text_w) / 2, sep_h + img_h + (font_h - text_h) / 2),
|
||||
text,
|
||||
font=font,
|
||||
fill="gray",
|
||||
)
|
||||
return bg
|
||||
|
||||
def _init_data(self):
|
||||
self.ALL_CHAR = [
|
||||
PcrChar(
|
||||
name=value["名称"],
|
||||
star=int(value["星级"]),
|
||||
limited=True if "(" in key else False,
|
||||
)
|
||||
for key, value in self.load_data().items()
|
||||
]
|
||||
|
||||
async def _update_info(self):
|
||||
info = {}
|
||||
if draw_config.PCR_TAI:
|
||||
url = "https://wiki.biligame.com/pcr/角色图鉴"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
return
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath(
|
||||
"//div[@class='resp-tab-content']/div[@class='unit-icon']"
|
||||
)
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./a/@title")[0]
|
||||
avatar = char.xpath("./a/img/@srcset")[0]
|
||||
star = len(char.xpath("./div[1]/img"))
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"星级": star,
|
||||
}
|
||||
info[member_dict["名称"]] = member_dict
|
||||
else:
|
||||
url = "https://wiki.biligame.com/pcr/角色筛选表"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
return
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath("//table[@id='CardSelectTr']/tbody/tr")
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./td[1]/a/@title")[0]
|
||||
avatar = char.xpath("./td[1]/a/img/@srcset")[0]
|
||||
star = char.xpath("./td[4]/text()")[0]
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"星级": int(str(star).strip()),
|
||||
}
|
||||
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/pcr/0/02/s75ys2ecqhu2xbdw1wf1v9ccscnvi5g.png",
|
||||
"star",
|
||||
)
|
||||
@@ -0,0 +1,426 @@
|
||||
import re
|
||||
import random
|
||||
import dateparser
|
||||
from lxml import etree
|
||||
from PIL import ImageDraw
|
||||
from bs4 import BeautifulSoup
|
||||
from datetime import datetime
|
||||
from urllib.parse import unquote
|
||||
from typing import List, Optional, Tuple
|
||||
from pydantic import ValidationError
|
||||
from nonebot.adapters.onebot.v11 import Message
|
||||
from utils.message_builder import image
|
||||
from nonebot.log import logger
|
||||
import asyncio
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
from .base_handle import BaseHandle, BaseData, UpChar, UpEvent
|
||||
from ..config import draw_config
|
||||
from ..util import remove_prohibited_str, cn2py, load_font
|
||||
from utils.image_utils import BuildImage
|
||||
|
||||
|
||||
class PrettyData(BaseData):
|
||||
pass
|
||||
|
||||
|
||||
class PrettyChar(PrettyData):
|
||||
pass
|
||||
|
||||
|
||||
class PrettyCard(PrettyData):
|
||||
@property
|
||||
def star_str(self) -> str:
|
||||
return ["R", "SR", "SSR"][self.star - 1]
|
||||
|
||||
|
||||
class PrettyHandle(BaseHandle[PrettyData]):
|
||||
def __init__(self):
|
||||
super().__init__("pretty", "赛马娘", "#eff2f5")
|
||||
self.data_files.append("pretty_card.json")
|
||||
self.max_star = 3
|
||||
self.config = draw_config.pretty
|
||||
|
||||
self.ALL_CHAR: List[PrettyChar] = []
|
||||
self.ALL_CARD: List[PrettyCard] = []
|
||||
self.UP_CHAR: Optional[UpEvent] = None
|
||||
self.UP_CARD: Optional[UpEvent] = None
|
||||
|
||||
def get_card(self, pool_name: str, mode: int = 1) -> PrettyData:
|
||||
if mode == 1:
|
||||
star = self.get_star(
|
||||
[3, 2, 1],
|
||||
[
|
||||
self.config.PRETTY_THREE_P,
|
||||
self.config.PRETTY_TWO_P,
|
||||
self.config.PRETTY_ONE_P,
|
||||
],
|
||||
)
|
||||
else:
|
||||
star = self.get_star(
|
||||
[3, 2], [self.config.PRETTY_THREE_P, self.config.PRETTY_TWO_P]
|
||||
)
|
||||
up_pool = None
|
||||
if pool_name == "char":
|
||||
up_pool = self.UP_CHAR
|
||||
all_list = self.ALL_CHAR
|
||||
else:
|
||||
up_pool = self.UP_CARD
|
||||
all_list = self.ALL_CARD
|
||||
|
||||
all_char = [x for x in all_list if x.star == star and not x.limited]
|
||||
acquire_char = None
|
||||
# 有UP池子
|
||||
if up_pool and star in [x.star for x in up_pool.up_char]:
|
||||
up_list = [x.name for x in up_pool.up_char if x.star == star]
|
||||
# 抽到UP
|
||||
if random.random() < 1 / len(all_char) * (0.7 / 0.1385):
|
||||
up_name = random.choice(up_list)
|
||||
try:
|
||||
acquire_char = [x for x in all_list if x.name == up_name][0]
|
||||
except IndexError:
|
||||
pass
|
||||
if not acquire_char:
|
||||
acquire_char = random.choice(all_char)
|
||||
return acquire_char
|
||||
|
||||
def get_cards(self, count: int, pool_name: str) -> List[Tuple[PrettyData, int]]:
|
||||
card_list = []
|
||||
card_count = 0 # 保底计算
|
||||
for i in range(count):
|
||||
card_count += 1
|
||||
# 十连保底
|
||||
if card_count == 10:
|
||||
card = self.get_card(pool_name, 2)
|
||||
card_count = 0
|
||||
else:
|
||||
card = self.get_card(pool_name, 1)
|
||||
if card.star > self.max_star - 2:
|
||||
card_count = 0
|
||||
card_list.append((card, i + 1))
|
||||
return card_list
|
||||
|
||||
def format_pool_info(self, pool_name: str) -> str:
|
||||
info = ""
|
||||
up_event = self.UP_CHAR if pool_name == "char" else self.UP_CARD
|
||||
if up_event:
|
||||
star3_list = [x.name for x in up_event.up_char if x.star == 3]
|
||||
star2_list = [x.name for x in up_event.up_char if x.star == 2]
|
||||
star1_list = [x.name for x in up_event.up_char if x.star == 1]
|
||||
if star3_list:
|
||||
if pool_name == "char":
|
||||
info += f'三星UP:{" ".join(star3_list)}\n'
|
||||
else:
|
||||
info += f'SSR UP:{" ".join(star3_list)}\n'
|
||||
if star2_list:
|
||||
if pool_name == "char":
|
||||
info += f'二星UP:{" ".join(star2_list)}\n'
|
||||
else:
|
||||
info += f'SR UP:{" ".join(star2_list)}\n'
|
||||
if star1_list:
|
||||
if pool_name == "char":
|
||||
info += f'一星UP:{" ".join(star1_list)}\n'
|
||||
else:
|
||||
info += f'R UP:{" ".join(star1_list)}\n'
|
||||
info = f"当前up池:{up_event.title}\n{info}"
|
||||
return info.strip()
|
||||
|
||||
async def draw(self, count: int, pool_name: str, **kwargs) -> Message:
|
||||
return await asyncio.get_event_loop().run_in_executor(None, self._draw, count, pool_name)
|
||||
|
||||
def _draw(self, count: int, pool_name: str, **kwargs) -> Message:
|
||||
pool_name = "char" if not pool_name else pool_name
|
||||
index2card = self.get_cards(count, pool_name)
|
||||
cards = [card[0] for card in index2card]
|
||||
up_event = self.UP_CHAR if pool_name == "char" else self.UP_CARD
|
||||
up_list = [x.name for x in up_event.up_char] if up_event else []
|
||||
result = self.format_result(index2card, up_list=up_list)
|
||||
pool_info = self.format_pool_info(pool_name)
|
||||
return pool_info + image(b64=self.generate_img(cards).pic2bs4()) + result
|
||||
|
||||
def generate_card_img(self, card: PrettyData) -> BuildImage:
|
||||
if isinstance(card, PrettyChar):
|
||||
star_h = 30
|
||||
img_w = 200
|
||||
img_h = 219
|
||||
font_h = 50
|
||||
bg = BuildImage(img_w, img_h + font_h, color="#EFF2F5")
|
||||
star_path = str(self.img_path / "star.png")
|
||||
star = BuildImage(star_h, star_h, background=star_path)
|
||||
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
|
||||
img = BuildImage(img_w, img_h, background=img_path)
|
||||
star_w = star_h * card.star
|
||||
for i in range(card.star):
|
||||
bg.paste(star, (int((img_w - star_w) / 2) + star_h * i, 0), alpha=True)
|
||||
bg.paste(img, (0, 0), alpha=True)
|
||||
# 加名字
|
||||
text = card.name[:5] + "..." if len(card.name) > 6 else card.name
|
||||
font = load_font(fontsize=30)
|
||||
text_w, _ = font.getsize(text)
|
||||
draw = ImageDraw.Draw(bg.markImg)
|
||||
draw.text(
|
||||
((img_w - text_w) / 2, img_h),
|
||||
text,
|
||||
font=font,
|
||||
fill="gray",
|
||||
)
|
||||
return bg
|
||||
else:
|
||||
sep_w = 10
|
||||
img_w = 200
|
||||
img_h = 267
|
||||
font_h = 75
|
||||
bg = BuildImage(img_w + sep_w * 2, img_h + font_h, color="#EFF2F5")
|
||||
label_path = str(self.img_path / f"{card.star}_label.png")
|
||||
label = BuildImage(40, 40, background=label_path)
|
||||
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
|
||||
img = BuildImage(img_w, img_h, background=img_path)
|
||||
bg.paste(img, (sep_w, 0), alpha=True)
|
||||
bg.paste(label, (30, 3), alpha=True)
|
||||
# 加名字
|
||||
text = ""
|
||||
texts = []
|
||||
font = load_font(fontsize=25)
|
||||
for t in card.name:
|
||||
if font.getsize(text + t)[0] > 190:
|
||||
texts.append(text)
|
||||
text = ""
|
||||
if len(texts) >= 2:
|
||||
texts[-1] += "..."
|
||||
break
|
||||
else:
|
||||
text += t
|
||||
if text:
|
||||
texts.append(text)
|
||||
text = "\n".join(texts)
|
||||
text_w, _ = font.getsize_multiline(text)
|
||||
draw = ImageDraw.Draw(bg.markImg)
|
||||
draw.text(
|
||||
((img_w - text_w) / 2, img_h),
|
||||
text,
|
||||
font=font,
|
||||
align="center",
|
||||
fill="gray",
|
||||
)
|
||||
return bg
|
||||
|
||||
def _init_data(self):
|
||||
self.ALL_CHAR = [
|
||||
PrettyChar(
|
||||
name=value["名称"],
|
||||
star=int(value["初始星级"]),
|
||||
limited=False,
|
||||
)
|
||||
for value in self.load_data().values()
|
||||
]
|
||||
self.ALL_CARD = [
|
||||
PrettyCard(
|
||||
name=value["中文名"],
|
||||
star=["R", "SR", "SSR"].index(value["稀有度"]) + 1,
|
||||
limited=True if "卡池" not in value["获取方式"] else False,
|
||||
)
|
||||
for value in self.load_data("pretty_card.json").values()
|
||||
]
|
||||
self.load_up_char()
|
||||
|
||||
def load_up_char(self):
|
||||
try:
|
||||
data = self.load_data(f"draw_card_up/{self.game_name}_up_char.json")
|
||||
self.UP_CHAR = UpEvent.parse_obj(data.get("char", {}))
|
||||
self.UP_CARD = UpEvent.parse_obj(data.get("card", {}))
|
||||
except ValidationError:
|
||||
logger.warning(f"{self.game_name}_up_char 解析出错")
|
||||
|
||||
def dump_up_char(self):
|
||||
if self.UP_CHAR and self.UP_CARD:
|
||||
data = {
|
||||
"char": json.loads(self.UP_CHAR.json()),
|
||||
"card": json.loads(self.UP_CARD.json()),
|
||||
}
|
||||
self.dump_data(data, f"draw_card_up/{self.game_name}_up_char.json")
|
||||
|
||||
async def _update_info(self):
|
||||
# pretty.json
|
||||
pretty_info = {}
|
||||
url = "https://wiki.biligame.com/umamusume/赛马娘图鉴"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
else:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath("//table[@id='CardSelectTr']/tbody/tr")
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./td[1]/a/@title")[0]
|
||||
avatar = char.xpath("./td[1]/a/img/@srcset")[0]
|
||||
star = len(char.xpath("./td[3]/img"))
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"初始星级": star,
|
||||
}
|
||||
pretty_info[member_dict["名称"]] = member_dict
|
||||
self.dump_data(pretty_info)
|
||||
logger.info(f"{self.game_name_cn} 更新成功")
|
||||
# pretty_card.json
|
||||
pretty_card_info = {}
|
||||
url = "https://wiki.biligame.com/umamusume/支援卡图鉴"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 卡牌出错")
|
||||
else:
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath("//table[@id='CardSelectTr']/tbody/tr")
|
||||
for char in char_list:
|
||||
try:
|
||||
name = char.xpath("./td[1]/div/a/@title")[0]
|
||||
name_cn = char.xpath("./td[3]/a/text()")[0]
|
||||
avatar = char.xpath("./td[1]/div/a/img/@srcset")[0]
|
||||
star = str(char.xpath("./td[5]/text()")[0]).strip()
|
||||
sources = str(char.xpath("./td[7]/text()")[0]).strip()
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||
"名称": remove_prohibited_str(name),
|
||||
"中文名": remove_prohibited_str(name_cn),
|
||||
"稀有度": star,
|
||||
"获取方式": [sources] if sources else [],
|
||||
}
|
||||
pretty_card_info[member_dict["中文名"]] = member_dict
|
||||
self.dump_data(pretty_card_info, "pretty_card.json")
|
||||
logger.info(f"{self.game_name_cn} 卡牌更新成功")
|
||||
# 下载头像
|
||||
for value in pretty_info.values():
|
||||
await self.download_img(value["头像"], value["名称"])
|
||||
for value in pretty_card_info.values():
|
||||
await self.download_img(value["头像"], value["中文名"])
|
||||
# 下载星星
|
||||
PRETTY_URL = "https://patchwiki.biligame.com/images/umamusume"
|
||||
await self.download_img(
|
||||
PRETTY_URL + "/1/13/e1hwjz4vmhtvk8wlyb7c0x3ld1s2ata.png", "star"
|
||||
)
|
||||
# 下载稀有度标志
|
||||
idx = 1
|
||||
for url in [
|
||||
"/f/f7/afqs7h4snmvovsrlifq5ib8vlpu2wvk.png",
|
||||
"/3/3b/d1jmpwrsk4irkes1gdvoos4ic6rmuht.png",
|
||||
"/0/06/q23szwkbtd7pfkqrk3wcjlxxt9z595o.png",
|
||||
]:
|
||||
await self.download_img(PRETTY_URL + url, f"{idx}_label")
|
||||
idx += 1
|
||||
await self.update_up_char()
|
||||
|
||||
async def update_up_char(self):
|
||||
announcement_url = "https://wiki.biligame.com/umamusume/公告"
|
||||
result = await self.get_url(announcement_url)
|
||||
if not result:
|
||||
logger.warning(f"{self.game_name_cn}获取公告出错")
|
||||
return
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
announcements = dom.xpath("//div[@id='mw-content-text']/div/div/span/a")
|
||||
title = ""
|
||||
url = ""
|
||||
for announcement in announcements:
|
||||
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
|
||||
):
|
||||
break
|
||||
except IndexError:
|
||||
continue
|
||||
if not title:
|
||||
logger.warning(f"{self.game_name_cn}未找到新UP公告")
|
||||
return
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"{self.game_name_cn}获取UP公告出错")
|
||||
return
|
||||
try:
|
||||
start_time = None
|
||||
end_time = None
|
||||
char_img = ""
|
||||
card_img = ""
|
||||
up_chars = []
|
||||
up_cards = []
|
||||
soup = BeautifulSoup(result, "lxml")
|
||||
heads = soup.find_all("span", {"class": "mw-headline"})
|
||||
for head in heads:
|
||||
if "时间" in head.text:
|
||||
time = head.find_next("p").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")
|
||||
chars = [
|
||||
line
|
||||
for line in lines
|
||||
if "★" in line and "(" in line and ")" in line
|
||||
]
|
||||
for char in chars:
|
||||
star = char.count("★")
|
||||
name = re.split(r"[()]", char)[-2].strip()
|
||||
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")
|
||||
cards = [
|
||||
line
|
||||
for line in lines
|
||||
if "R" in line and "(" in line and ")" in line
|
||||
]
|
||||
for card in cards:
|
||||
star = 3 if "SSR" in card else 2 if "SR" in card else 1
|
||||
name = re.split(r"[()]", card)[-2].strip()
|
||||
up_cards.append(
|
||||
UpChar(name=name, star=star, limited=False, zoom=70)
|
||||
)
|
||||
if start_time and end_time:
|
||||
if start_time <= datetime.now() <= end_time:
|
||||
self.UP_CHAR = UpEvent(
|
||||
title=title,
|
||||
pool_img=char_img,
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_chars,
|
||||
)
|
||||
self.UP_CARD = UpEvent(
|
||||
title=title,
|
||||
pool_img=card_img,
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_cards,
|
||||
)
|
||||
self.dump_up_char()
|
||||
logger.info(f"成功获取{self.game_name_cn}当前up信息...当前up池: {title}")
|
||||
except Exception as e:
|
||||
logger.warning(f"{self.game_name_cn}UP更新出错 {type(e)}:{e}")
|
||||
|
||||
async def _reload_pool(self) -> Optional[Message]:
|
||||
await self.update_up_char()
|
||||
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,
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,292 @@
|
||||
import re
|
||||
import random
|
||||
import dateparser
|
||||
from lxml import etree
|
||||
from PIL import ImageDraw
|
||||
from bs4 import BeautifulSoup
|
||||
from datetime import datetime
|
||||
from urllib.parse import unquote
|
||||
from typing import List, Optional, Tuple
|
||||
from pydantic import ValidationError
|
||||
from nonebot.adapters.onebot.v11 import Message
|
||||
from utils.message_builder import image
|
||||
from nonebot.log import logger
|
||||
import asyncio
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
from .base_handle import BaseHandle, BaseData, UpChar, UpEvent
|
||||
from ..config import draw_config
|
||||
from ..util import remove_prohibited_str, cn2py, load_font
|
||||
from utils.image_utils import BuildImage
|
||||
|
||||
|
||||
class Operator(BaseData):
|
||||
recruit_only: bool # 公招限定
|
||||
event_only: bool # 活动获得干员
|
||||
# special_only: bool # 升变/异格干员
|
||||
|
||||
|
||||
class PrtsHandle(BaseHandle[Operator]):
|
||||
def __init__(self):
|
||||
super().__init__("prts", "明日方舟", "#eff2f5")
|
||||
self.max_star = 6
|
||||
self.config = draw_config.prts
|
||||
|
||||
self.ALL_OPERATOR: List[Operator] = []
|
||||
self.UP_EVENT: Optional[UpEvent] = None
|
||||
|
||||
def get_card(self, add: float) -> Operator:
|
||||
star = self.get_star(
|
||||
[6, 5, 4, 3],
|
||||
[
|
||||
self.config.PRTS_SIX_P + add,
|
||||
self.config.PRTS_FIVE_P,
|
||||
self.config.PRTS_FOUR_P,
|
||||
self.config.PRTS_THREE_P,
|
||||
],
|
||||
)
|
||||
|
||||
all_operators = [
|
||||
x
|
||||
for x in self.ALL_OPERATOR
|
||||
if x.star == star and not any([x.limited, x.event_only, x.recruit_only])
|
||||
]
|
||||
acquire_operator = None
|
||||
|
||||
if self.UP_EVENT:
|
||||
up_operators = [x for x in self.UP_EVENT.up_char if x.star == star]
|
||||
# UPs
|
||||
try:
|
||||
zooms = [x.zoom for x in up_operators]
|
||||
zoom_sum = sum(zooms)
|
||||
if random.random() < zoom_sum:
|
||||
up_name = random.choices(up_operators, weights=zooms, k=1)[0].name
|
||||
acquire_operator = [
|
||||
x for x in self.ALL_OPERATOR if x.name == up_name
|
||||
][0]
|
||||
except IndexError:
|
||||
pass
|
||||
if not acquire_operator:
|
||||
acquire_operator = random.choice(all_operators)
|
||||
return acquire_operator
|
||||
|
||||
def get_cards(self, count: int) -> List[Tuple[Operator, int]]:
|
||||
card_list = [] # 获取所有角色
|
||||
add = 0.0
|
||||
count_idx = 0
|
||||
for i in range(count):
|
||||
count_idx += 1
|
||||
card = self.get_card(add)
|
||||
if card.star == self.max_star:
|
||||
add = 0.0
|
||||
count_idx = 0
|
||||
elif count_idx > 50:
|
||||
add += 0.02
|
||||
card_list.append((card, i + 1))
|
||||
return card_list
|
||||
|
||||
def format_pool_info(self) -> str:
|
||||
info = ""
|
||||
if self.UP_EVENT:
|
||||
star6_list = [x.name for x in self.UP_EVENT.up_char if x.star == 6]
|
||||
star5_list = [x.name for x in self.UP_EVENT.up_char if x.star == 5]
|
||||
star4_list = [x.name for x in self.UP_EVENT.up_char if x.star == 4]
|
||||
if star6_list:
|
||||
info += f"六星UP:{' '.join(star6_list)}\n"
|
||||
if star5_list:
|
||||
info += f"五星UP:{' '.join(star5_list)}\n"
|
||||
if star4_list:
|
||||
info += f"四星UP:{' '.join(star4_list)}\n"
|
||||
info = f"当前up池: {self.UP_EVENT.title}\n{info}"
|
||||
return info.strip()
|
||||
|
||||
async def draw(self, count: int, **kwargs) -> Message:
|
||||
return await asyncio.get_event_loop().run_in_executor(None, self._draw, count)
|
||||
|
||||
def _draw(self, count: int, **kwargs) -> Message:
|
||||
index2card = self.get_cards(count)
|
||||
cards = [card[0] for card in self.get_cards(count)]
|
||||
up_list = [x.name for x in self.UP_EVENT.up_char] if self.UP_EVENT else []
|
||||
result = self.format_result(index2card, up_list=up_list)
|
||||
pool_info = self.format_pool_info()
|
||||
return pool_info + image(b64=self.generate_img(cards).pic2bs4()) + result
|
||||
|
||||
def generate_card_img(self, card: Operator) -> BuildImage:
|
||||
sep_w = 5
|
||||
sep_h = 5
|
||||
star_h = 15
|
||||
img_w = 120
|
||||
img_h = 120
|
||||
font_h = 20
|
||||
bg = BuildImage(img_w + sep_w * 2, img_h + font_h + sep_h * 2, color="#EFF2F5")
|
||||
star_path = str(self.img_path / "star.png")
|
||||
star = BuildImage(star_h, star_h, background=star_path)
|
||||
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
|
||||
img = BuildImage(img_w, img_h, background=img_path)
|
||||
bg.paste(img, (sep_w, sep_h), alpha=True)
|
||||
for i in range(card.star):
|
||||
bg.paste(star, (sep_w + img_w - 5 - star_h * (i + 1), sep_h), alpha=True)
|
||||
# 加名字
|
||||
text = card.name[:7] + "..." if len(card.name) > 8 else card.name
|
||||
font = load_font(fontsize=16)
|
||||
text_w, text_h = font.getsize(text)
|
||||
draw = ImageDraw.Draw(bg.markImg)
|
||||
draw.text(
|
||||
(sep_w + (img_w - text_w) / 2, sep_h + img_h + (font_h - text_h) / 2),
|
||||
text,
|
||||
font=font,
|
||||
fill="gray",
|
||||
)
|
||||
return bg
|
||||
|
||||
def _init_data(self):
|
||||
self.ALL_OPERATOR = [
|
||||
Operator(
|
||||
name=value["名称"],
|
||||
star=int(value["星级"]),
|
||||
limited="干员寻访" not in value["获取途径"],
|
||||
recruit_only=True
|
||||
if "干员寻访" not in value["获取途径"] and "公开招募" in value["获取途径"]
|
||||
else False,
|
||||
event_only=True if "活动获取" in value["获取途径"] else False,
|
||||
)
|
||||
for key, value in self.load_data().items()
|
||||
if "阿米娅" not in key
|
||||
]
|
||||
self.load_up_char()
|
||||
|
||||
def load_up_char(self):
|
||||
try:
|
||||
data = self.load_data(f"draw_card_up/{self.game_name}_up_char.json")
|
||||
self.UP_EVENT = UpEvent.parse_obj(data.get("char", {}))
|
||||
except ValidationError:
|
||||
logger.warning(f"{self.game_name}_up_char 解析出错")
|
||||
|
||||
def dump_up_char(self):
|
||||
if self.UP_EVENT:
|
||||
data = {"char": json.loads(self.UP_EVENT.json())}
|
||||
self.dump_data(data, f"draw_card_up/{self.game_name}_up_char.json")
|
||||
|
||||
async def _update_info(self):
|
||||
info = {}
|
||||
url = "https://wiki.biligame.com/arknights/干员数据表"
|
||||
result = await self.get_url(url)
|
||||
if not result:
|
||||
logger.warning(f"更新 {self.game_name_cn} 出错")
|
||||
return
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
char_list = dom.xpath("//table[@id='CardSelectTr']/tbody/tr")
|
||||
for char in char_list:
|
||||
try:
|
||||
avatar = char.xpath("./td[1]/div/div/div/a/img/@srcset")[0]
|
||||
name = char.xpath("./td[2]/a/text()")[0]
|
||||
star = char.xpath("./td[5]/text()")[0]
|
||||
sources = str(char.xpath("./td[8]/text()")[0]).split("\n")
|
||||
except IndexError:
|
||||
continue
|
||||
member_dict = {
|
||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||
"名称": remove_prohibited_str(str(name).strip()),
|
||||
"星级": int(str(star).strip()),
|
||||
"获取途径": [s for s in sources if s],
|
||||
}
|
||||
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/pcr/0/02/s75ys2ecqhu2xbdw1wf1v9ccscnvi5g.png",
|
||||
"star",
|
||||
)
|
||||
await self.update_up_char()
|
||||
|
||||
async def update_up_char(self):
|
||||
announcement_url = "https://ak.hypergryph.com/news.html"
|
||||
result = await self.get_url(announcement_url)
|
||||
if not result:
|
||||
logger.warning(f"{self.game_name_cn}获取公告出错")
|
||||
return
|
||||
dom = etree.HTML(result, etree.HTMLParser())
|
||||
activity_urls = dom.xpath(
|
||||
"//ol[@class='articleList' and @data-category-key='ACTIVITY']/li/a/@href"
|
||||
)
|
||||
start_time = None
|
||||
end_time = None
|
||||
up_chars = []
|
||||
pool_img = ""
|
||||
title = ""
|
||||
for activity_url in activity_urls:
|
||||
activity_url = f"https://ak.hypergryph.com{activity_url}"
|
||||
result = await self.get_url(activity_url)
|
||||
if not result:
|
||||
logger.warning(f"{self.game_name_cn}获取公告 {activity_url} 出错")
|
||||
continue
|
||||
soup = BeautifulSoup(result, "lxml")
|
||||
contents = soup.find_all("p")
|
||||
for index, content in enumerate(contents):
|
||||
if re.search("(.*)(寻访|复刻).*?开启", content.text):
|
||||
title = content.text
|
||||
if "【" in title and "】" in title:
|
||||
title = re.split(r"[【】]", title)[1]
|
||||
lines = [str(contents[index + i + 1].text) for i in range(5)]
|
||||
time = ""
|
||||
chars: List[str] = []
|
||||
for line in lines:
|
||||
match = re.search(
|
||||
r"(\d{1,2}月\d{1,2}日.*?-.*?\d{1,2}月\d{1,2}日.*?$)", line
|
||||
)
|
||||
if match:
|
||||
time = match.group(1)
|
||||
if "★" in line:
|
||||
chars.append(line)
|
||||
if not time:
|
||||
continue
|
||||
start, end = time.replace("月", "/").replace("日", "").split("-")[:2]
|
||||
start_time = dateparser.parse(start)
|
||||
end_time = dateparser.parse(end)
|
||||
pool_img = content.find_previous("img")["src"]
|
||||
for char in chars:
|
||||
star = char.split("(")[0].count("★")
|
||||
name = re.split(r"[:(]", char)[1]
|
||||
names = name.split("/") if "/" in name else [name]
|
||||
names = [name.replace("[限定]", "").strip() for name in names]
|
||||
if "权值" in char:
|
||||
match = re.search(r"(在.*?以.*?(\d+).*?倍权值.*?)", char)
|
||||
else:
|
||||
match = re.search(r"(占.*?的.*?(\d+).*?%)", char)
|
||||
zoom = 1
|
||||
if match:
|
||||
zoom = float(match.group(1))
|
||||
zoom = zoom / 100 if zoom > 10 else zoom
|
||||
for name in names:
|
||||
up_chars.append(
|
||||
UpChar(name=name, star=star, limited=False, zoom=zoom)
|
||||
)
|
||||
break
|
||||
if title and start_time and end_time:
|
||||
if start_time <= datetime.now() <= end_time:
|
||||
self.UP_EVENT = UpEvent(
|
||||
title=title,
|
||||
pool_img=pool_img,
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
up_char=up_chars,
|
||||
)
|
||||
self.dump_up_char()
|
||||
logger.info(f"成功获取{self.game_name_cn}当前up信息...当前up池: {title}")
|
||||
break
|
||||
|
||||
async def _reload_pool(self) -> Optional[Message]:
|
||||
await self.update_up_char()
|
||||
self.load_up_char()
|
||||
if self.UP_EVENT:
|
||||
return f"重载成功!\n当前UP池子:{self.UP_EVENT.title}" + image(
|
||||
self.UP_EVENT.pool_img
|
||||
)
|
||||
@@ -1,137 +0,0 @@
|
||||
from typing import Any
|
||||
from .config import DATA_PATH
|
||||
from utils.utils import is_number
|
||||
from pathlib import Path
|
||||
from services.log import logger
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
def init_game_pool(game: str, data: dict, Operator: Any):
|
||||
tmp_lst = []
|
||||
if game == 'prts':
|
||||
for key in data.keys():
|
||||
limited = False
|
||||
recruit_only = False
|
||||
event_only = False
|
||||
if '限定寻访' in data[key]['获取途径']:
|
||||
limited = True
|
||||
if '干员寻访' not in data[key]['获取途径'] and '公开招募' in data[key]['获取途径']:
|
||||
recruit_only = True
|
||||
if '活动获取' in data[key]['获取途径']:
|
||||
event_only = True
|
||||
if '干员寻访' not in data[key]['获取途径'] and '凭证交易所' == data[key]['获取途径'][0]:
|
||||
limited = True
|
||||
if '干员寻访' not in data[key]['获取途径'] and '信用累计奖励' == data[key]['获取途径'][0]:
|
||||
limited = True
|
||||
if key.find('阿米娅') != -1:
|
||||
continue
|
||||
try:
|
||||
tmp_lst.append(Operator(name=key, star=int(data[key]['星级']),
|
||||
limited=limited, recruit_only=recruit_only, event_only=event_only))
|
||||
except Exception as e:
|
||||
logger.warning(f"明日方舟导入角色 {key} 数据错误:{type(e)}:{e}")
|
||||
if game == 'genshin':
|
||||
for key in data.keys():
|
||||
if key.find('旅行者') != -1:
|
||||
continue
|
||||
limited = False
|
||||
if data[key]['常驻/限定'] == '限定UP':
|
||||
limited = True
|
||||
try:
|
||||
tmp_lst.append(Operator(name=key, star=int(data[key]['稀有度'][:1]), limited=limited))
|
||||
except Exception as e:
|
||||
logger.warning(f"原神导入角色 {key} 数据错误:{type(e)}:{e}")
|
||||
if game == 'genshin_arms':
|
||||
for key in data.keys():
|
||||
if data[key]['获取途径'].find('祈愿') != -1:
|
||||
limited = False
|
||||
if data[key]['获取途径'].find('限定祈愿') != -1:
|
||||
limited = True
|
||||
try:
|
||||
tmp_lst.append(Operator(name=key, star=int(data[key]['稀有度'][:1]), limited=limited))
|
||||
except Exception as e:
|
||||
logger.warning(f"原神导入武器 {key} 数据错误:{type(e)}:{e}")
|
||||
if game == 'pretty':
|
||||
for key in data.keys():
|
||||
try:
|
||||
tmp_lst.append(Operator(name=key, star=data[key]['初始星级'], limited=False))
|
||||
except Exception as e:
|
||||
logger.warning(f"赛马娘导入角色 {key} 数据错误:{type(e)}:{e}")
|
||||
if game == 'pretty_card':
|
||||
for key in data.keys():
|
||||
limited = False
|
||||
if '卡池' not in data[key]['获取方式']:
|
||||
limited = True
|
||||
if not data[key]['获取方式']:
|
||||
limited = False
|
||||
try:
|
||||
tmp_lst.append(Operator(name=data[key]['中文名'], star=len(data[key]['稀有度']), limited=limited))
|
||||
except Exception as e:
|
||||
logger.warning(f"赛马娘导入卡片 {key} 数据错误:{type(e)}:{e}")
|
||||
if game in ['guardian', 'guardian_arms']:
|
||||
for key in data.keys():
|
||||
tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), limited=False))
|
||||
if game == 'pcr':
|
||||
for key in data.keys():
|
||||
limited = False
|
||||
if key.find('(') != -1:
|
||||
limited = True
|
||||
try:
|
||||
tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), limited=limited))
|
||||
except Exception as e:
|
||||
logger.warning(f"公主连接导入角色 {key} 数据错误:{type(e)}:{e}")
|
||||
if game == 'azur':
|
||||
for key in data.keys():
|
||||
if is_number(data[key]['星级']):
|
||||
limited = False
|
||||
if '可以建造' not in data[key]['获取途径']:
|
||||
limited = True
|
||||
try:
|
||||
tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']),
|
||||
limited=limited, itype=data[key]['类型']))
|
||||
except Exception as e:
|
||||
logger.warning(f"碧蓝航线导入角色 {key} 数据错误:{type(e)}:{e}")
|
||||
if game in ['fgo', 'fgo_card']:
|
||||
for key in data.keys():
|
||||
limited = False
|
||||
try:
|
||||
if "圣晶石召唤" not in data[key]['入手方式'] and "圣晶石召唤(Story卡池)" not in data[key]['入手方式']:
|
||||
limited = True
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), limited=limited))
|
||||
except Exception as e:
|
||||
logger.warning(f"FGO导入角色 {key} 数据错误:{type(e)}:{e}")
|
||||
if game == 'onmyoji':
|
||||
for key in data.keys():
|
||||
limited = False
|
||||
if key in ['奴良陆生', '卖药郎', '鬼灯', '阿香', '蜜桃&芥子', '犬夜叉', '杀生丸', '桔梗', '朽木露琪亚', '黑崎一护',
|
||||
'灶门祢豆子', '灶门炭治郎']:
|
||||
limited = True
|
||||
try:
|
||||
tmp_lst.append(Operator(name=data[key]['名称'], star=data[key]['星级'], limited=limited))
|
||||
except Exception as e:
|
||||
logger.warning(f"阴阳师导入角色 {key} 数据错误:{type(e)}:{e}")
|
||||
# print(tmp_lst)
|
||||
char_name_lst = [x.name for x in tmp_lst]
|
||||
up_char_file = Path(f'{DATA_PATH}/draw_card/draw_card_up/{game.split("_")[0]}_up_char.json')
|
||||
if up_char_file.exists():
|
||||
data = json.load(open(up_char_file, 'r', encoding='utf8'))
|
||||
if len(game.split('_')) == 1:
|
||||
key = 'char'
|
||||
else:
|
||||
key = list(data.keys())[1]
|
||||
for x in data[key]['up_char']:
|
||||
for char in data[key]['up_char'][x]:
|
||||
if char not in char_name_lst:
|
||||
if game.find('prts') != -1:
|
||||
tmp_lst.append(Operator(name=char, star=int(x),
|
||||
recruit_only=False, event_only=False, limited=False))
|
||||
else:
|
||||
tmp_lst.append(Operator(name=char, star=int(x), limited=False))
|
||||
return tmp_lst
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user