Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74e9c55a09 | ||
|
|
d4d6e736a4 | ||
|
|
5cf9938fa2 | ||
|
|
72ad0ad983 | ||
|
|
690750d91e | ||
|
|
9f1dfc4b9c | ||
|
|
05eab5307f | ||
|
|
b0fe70c960 | ||
|
|
09d7992bc4 | ||
|
|
c832a432c1 | ||
|
|
41c22f4314 | ||
|
|
252d45c79b | ||
|
|
ae8a214a3a | ||
|
|
86ce6d7664 | ||
|
|
67e96d6106 | ||
|
|
24d9ec2b75 | ||
|
|
501e47c6ec | ||
|
|
5534a5a5c2 | ||
|
|
7246aabf40 | ||
|
|
604ffae87e | ||
|
|
2d5c16456b | ||
|
|
d44f7633dc | ||
|
|
469ac4035c | ||
|
|
dab218a6d7 | ||
|
|
d6fc675d57 | ||
|
|
04148f7365 | ||
|
|
4c34ac570f | ||
|
|
fbdb8758a3 | ||
|
|
2d08747d70 | ||
|
|
0b4bacbbd1 | ||
|
|
e0412c7edb | ||
|
|
38501cebf1 | ||
|
|
ee45d0217e | ||
|
|
558f362919 | ||
|
|
fb9db2f50c | ||
|
|
374b7b7261 |
@@ -243,10 +243,36 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
||||
|
||||
## 更新
|
||||
|
||||
### 2022/5/29 \[v0.1.5.7]
|
||||
### 2022/6/5 \[v0.1.5.9]
|
||||
|
||||
* webui修复plugin2setting中cmd从list转变为str
|
||||
* 当命令`我的金币`被风控时将以图片形式发送
|
||||
* fix gold_redbag [@pull/763](https://github.com/HibiKier/zhenxun_bot/pull/763)
|
||||
* 金币红包功能增加更多封面 [@pull/764](https://github.com/HibiKier/zhenxun_bot/pull/764)
|
||||
|
||||
### 2022/6/3
|
||||
|
||||
* 修复了webUI插件相关API问题
|
||||
* 插件仓库在已安装插件边上会提示\[已安装]
|
||||
* 修复ShopRegister kwargs某些字段无效
|
||||
* 调整了一下查看所有请求中的年龄绘制 [@pull/745](https://github.com/HibiKier/zhenxun_bot/pull/745)
|
||||
* 修复原神树脂提醒bug [@pull/756](https://github.com/HibiKier/zhenxun_bot/pull/756)
|
||||
|
||||
### 2022/5/31
|
||||
|
||||
* 修复开启/关闭全部功能时帮助图片未重绘 [@pull/721](https://github.com/HibiKier/zhenxun_bot/pull/721)
|
||||
* bot_friend_group将group_handle.修改为friend_handle. [@pull/711](https://github.com/HibiKier/zhenxun_bot/pull/711)
|
||||
* 修复发红包图片背景未透明化;修复原神树脂提醒参数错误 [@pull/712](https://github.com/HibiKier/zhenxun_bot/pull/712)
|
||||
* 修复抽卡插件:方舟更新UP池信息时,若公告的第一个池子过期会导致无法更新UP池信息 [@pull/707](https://github.com/HibiKier/zhenxun_bot/pull/707)
|
||||
* 商店插件判断是否有requirements.txt文件 [@pull/705](https://github.com/HibiKier/zhenxun_bot/pull/705)
|
||||
* 删除原神玩家查询api返回变更的多余键值
|
||||
* 优化了text2image方法
|
||||
|
||||
### 2022/5/29 \[v0.1.5.8]
|
||||
|
||||
* 修复错误的resource路径会删除IMAGE_PATH等重要文件夹
|
||||
* 提供了真寻适配仓库的插件 安装/卸载 操作
|
||||
* 暂时关闭了插件资源清空
|
||||
* 通过指令安装插件时会在插件目录下生成plugin_info.json记录当前插件信息
|
||||
|
||||
### 2022/5/28
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__: v0.1.5.6
|
||||
__version__: v0.1.5.9
|
||||
@@ -118,6 +118,8 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
|
||||
group_manager.unblock_plugin(f, group_id)
|
||||
else:
|
||||
group_manager.block_plugin(f, group_id)
|
||||
if group_help_file.exists():
|
||||
group_help_file.unlink()
|
||||
return f"已 {status} 全部功能!"
|
||||
if cmd in [task_data[x] for x in task_data.keys()]:
|
||||
type_ = "task"
|
||||
|
||||
@@ -40,7 +40,7 @@ def init_none_plugin_count_manager():
|
||||
plugins2block_manager.save()
|
||||
plugins_manager.delete(module)
|
||||
plugins_manager.save()
|
||||
resources_manager.remove_resource(module)
|
||||
# resources_manager.remove_resource(module)
|
||||
none_plugin_count_manager.delete(module)
|
||||
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
|
||||
except Exception as e:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from nonebot import on_command, on_regex
|
||||
|
||||
from .data_source import show_plugin_repo, install_plugin, uninstall_plugin
|
||||
from .data_source import show_plugin_repo, install_plugin, uninstall_plugin, download_json
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
|
||||
from nonebot.params import CommandArg
|
||||
@@ -15,7 +15,8 @@ usage:
|
||||
下载安装插件
|
||||
指令:
|
||||
查看插件仓库
|
||||
安装插件 [name/id]
|
||||
更新插件仓库
|
||||
安装插件 [name/id] (重新安装等同于更新)
|
||||
卸载插件 [name/id]
|
||||
""".strip()
|
||||
__plugin_des__ = "从真寻适配仓库中下载插件"
|
||||
@@ -25,6 +26,8 @@ __plugin_author__ = "HibiKier"
|
||||
|
||||
show_repo = on_regex("^查看插件仓库$", priority=1, block=True, permission=SUPERUSER)
|
||||
|
||||
update_repo = on_regex("^更新插件仓库$", priority=1, block=True, permission=SUPERUSER)
|
||||
|
||||
install_plugin_matcher = on_command("安装插件", priority=1, block=True, permission=SUPERUSER)
|
||||
|
||||
uninstall_plugin_matcher = on_command("卸载插件", priority=1, block=True, permission=SUPERUSER)
|
||||
@@ -44,6 +47,14 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
await install_plugin_matcher.send(msg)
|
||||
|
||||
|
||||
@update_repo.handle()
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
code = await download_json()
|
||||
if code == 200:
|
||||
await update_repo.finish("更新插件仓库信息成功!")
|
||||
await update_repo.send("更新插件仓库信息失败!")
|
||||
|
||||
|
||||
@show_repo.handle()
|
||||
async def _(bot: Bot, event: MessageEvent):
|
||||
msg = await show_plugin_repo()
|
||||
|
||||
@@ -3,6 +3,7 @@ import shutil
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from typing import Union, Tuple
|
||||
from utils.manager import plugins_manager
|
||||
|
||||
import ujson as json
|
||||
|
||||
@@ -71,6 +72,13 @@ async def install_plugin(name: str) -> str:
|
||||
os.system(
|
||||
f"poetry run pip install -r {(extensive_plugin_path / f'{name}' / 'pyproject.toml').absolute()}"
|
||||
)
|
||||
elif "requirements.txt" in os.listdir(extensive_plugin_path / f"{name}"):
|
||||
tmp = "检测到该插件含有额外依赖,当前安装无法保证依赖完全安装成功。"
|
||||
os.system(
|
||||
f"poetry run pip install -r {(extensive_plugin_path / f'{name}' / 'requirements.txt').absolute()}"
|
||||
)
|
||||
with open(extensive_plugin_path / f"{name}" / "plugin_info.json", "w") as f:
|
||||
json.dump(data[name], f, ensure_ascii=False, indent=4)
|
||||
logger.debug("移动插件文件夹完成...")
|
||||
logger.info(f"成功安装插件 {name} 成功!\n{tmp}")
|
||||
return f"成功安装插件 {name},请重启bot!"
|
||||
@@ -108,6 +116,7 @@ async def show_plugin_repo() -> Union[int, str]:
|
||||
if code != 200:
|
||||
return code
|
||||
plugin_info = json.load(open(plugin_json, "r", encoding="utf8"))
|
||||
load_plugin_list = plugins_manager.get_data().keys()
|
||||
image_list = []
|
||||
w, h = 0, 0
|
||||
line_height = 10
|
||||
@@ -122,8 +131,9 @@ async def show_plugin_repo() -> Union[int, str]:
|
||||
"github_url": plugin_info[key]["github_url"],
|
||||
}
|
||||
s = (
|
||||
f'id:{i+1}\n名称:{plugin_info[key]["plugin_name"]}\n'
|
||||
f'模块:{key}\n'
|
||||
f'id:{i+1}\n名称:{plugin_info[key]["plugin_name"]}'
|
||||
f' \t\t{"<f font_color=#1a7e30>[已安装]</f>" if key in load_plugin_list else ""}\n'
|
||||
f"模块:{key}\n"
|
||||
f'作者:{plugin_info[key]["author"]}\n'
|
||||
f'版本:{plugin_info[key]["version"]}\n'
|
||||
f'简介:{plugin_info[key]["introduction"]}\n'
|
||||
@@ -133,10 +143,10 @@ async def show_plugin_repo() -> Union[int, str]:
|
||||
w = w if w > img.w else img.w
|
||||
h += img.h + line_height
|
||||
image_list.append(img)
|
||||
A = BuildImage(w + 100, h + 100, color="#f9f6f2")
|
||||
cur_h = 50
|
||||
A = BuildImage(w + 50, h + 50, color="#f9f6f2")
|
||||
cur_h = 25
|
||||
for img in image_list:
|
||||
await A.apaste(img, (50, cur_h))
|
||||
await A.apaste(img, (25, cur_h))
|
||||
cur_h += img.h + line_height
|
||||
return A.pic2bs4()
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, ActionFailed
|
||||
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.image_utils import text2image
|
||||
from utils.message_builder import image
|
||||
from utils.utils import is_number
|
||||
|
||||
@@ -34,7 +35,11 @@ gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP)
|
||||
|
||||
@my_gold.handle()
|
||||
async def _(event: GroupMessageEvent):
|
||||
await my_gold.finish(await BagUser.get_user_total_gold(event.user_id, event.group_id))
|
||||
msg = await BagUser.get_user_total_gold(event.user_id, event.group_id)
|
||||
try:
|
||||
await my_gold.send(msg)
|
||||
except ActionFailed:
|
||||
await my_gold.send(image(b64=(await text2image(msg, color="#f9f6f2", padding=10)).pic2bs4()))
|
||||
|
||||
|
||||
@gold_rank.handle()
|
||||
|
||||
@@ -26,7 +26,7 @@ class GoodsUseFuncManager:
|
||||
判断商品使用方法是否被注册
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
return bool(self._data.get(goods_name))
|
||||
return bool(self ._data.get(goods_name))
|
||||
|
||||
def get_max_num_limit(self, goods_name: str) -> int:
|
||||
"""
|
||||
|
||||
@@ -119,18 +119,18 @@ async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandAr
|
||||
)
|
||||
flag = await requests_manager.approve(bot, id_, "group")
|
||||
else:
|
||||
await friend_handle.send("同意群聊请求失败,未找到此id的请求..")
|
||||
await group_handle.send("同意群聊请求失败,未找到此id的请求..")
|
||||
else:
|
||||
flag = await requests_manager.refused(bot, id_, "group")
|
||||
if flag == 1:
|
||||
await friend_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..")
|
||||
await group_handle.send(f"{cmd[:2]}群聊请求失败,该请求已失效..")
|
||||
requests_manager.delete_request(id_, "group")
|
||||
elif flag == 2:
|
||||
await friend_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..")
|
||||
await group_handle.send(f"{cmd[:2]}群聊请求失败,未找到此id的请求..")
|
||||
else:
|
||||
await friend_handle.send(f"{cmd[:2]}群聊请求成功!")
|
||||
await group_handle.send(f"{cmd[:2]}群聊请求成功!")
|
||||
else:
|
||||
await friend_handle.send("id必须为纯数字!")
|
||||
await group_handle.send("id必须为纯数字!")
|
||||
|
||||
|
||||
@cls_request.handle()
|
||||
@@ -150,4 +150,4 @@ async def _():
|
||||
@clear_request.handle()
|
||||
async def _():
|
||||
requests_manager.clear()
|
||||
await cls_request.send("已清空所有好友/群聊请求..")
|
||||
await clear_request.send("已清空所有好友/群聊请求..")
|
||||
@@ -80,8 +80,8 @@ async def _(
|
||||
except TimeoutError:
|
||||
await bt.finish(f"搜索 {keyword} 超时...")
|
||||
except Exception as e:
|
||||
await bt.finish(f"bt 其他未知错误..")
|
||||
logger.error(f"bt 错误 {type(e)}:{e}")
|
||||
await bt.finish(f"bt 其他未知错误..")
|
||||
if not send_flag:
|
||||
await bt.send(f"{keyword} 未搜索到...")
|
||||
logger.info(f"USER {event.user_id} BT搜索 {keyword} 第 {page} 页")
|
||||
|
||||
@@ -27,7 +27,7 @@ __plugin_author__ = "HibiKier"
|
||||
__plugin_configs__ = {
|
||||
"UPDATE_REMIND": {
|
||||
"value": True,
|
||||
"help": "真寻是否自动检查更新",
|
||||
"help": "真寻是否检测版本状态",
|
||||
"default": True,
|
||||
},
|
||||
"AUTO_UPDATE_ZHENXUN": {
|
||||
|
||||
@@ -189,6 +189,9 @@ def _file_handle(latest_version: str) -> str:
|
||||
local_update_info_file.unlink()
|
||||
with open(_version_file, "w", encoding="utf8") as f:
|
||||
f.write(f"__version__: {latest_version}")
|
||||
os.system(
|
||||
f"poetry run pip install -r {(Path() / 'pyproject.toml').absolute()}"
|
||||
)
|
||||
return error
|
||||
|
||||
|
||||
|
||||
@@ -288,7 +288,10 @@ class PrtsHandle(BaseHandle[Operator]):
|
||||
up_chars.append(
|
||||
UpChar(name=name, star=star, limited=False, zoom=zoom)
|
||||
)
|
||||
break # 这里break会导致个问题:如果一个公告里有两个池子,会漏掉下面的池子,比如 5.19 的定向寻访。但目前我也没啥好想法解决
|
||||
if start_time <= datetime.now() <= end_time: # 跳过过时的卡池
|
||||
break # 这里break会导致个问题:如果一个公告里有两个池子,会漏掉下面的池子,比如 5.19 的定向寻访。但目前我也没啥好想法解决
|
||||
chars: List[str] = [] # 查找下一个卡池之前清空 chars
|
||||
up_chars = [] # 查找下一个卡池之前清空 up_chars
|
||||
if title and start_time and end_time:
|
||||
if start_time <= datetime.now() <= end_time:
|
||||
self.UP_EVENT = UpEvent(
|
||||
|
||||
@@ -182,7 +182,7 @@ def parsed_data(
|
||||
role_data = {
|
||||
"active_day_number": data["stats"]["active_day_number"], # 活跃天数
|
||||
"achievement_number": data["stats"]["achievement_number"], # 达成成就数量
|
||||
"win_rate": data["stats"]["win_rate"],
|
||||
# "win_rate": data["stats"]["win_rate"],
|
||||
"anemoculus_number": data["stats"]["anemoculus_number"], # 风神瞳已收集
|
||||
"geoculus_number": data["stats"]["geoculus_number"], # 岩神瞳已收集
|
||||
"avatar_number": data["stats"]["avatar_number"], # 获得角色数量
|
||||
|
||||
@@ -86,30 +86,28 @@ async def _():
|
||||
if await Genshin.get_user_resin_recovery_time(u.uid) > datetime.now(
|
||||
pytz.timezone("Asia/Shanghai")
|
||||
):
|
||||
date = await Genshin.get_user_resin_recovery_time(u.uid)
|
||||
scheduler.add_job(
|
||||
_remind,
|
||||
"date",
|
||||
run_date=date.replace(microsecond=0),
|
||||
id=f"genshin_resin_remind_{u.uid}_{u.user_qq}",
|
||||
args=[u.user_qq, u.uid],
|
||||
)
|
||||
# date = await Genshin.get_user_resin_recovery_time(u.uid) # 不能要,因为可能在这期间用户使用了树脂
|
||||
add_job(u.user_qq, u.uid)
|
||||
# scheduler.add_job(
|
||||
# _remind,
|
||||
# "date",
|
||||
# run_date=date.replace(microsecond=0),
|
||||
# id=f"genshin_resin_remind_{u.uid}_{u.user_qq}",
|
||||
# args=[u.user_qq, u.uid],
|
||||
# )
|
||||
logger.info(
|
||||
f"genshin_resin_remind add_job:USER:{u.user_qq} UID:{u.uid} "
|
||||
f"{date} 原神树脂提醒"
|
||||
f"genshin_resin_remind add_job:USER:{u.user_qq} UID:{u.uid}启动原神树脂提醒 "
|
||||
)
|
||||
else:
|
||||
await Genshin.clear_resin_remind_time(u.uid)
|
||||
add_job(u.user_qq, u.uid)
|
||||
logger.info(
|
||||
f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid} "
|
||||
f"{date} 原神树脂提醒"
|
||||
f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid}启动原神树脂提醒 "
|
||||
)
|
||||
else:
|
||||
add_job(u.user_qq, u.uid)
|
||||
logger.info(
|
||||
f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid} "
|
||||
f"{date} 原神树脂提醒"
|
||||
f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid}启动原神树脂提醒 "
|
||||
)
|
||||
|
||||
|
||||
@@ -144,16 +142,18 @@ async def _remind(user_id: int, uid: str):
|
||||
now = datetime.now(pytz.timezone("Asia/Shanghai"))
|
||||
next_time = None
|
||||
if code == 200:
|
||||
current_resin = data["current_resin"] # 当前树脂
|
||||
max_resin = data["max_resin"] # 最大树脂
|
||||
current_resin = int(data["current_resin"]) # 当前树脂
|
||||
max_resin = int(data["max_resin"]) # 最大树脂
|
||||
msg = f"你的已经存了 {current_resin} 个树脂了!不要忘记刷掉!"
|
||||
# resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间
|
||||
if current_resin < max_resin:
|
||||
user_manager.remove(uid)
|
||||
user_manager.remove_overflow(uid)
|
||||
if max_resin - 40 < current_resin <= max_resin - 20:
|
||||
if current_resin <= max_resin - 40:
|
||||
next_time = now + timedelta(minutes=(max_resin - 40 - current_resin + 1) * 8, seconds=10)
|
||||
elif max_resin - 40 < current_resin <= max_resin - 20:
|
||||
next_time = now + timedelta(minutes=(max_resin - 20 - current_resin + 1) * 8, seconds=10)
|
||||
elif current_resin < max_resin:
|
||||
elif max_resin - 20 < current_resin < max_resin:
|
||||
next_time = now + timedelta(minutes=(max_resin - current_resin) * 8, seconds=10)
|
||||
elif current_resin == max_resin:
|
||||
custom_overflow_resin = Config.get_config("resin_remind", "CUSTOM_RESIN_OVERFLOW_REMIND")
|
||||
@@ -164,6 +164,7 @@ async def _remind(user_id: int, uid: str):
|
||||
msg = f"你的树脂都溢出 {custom_overflow_resin} 个了!浪费可耻!"
|
||||
else:
|
||||
next_time = now + timedelta(minutes=40 * 8 + random.randint(5, 50))
|
||||
|
||||
if not user_manager.exists(uid) and current_resin >= max_resin - 40:
|
||||
if current_resin == max_resin:
|
||||
user_manager.append(uid)
|
||||
@@ -187,6 +188,7 @@ async def _remind(user_id: int, uid: str):
|
||||
)
|
||||
except ActionFailed as e:
|
||||
logger.error(f"树脂提醒推送发生错误 {type(e)}:{e}")
|
||||
|
||||
if not next_time:
|
||||
if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"):
|
||||
await Genshin.set_resin_remind(int(uid), False)
|
||||
@@ -197,10 +199,13 @@ async def _remind(user_id: int, uid: str):
|
||||
user_manager.remove_error_count(uid)
|
||||
await Genshin.set_user_resin_recovery_time(int(uid), next_time)
|
||||
scheduler.add_job(
|
||||
_remind,
|
||||
_remind,
|
||||
"date",
|
||||
run_date=next_time,
|
||||
id=f"genshin_resin_remind_{uid}_{user_id}",
|
||||
args=[user_id, uid],
|
||||
)
|
||||
logger.info(
|
||||
f"genshin_resin_remind add_job:USER:{user_id} UID:{uid} "
|
||||
f"{next_time} 原神树脂提醒"
|
||||
)
|
||||
|
||||
@@ -124,7 +124,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
redbag_data[event.group_id]["amount"]
|
||||
- redbag_data[event.group_id]["open_amount"]
|
||||
)
|
||||
await return_gold(event.user_id, event.group_id, amount)
|
||||
await return_gold(redbag_data[event.group_id]["user_id"], event.group_id, amount)
|
||||
await gold_redbag.send(
|
||||
f'{redbag_data[event.group_id]["nickname"]}的红包过时未开完,退还{amount}金币...'
|
||||
)
|
||||
|
||||
@@ -61,7 +61,8 @@ async def generate_open_redbag_pic(user_id: int, send_user_nickname: str, amount
|
||||
async def _generate_open_redbag_pic(user_id: int, send_user_nickname: str, amount: int, text: str):
|
||||
send_user_nickname += '的红包'
|
||||
amount = str(amount)
|
||||
head = BuildImage(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_12.png')
|
||||
random_redbag = random.choice(os.listdir(f"{IMAGE_PATH}/prts/redbag_1"))
|
||||
head = BuildImage(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_1/{random_redbag}')
|
||||
size = BuildImage(0, 0, font_size=50).getsize(send_user_nickname)
|
||||
# QQ头像
|
||||
ava_bk = BuildImage(100 + size[0], 66, is_alpha=True, font_size=50)
|
||||
@@ -70,13 +71,13 @@ async def _generate_open_redbag_pic(user_id: int, send_user_nickname: str, amoun
|
||||
ava_bk.text((100, 7), send_user_nickname)
|
||||
# ava_bk.show()
|
||||
ava_bk_w, ava_bk_h = ava_bk.size
|
||||
head.paste(ava_bk, (int((1000 - ava_bk_w) / 2), 300))
|
||||
head.paste(ava_bk, (int((1000 - ava_bk_w) / 2), 300), alpha=True)
|
||||
# 金额
|
||||
size = BuildImage(0, 0, font_size=150).getsize(amount)
|
||||
price = BuildImage(size[0], size[1], is_alpha=True, font_size=150)
|
||||
price.text((0, 0), amount, fill=(209, 171, 108))
|
||||
# 金币中文
|
||||
head.paste(price, (int((1000 - size[0]) / 2) - 50, 460))
|
||||
head.paste(price, (int((1000 - size[0]) / 2) - 50, 460), alpha=True)
|
||||
head.text((int((1000 - size[0]) / 2 + size[0]) - 50, 500 + size[1] - 70), '金币', fill=(209, 171, 108))
|
||||
# 剩余数量和金额
|
||||
head.text((350, 900), text, (198, 198, 198))
|
||||
|
||||
@@ -36,7 +36,7 @@ __plugin_settings__ = {
|
||||
"limit_superuser": False,
|
||||
"cmd": ["发送图片"] + Config.get_config("image_management", "IMAGE_DIR_LIST"),
|
||||
}
|
||||
__plugin_resources__ = {"pa": IMAGE_PATH}
|
||||
__plugin_resources__ = {"pa": IMAGE_PATH / "pa"}
|
||||
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
|
||||
@@ -64,7 +64,7 @@ async def _poke_event(event: PokeNotifyEvent):
|
||||
rand = random.random()
|
||||
path = random.choice(["luoli", "meitu"])
|
||||
if rand <= 0.3 and len(os.listdir(IMAGE_PATH / "image_management" / path)) > 0:
|
||||
index = random.randint(0, len(os.listdir(IMAGE_PATH / "image_management" / path)))
|
||||
index = random.randint(0, len(os.listdir(IMAGE_PATH / "image_management" / path)) - 1)
|
||||
result = f"id:{index}" + image(f"{index}.jpg", "image_management/" + path)
|
||||
await poke_.send(result)
|
||||
logger.info(f"USER {event.user_id} 戳了戳我 回复: {result} {result}")
|
||||
|
||||
@@ -58,4 +58,4 @@ async def _(group: GroupResult, user: User = Depends(token_to_user)) -> Result:
|
||||
group_manager.turn_on_group_bot_status(group_id)
|
||||
else:
|
||||
group_manager.shutdown_group_bot_status(group_id)
|
||||
return Result(code=200)
|
||||
return Result(code=200, data="修改成功!")
|
||||
|
||||
@@ -108,7 +108,7 @@ def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result:
|
||||
if str(c.value).lower() in ["true", "false"] and (
|
||||
c.default_value is None or isinstance(c.default_value, bool)
|
||||
):
|
||||
c.value = True if str(c.value).lower() == "true" else False
|
||||
c.value = str(c.value).lower() == "true"
|
||||
elif isinstance(
|
||||
Config.get_config(plugin.model, c.key, c.value), int
|
||||
) or isinstance(c.default_value, int):
|
||||
@@ -121,14 +121,22 @@ def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result:
|
||||
isinstance(Config.get_config(plugin.model, c.key, c.value), list)
|
||||
or isinstance(c.default_value, list)
|
||||
):
|
||||
default_value = Config.get_config(plugin.model, c.key, c.value)
|
||||
c.value = c.value.split(",")
|
||||
if default_value and isinstance(default_value[0], int):
|
||||
c.value = [int(x) for x in c.value]
|
||||
elif default_value and isinstance(default_value[0], float):
|
||||
c.value = [float(x) for x in c.value]
|
||||
elif default_value and isinstance(default_value[0], bool):
|
||||
temp = []
|
||||
for x in c.value:
|
||||
temp.append(x.lower() == "true")
|
||||
c.value = temp
|
||||
Config.set_config(plugin.model, c.key, c.value)
|
||||
Config.save(None, True)
|
||||
else:
|
||||
if plugin.plugin_settings:
|
||||
for key, value in plugin.plugin_settings:
|
||||
if plugin.plugin_settings.cmd:
|
||||
plugin.plugin_settings.cmd = plugin.plugin_settings.cmd.split(',')
|
||||
plugins2settings_manager.set_module_data(plugin.model, key, value)
|
||||
if plugin.plugin_manager:
|
||||
for key, value in plugin.plugin_manager:
|
||||
@@ -141,4 +149,4 @@ def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result:
|
||||
code=500,
|
||||
data=f"WEB_UI POST /webui/plugins model:{plugin.model} 发生错误 {type(e)}:{e}",
|
||||
)
|
||||
return Result(code=200)
|
||||
return Result(code=200, data="修改成功!")
|
||||
|
||||
@@ -34,7 +34,7 @@ async def _(parma: RequestParma, user: User = Depends(token_to_user)) -> Result:
|
||||
操作请求
|
||||
:param parma: 参数
|
||||
"""
|
||||
result = "ok"
|
||||
result = "操作成功!"
|
||||
flag = 3
|
||||
if bot := get_bot():
|
||||
if parma.handle == "approve":
|
||||
|
||||
@@ -29,7 +29,7 @@ disk_data = {"data": []}
|
||||
|
||||
|
||||
@app.get("/webui/system")
|
||||
async def _(user: User = Depends(token_to_user)) -> Result:
|
||||
async def _() -> Result:
|
||||
return await get_system_data()
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ async def _(user: User = Depends(token_to_user)) -> Result:
|
||||
)
|
||||
|
||||
|
||||
async def get_system_data():
|
||||
async def get_system_data(user: User = Depends(token_to_user)):
|
||||
"""
|
||||
说明:
|
||||
获取系统信息,资源文件大小,网络状态等
|
||||
@@ -92,7 +92,7 @@ async def get_system_data():
|
||||
logger.warning(f"访问Google失败... {type(e)}: {e}")
|
||||
google = 404
|
||||
network = SystemNetwork(baidu=baidu, google=google)
|
||||
disk = await asyncio.get_event_loop().run_in_executor(None, _get_system_disk)
|
||||
disk = await asyncio.get_event_loop().run_in_executor(None, _get_system_disk, None)
|
||||
status = await asyncio.get_event_loop().run_in_executor(None, _get_system_status)
|
||||
return Result(
|
||||
code=200,
|
||||
@@ -105,7 +105,7 @@ async def get_system_data():
|
||||
)
|
||||
|
||||
|
||||
def _get_system_status() -> SystemStatus:
|
||||
def _get_system_status(user: User = Depends(token_to_user)) -> SystemStatus:
|
||||
"""
|
||||
说明:
|
||||
获取系统信息等
|
||||
@@ -123,7 +123,7 @@ def _get_system_status() -> SystemStatus:
|
||||
|
||||
|
||||
def _get_system_disk(
|
||||
type_: Optional[str],
|
||||
type_: Optional[str], user: User = Depends(token_to_user)
|
||||
) -> Union[SystemFolderSize, Dict[str, Union[float, datetime]]]:
|
||||
"""
|
||||
说明:
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
from configs.path_config import DATA_PATH
|
||||
from typing import Optional
|
||||
from starlette import status
|
||||
from fastapi import Depends, HTTPException
|
||||
@@ -8,6 +10,8 @@ from configs.config import Config
|
||||
from jose import JWTError, jwt
|
||||
import nonebot
|
||||
|
||||
from ..config import Result
|
||||
|
||||
app = nonebot.get_app()
|
||||
|
||||
|
||||
@@ -18,6 +22,13 @@ ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="webui/login")
|
||||
|
||||
|
||||
token_file = DATA_PATH / "web_ui" / "token.json"
|
||||
token_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
token_data = {"token": []}
|
||||
if token_file.exists():
|
||||
token_data = json.load(open(token_file, 'r', encoding='utf8'))
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
@@ -62,6 +73,9 @@ async def login_get_token(form_data: OAuth2PasswordRequestForm = Depends()):
|
||||
if not user or user.password != form_data.password:
|
||||
raise form_exception
|
||||
access_token = create_token(user=user, expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
|
||||
token_data["token"].append(access_token)
|
||||
if len(token_data["token"]) > 3:
|
||||
token_data["token"] = token_data["token"][1:]
|
||||
return {"access_token": access_token, "token_type": "bearer"}
|
||||
|
||||
|
||||
@@ -72,16 +86,18 @@ credentials_exception = HTTPException(
|
||||
)
|
||||
|
||||
|
||||
@app.post("/webui/auth")
|
||||
def token_to_user(token: str = Depends(oauth2_scheme)):
|
||||
try:
|
||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||
username, expire = payload.get("sub"), payload.get("exp")
|
||||
user = get_user(username)
|
||||
if user is None:
|
||||
raise JWTError
|
||||
except JWTError:
|
||||
raise credentials_exception
|
||||
return user
|
||||
if token not in token_data["token"]:
|
||||
try:
|
||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||
username, expire = payload.get("sub"), payload.get("exp")
|
||||
user = get_user(username)
|
||||
if user is None:
|
||||
raise JWTError
|
||||
except JWTError:
|
||||
return Result(code=401)
|
||||
return Result(code=200, data="ok")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -7,7 +7,7 @@ import nonebot
|
||||
|
||||
app = nonebot.get_app()
|
||||
|
||||
origins = ["http://localhost"]
|
||||
origins = ["*"]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
|
||||
|
After Width: | Height: | Size: 600 KiB |
|
After Width: | Height: | Size: 614 KiB |
|
After Width: | Height: | Size: 534 KiB |
|
After Width: | Height: | Size: 466 KiB |
|
After Width: | Height: | Size: 479 KiB |
|
After Width: | Height: | Size: 468 KiB |
|
After Width: | Height: | Size: 501 KiB |
|
After Width: | Height: | Size: 518 KiB |
|
After Width: | Height: | Size: 709 KiB |
|
After Width: | Height: | Size: 747 KiB |
|
After Width: | Height: | Size: 653 KiB |
|
After Width: | Height: | Size: 839 KiB |
|
After Width: | Height: | Size: 543 KiB |
|
After Width: | Height: | Size: 587 KiB |
|
After Width: | Height: | Size: 738 KiB |
|
After Width: | Height: | Size: 602 KiB |
|
After Width: | Height: | Size: 599 KiB |
|
After Width: | Height: | Size: 814 KiB |
|
After Width: | Height: | Size: 831 KiB |
|
After Width: | Height: | Size: 600 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
|
After Width: | Height: | Size: 392 KiB |
|
After Width: | Height: | Size: 395 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 557 KiB |
|
After Width: | Height: | Size: 412 KiB |
|
After Width: | Height: | Size: 467 KiB |
|
After Width: | Height: | Size: 465 KiB |
|
After Width: | Height: | Size: 482 KiB |
|
After Width: | Height: | Size: 406 KiB |
|
After Width: | Height: | Size: 517 KiB |
|
After Width: | Height: | Size: 337 KiB |
|
After Width: | Height: | Size: 327 KiB |
|
After Width: | Height: | Size: 567 KiB |
|
After Width: | Height: | Size: 426 KiB |
|
After Width: | Height: | Size: 543 KiB |
|
After Width: | Height: | Size: 381 KiB |
|
After Width: | Height: | Size: 429 KiB |
|
After Width: | Height: | Size: 496 KiB |
|
After Width: | Height: | Size: 361 KiB |
|
After Width: | Height: | Size: 532 KiB |
|
After Width: | Height: | Size: 404 KiB |
@@ -31,6 +31,8 @@ class ShopRegister(dict):
|
||||
for key, value in kwargs.items():
|
||||
if key.startswith(f"{n}_"):
|
||||
_temp_kwargs[key.split("_", maxsplit=1)[-1]] = value
|
||||
else:
|
||||
_temp_kwargs[key] = value
|
||||
self._data[n] = {
|
||||
"price": p,
|
||||
"des": d,
|
||||
|
||||
@@ -178,7 +178,7 @@ class BuildImage:
|
||||
self.paste_image_height = int(paste_image_height)
|
||||
self.current_w = 0
|
||||
self.current_h = 0
|
||||
self.font = ImageFont.truetype(str(FONT_PATH / font), int(font_size))
|
||||
self.font = ImageFont.truetype(str(FONT_PATH / font), font_size)
|
||||
if not plain_text and not color:
|
||||
color = (255, 255, 255)
|
||||
self.background = background
|
||||
@@ -1492,23 +1492,25 @@ async def text2image(
|
||||
width = 0
|
||||
height = 0
|
||||
_tmp = BuildImage(0, 0, font=font, font_size=font_size)
|
||||
_, h = _tmp.getsize("正")
|
||||
line_height = int(font_size / 3)
|
||||
image_list = []
|
||||
for x in text.split("\n"):
|
||||
if x:
|
||||
w, _ = _tmp.getsize(x)
|
||||
_, h = _tmp.getsize("正")
|
||||
height += h + _add_height
|
||||
width = width if width > w else w
|
||||
w, _ = _tmp.getsize(x.strip() or "正")
|
||||
height += h + line_height
|
||||
width = width if width > w else w
|
||||
image_list.append(BuildImage(w, h, font=font, font_size=font_size, plain_text=x.strip()))
|
||||
width += pw
|
||||
height += ph
|
||||
A = BuildImage(
|
||||
width + left_padding,
|
||||
height + top_padding + 2,
|
||||
font_size=font_size,
|
||||
color=color,
|
||||
font=font,
|
||||
)
|
||||
await A.atext((left_padding, top_padding), text, font_color)
|
||||
# A.show()
|
||||
cur_h = ph
|
||||
for img in image_list:
|
||||
await A.apaste(img, (pw, cur_h), True)
|
||||
cur_h += img.h + line_height
|
||||
return A
|
||||
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ class RequestManager(StaticData):
|
||||
)
|
||||
ava.circle()
|
||||
age_bk = BuildImage(
|
||||
len(str(age)) * 10 - 5,
|
||||
len(str(age)) * 6 + 6,
|
||||
15,
|
||||
color="#04CAF7" if sex == "male" else "#F983C1",
|
||||
)
|
||||
|
||||