diff --git a/README.md b/README.md index 4574e51b..d53c10d0 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,11 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能 ## 更新 +### 2023/4/1 + +* 修复开箱偶尔出现`未抽取到任何皮肤` +* 修改优化开箱显示图片 + ### 2023/3/28 * 补全注释`SCRIPT`中的sql语句 diff --git a/plugins/open_cases/__init__.py b/plugins/open_cases/__init__.py index 941916a5..f1226f97 100755 --- a/plugins/open_cases/__init__.py +++ b/plugins/open_cases/__init__.py @@ -235,7 +235,7 @@ async def _(event: MessageEvent, arg: Message = CommandArg(), cmd: str = OneComm await update_case.finish(f"未登录, 已停止更新...") rand = random.randint(300, 500) result = f"更新全部{type_}完成" - if i < len(case_list): + if i < len(case_list) - 1: next_case = case_list[i + 1] result = f"将在 {rand} 秒后更新下一{type_}: {next_case}" await update_case.send(f"{info}, {result}") @@ -248,7 +248,9 @@ async def _(event: MessageEvent, arg: Message = CommandArg(), cmd: str = OneComm else: await update_case.send(f"开始{cmd}: {msg}, 请稍等") try: - await update_case.send(await update_skin_data(msg, is_update_case_name), at_sender=True) + await update_case.send( + await update_skin_data(msg, is_update_case_name), at_sender=True + ) except Exception as e: logger.error(f"{cmd}: {msg}", e=e) await update_case.send(f"成功{cmd}: {msg} 发生错误: {type(e)}: {e}") diff --git a/plugins/open_cases/build_image.py b/plugins/open_cases/build_image.py index 4413b6ad..972eb45f 100644 --- a/plugins/open_cases/build_image.py +++ b/plugins/open_cases/build_image.py @@ -14,6 +14,56 @@ BASE_PATH = IMAGE_PATH / "csgo_cases" ICON_PATH = IMAGE_PATH / "_icon" +async def draw_card(skin: BuffSkin, rand: str) -> BuildImage: + """构造抽取图片 + + Args: + skin (BuffSkin): BuffSkin + rand (str): 磨损 + + Returns: + BuildImage: BuildImage + """ + name = skin.name + "-" + skin.skin_name + "-" + skin.abrasion + file_path = BASE_PATH / cn2py(skin.case_name.split(",")[0]) / f"{cn2py(name)}.jpg" + if not file_path.exists(): + logger.warning(f"皮肤图片: {name} 不存在", "开箱") + skin_bk = BuildImage( + 460, 200, color=(25, 25, 25, 100), font_size=25, font="CJGaoDeGuo.otf" + ) + if file_path.exists(): + skin_image = BuildImage(205, 153, background=file_path) + await skin_bk.apaste(skin_image, (10, 30), alpha=True) + await skin_bk.aline((220, 10, 220, 180)) + await skin_bk.atext((10, 10), skin.name, (255, 255, 255)) + name_icon = BuildImage(20, 20, background=ICON_PATH / "name_white.png") + await skin_bk.apaste(name_icon, (240, 13), True) + await skin_bk.atext((265, 15), f"名称:", (255, 255, 255), font_size=20) + await skin_bk.atext( + (300, 9), + f"{skin.skin_name + ('(St)' if skin.is_stattrak else '')}", + (255, 255, 255), + ) + tone_icon = BuildImage(20, 20, background=ICON_PATH / "tone_white.png") + await skin_bk.apaste(tone_icon, (240, 45), True) + await skin_bk.atext((265, 45), "品质:", (255, 255, 255), font_size=20) + await skin_bk.atext((300, 40), COLOR2NAME[skin.color][:2], COLOR2COLOR[skin.color]) + type_icon = BuildImage(20, 20, background=ICON_PATH / "type_white.png") + await skin_bk.apaste(type_icon, (240, 73), True) + await skin_bk.atext((265, 75), "类型:", (255, 255, 255), font_size=20) + await skin_bk.atext((300, 70), skin.weapon_type, (255, 255, 255)) + price_icon = BuildImage(20, 20, background=ICON_PATH / "price_white.png") + await skin_bk.apaste(price_icon, (240, 103), True) + await skin_bk.atext((265, 105), "价格:", (255, 255, 255), font_size=20) + await skin_bk.atext((300, 102), str(skin.sell_min_price), (0, 255, 98)) + abrasion_icon = BuildImage(20, 20, background=ICON_PATH / "abrasion_white.png") + await skin_bk.apaste(abrasion_icon, (240, 133), True) + await skin_bk.atext((265, 135), "磨损:", (255, 255, 255), font_size=20) + await skin_bk.atext((300, 130), skin.abrasion, (255, 255, 255)) + await skin_bk.atext((228, 165), f"({rand})", (255, 255, 255)) + return skin_bk + + async def generate_skin(skin: BuffSkin, update_count: int) -> Optional[BuildImage]: """构造皮肤图片 @@ -27,13 +77,13 @@ async def generate_skin(skin: BuffSkin, update_count: int) -> Optional[BuildImag file_path = BASE_PATH / cn2py(skin.case_name.split(",")[0]) / f"{cn2py(name)}.jpg" if not file_path.exists(): logger.warning(f"皮肤图片: {name} 不存在", "查看武器箱") - return None if skin.color == "CASE": - skin_img = BuildImage(200, 200, background=file_path) case_bk = BuildImage( 700, 200, color=(25, 25, 25, 100), font_size=25, font="CJGaoDeGuo.otf" ) - await case_bk.apaste(skin_img, (10, 10), True) + if file_path.exists(): + skin_img = BuildImage(200, 200, background=file_path) + await case_bk.apaste(skin_img, (10, 10), True) await case_bk.aline((250, 10, 250, 190)) await case_bk.aline((280, 160, 660, 160)) name_icon = BuildImage(30, 30, background=ICON_PATH / "box_white.png") @@ -86,11 +136,12 @@ async def generate_skin(skin: BuffSkin, update_count: int) -> Optional[BuildImag skin_bk = BuildImage( 235, 250, color=(25, 25, 25, 100), font_size=25, font="CJGaoDeGuo.otf" ) - skin_image = BuildImage(205, 153, background=file_path) + if file_path.exists(): + skin_image = BuildImage(205, 153, background=file_path) + await skin_bk.apaste(skin_image, (10, 30), alpha=True) update_count_icon = BuildImage( 35, 35, background=ICON_PATH / "reload_white.png" ) - await skin_bk.apaste(skin_image, (10, 30), alpha=True) await skin_bk.aline((10, 180, 220, 180)) await skin_bk.atext((10, 10), skin.name, (255, 255, 255)) await skin_bk.apaste(update_count_icon, (140, 10), True) diff --git a/plugins/open_cases/models/buff_skin.py b/plugins/open_cases/models/buff_skin.py index 93dd0494..279f082e 100644 --- a/plugins/open_cases/models/buff_skin.py +++ b/plugins/open_cases/models/buff_skin.py @@ -72,7 +72,7 @@ class BuffSkin(Model): ) -> List["BuffSkin"]: # type: ignore query = cls if case_name: - query = query.filter(case_name=case_name) + query = query.filter(case_name__contains=case_name) query = query.filter(abrasion=abrasion, is_stattrak=is_stattrak, color=color) skin_list = await query.annotate(rand=Random()).limit(num) # type:ignore num_ = num diff --git a/plugins/open_cases/open_cases_c.py b/plugins/open_cases/open_cases_c.py index f0e56354..4ccfbb26 100755 --- a/plugins/open_cases/open_cases_c.py +++ b/plugins/open_cases/open_cases_c.py @@ -14,6 +14,7 @@ from utils.image_utils import BuildImage from utils.message_builder import image from utils.utils import cn2py +from .build_image import draw_card from .config import * from .models.open_cases_log import OpenCasesLog from .models.open_cases_user import OpenCasesUser @@ -147,14 +148,11 @@ async def open_case(user_qq: int, group_id: int, case_name: str) -> Union[str, M ) logger.debug(f"添加 1 条开箱日志", "开箱", user_qq, group_id) over_count = max_count - user.today_open_total + img = await draw_card(skin, rand) return ( f"开启{case_name}武器箱.\n剩余开箱次数:{over_count}.\n" - + image(img_path) - + "\n" - + f"皮肤:[{COLOR2NAME[skin.color]}]{skin.name}{'(StatTrak™)' if skin.is_stattrak else ''} | {skin.skin_name} ({skin.abrasion})\n" - f"磨损:{rand}\n" - f"价格:{price_result}\n箱子单价:{case_price}\n花费:{17 + case_price:.2f}\n" - f":{ridicule_result}" + + image(img) + + f"\n箱子单价:{case_price}\n花费:{17 + case_price:.2f}\n:{ridicule_result}" ) @@ -191,12 +189,7 @@ async def open_multiple_case( f"今天开箱次数不足{num}次噢,请单抽试试看(也许单抽运气更好?)" f"\n剩余开箱次数:{max_count - user.today_open_total}" ) - if num < 5: - h = 270 - elif num % 5 == 0: - h = 270 * int(num / 5) - else: - h = 270 * int(num / 5) + 270 + logger.debug(f"尝试开启武器箱: {case_name}", "开箱", user_qq, group_id) case = cn2py(case_name) skin_count = {} img_list = [] @@ -212,32 +205,19 @@ async def open_multiple_case( case_price = 0 if case_skin := await BuffSkin.get_or_none(case_name=case_name, color="CASE"): case_price = case_skin.sell_min_price - cnt = 0 + img_w, img_h = 0, 0 for skin, rand in skin_list: + img = await draw_card(skin, str(rand)[:11]) + img_w, img_h = img.size total_price += skin.sell_min_price - rand = str(rand)[:11] - add_count(user, skin, case_price) color_name = COLOR2CN[skin.color] - if skin.is_stattrak: - color_name += "(暗金)" if not skin_count.get(color_name): skin_count[color_name] = 0 skin_count[color_name] += 1 - name = skin.name + "-" + skin.skin_name + "-" + skin.abrasion - img_path = IMAGE_PATH / "csgo_cases" / case / f"{cn2py(name)}.jpg" - wImg = BuildImage(200, 270, 200, 200) - img = BuildImage(200, 200, background=img_path) - await wImg.apaste(img, (0, 0), True) - await wImg.atext( - (5, 200), - f"{skin.name}{'(StatTrak™)' if skin.is_stattrak else ''} | {skin.skin_name} ({skin.abrasion})", - ) - cnt += 1 - await wImg.atext((5, 220), f"磨损:{rand}") - await wImg.atext((5, 240), f"价格:{skin.sell_min_price}") - img_list.append(wImg) + add_count(user, skin, case_price) + img_list.append(img) logger.info( - f"开启{case_name}武器箱获得 {skin.name}{'(StatTrak™)' if skin.is_stattrak else ''} | {skin.skin_name} ({skin.abrasion}) 磨损: [{rand}] 价格: {skin.sell_min_price}", + f"开启{case_name}武器箱获得 {skin.name}{'(StatTrak™)' if skin.is_stattrak else ''} | {skin.skin_name} ({skin.abrasion}) 磨损: [{rand:.11f}] 价格: {skin.sell_min_price}", "开箱", user_qq, group_id, @@ -261,16 +241,26 @@ async def open_multiple_case( if log_list: await OpenCasesLog.bulk_create(log_list, 10) logger.debug(f"添加 {len(log_list)} 条开箱日志", "开箱", user_qq, group_id) - markImg = BuildImage(1000, h, 200, 270) + img_w += 10 + img_h += 10 + w = img_w * 5 + if num < 5: + h = img_h - 10 + w = img_w * num + elif not num % 5: + h = img_h * int(num / 5) + else: + h = img_h * int(num / 5) + img_h + markImg = BuildImage(w, h, img_w - 10, img_h - 10, 10) for img in img_list: - markImg.paste(img) + markImg.paste(img, alpha=True) over_count = max_count - user.today_open_total result = "" for color_name in skin_count: result += f"[{color_name}:{skin_count[color_name]}] " return ( f"开启{case_name}武器箱\n剩余开箱次数:{over_count}\n" - + image(markImg.pic2bs4()) + + image(markImg) + "\n" + result[:-1] + f"\n箱子单价:{case_price}\n总获取金额:{total_price:.2f}\n总花费:{(17 + case_price) * num:.2f}" diff --git a/plugins/open_cases/utils.py b/plugins/open_cases/utils.py index 6c46456b..c91607f3 100755 --- a/plugins/open_cases/utils.py +++ b/plugins/open_cases/utils.py @@ -45,9 +45,19 @@ class CaseManager: @classmethod async def reload(cls): - cls.CURRENT_CASES = ( - await BuffSkin.filter(case_name__not="未知武器箱").annotate().distinct().values_list("case_name", flat=True) # type: ignore + cls.CURRENT_CASES = [] + case_list = await BuffSkin.filter(color="CASE").values_list( + "case_name", flat=True ) + for case_name in ( + await BuffSkin.filter(case_name__not="未知武器箱") + .annotate() + .distinct() + .values_list("case_name", flat=True) + ): + for name in case_name.split(","): # type: ignore + if name not in cls.CURRENT_CASES and name in case_list: + cls.CURRENT_CASES.append(name) async def update_skin_data(name: str, is_update_case_name: bool = False) -> str: diff --git a/plugins/web_ui/api/group.py b/plugins/web_ui/api/group.py index 1e2f89c6..e7e73561 100644 --- a/plugins/web_ui/api/group.py +++ b/plugins/web_ui/api/group.py @@ -1,4 +1,5 @@ from pydantic.error_wrappers import ValidationError + from services.log import logger from utils.manager import group_manager from utils.utils import get_bot @@ -7,8 +8,8 @@ from ..auth import Depends, User, token_to_user from ..config import * -@app.get("/webui/group") -async def _(user: User = Depends(token_to_user)) -> Result: +@router.get("/group", dependencies=[token_to_user()]) +async def _() -> Result: """ 获取群信息 """ @@ -47,8 +48,8 @@ async def _(user: User = Depends(token_to_user)) -> Result: return Result(code=200, data=group_list_result) -@app.post("/webui/group") -async def _(group: GroupResult, user: User = Depends(token_to_user)) -> Result: +@router.post("/group", dependencies=[token_to_user()]) +async def _(group: GroupResult) -> Result: """ 修改群信息 """ @@ -58,4 +59,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, data="修改成功!") + return Result(data="修改成功!") diff --git a/plugins/web_ui/api/plugins.py b/plugins/web_ui/api/plugins.py index 23a94ba7..43fc744d 100644 --- a/plugins/web_ui/api/plugins.py +++ b/plugins/web_ui/api/plugins.py @@ -1,9 +1,14 @@ from pydantic import ValidationError + from configs.config import Config from services.log import logger -from utils.manager import (plugins2block_manager, plugins2cd_manager, - plugins2count_manager, plugins2settings_manager, - plugins_manager) +from utils.manager import ( + plugins2block_manager, + plugins2cd_manager, + plugins2count_manager, + plugins2settings_manager, + plugins_manager, +) from utils.utils import get_matchers from ..auth import Depends, User, token_to_user @@ -12,8 +17,8 @@ from ..config import * plugin_name_list = None -@app.get("/webui/plugins") -def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result: +@router.get("/plugins", dependencies=[token_to_user()]) +def _(type_: Optional[str]) -> Result: """ 获取插件列表 :param type_: 类型 normal, superuser, hidden, admin @@ -101,7 +106,7 @@ def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result: return Result(code=200, data=plugin_list) -@app.post("/webui/plugins") +@router.post("/plugins", dependencies=[token_to_user()]) def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result: """ 修改插件信息 @@ -126,7 +131,9 @@ def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result: ) or isinstance(c.default_value, float): c.value = float(c.value) elif isinstance(c.value, str) and ( - isinstance(Config.get_config(plugin.model, c.key, c.value), (list, tuple)) + isinstance( + Config.get_config(plugin.model, c.key, c.value), (list, tuple) + ) or isinstance(c.default_value, (list, tuple)) ): default_value = Config.get_config(plugin.model, c.key, c.value) @@ -161,7 +168,9 @@ def _(plugin: Plugin, user: User = Depends(token_to_user)) -> Result: ) for key in plugins2settings_manager.keys(): if isinstance(plugins2settings_manager[key].cmd, str): - plugins2settings_manager[key].cmd = plugins2settings_manager[key].cmd.split(',') + plugins2settings_manager[key].cmd = plugins2settings_manager[key].cmd.split( + "," + ) plugins2settings_manager.save() plugins_manager.save() return Result(code=200, data="修改成功!") diff --git a/plugins/web_ui/api/request.py b/plugins/web_ui/api/request.py index 02615304..d69957c8 100644 --- a/plugins/web_ui/api/request.py +++ b/plugins/web_ui/api/request.py @@ -6,8 +6,8 @@ from ..auth import Depends, User, token_to_user from ..config import * -@app.get("/webui/request") -def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result: +@router.get("/webui/request", dependencies=[token_to_user()]) +def _(type_: Optional[str]) -> Result: req_data = requests_manager.get_data() req_list = [] if type_ in ["group", "private"]: @@ -19,8 +19,8 @@ def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result: return Result(code=200, data=req_list) -@app.delete("/webui/request") -def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result: +@router.delete("/webui/request", dependencies=[token_to_user()]) +def _(type_: Optional[str]) -> Result: """ 清空请求 :param type_: 类型 @@ -29,8 +29,8 @@ def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result: return Result(code=200) -@app.post("/webui/request") -async def _(parma: RequestParma, user: User = Depends(token_to_user)) -> Result: +@router.post("/webui/request", dependencies=[token_to_user()]) +async def _(parma: RequestParma) -> Result: """ 操作请求 :param parma: 参数 diff --git a/plugins/web_ui/api/system.py b/plugins/web_ui/api/system.py index e83364b8..6faca37a 100644 --- a/plugins/web_ui/api/system.py +++ b/plugins/web_ui/api/system.py @@ -4,6 +4,7 @@ from pathlib import Path import psutil import ujson as json + from configs.path_config import ( DATA_PATH, FONT_PATH, @@ -28,21 +29,21 @@ memory_data = {"data": []} disk_data = {"data": []} -@app.get("/webui/system") +@router.get("/system", dependencies=[token_to_user()]) async def _() -> Result: return await get_system_data() -@app.get("/webui/system/status") -async def _(user: User = Depends(token_to_user)) -> Result: +@router.get("/webui/system/status", dependencies=[token_to_user()]) +async def _() -> Result: return Result( code=200, data=await asyncio.get_event_loop().run_in_executor(None, _get_system_status), ) -@app.get("/webui/system/disk") -async def _(type_: Optional[str] = None, user: User = Depends(token_to_user)) -> Result: +@router.get("/webui/system/disk", dependencies=[token_to_user()]) +async def _(type_: Optional[str] = None) -> Result: return Result( code=200, data=await asyncio.get_event_loop().run_in_executor( @@ -51,8 +52,8 @@ async def _(type_: Optional[str] = None, user: User = Depends(token_to_user)) -> ) -@app.get("/webui/system/statusList") -async def _(user: User = Depends(token_to_user)) -> Result: +@router.get("/webui/system/statusList", dependencies=[token_to_user()]) +async def _() -> Result: global cpu_data, memory_data, disk_data await asyncio.get_event_loop().run_in_executor(None, _get_system_status) cpu_rst = cpu_data["data"][-10:] if len(cpu_data["data"]) > 10 else cpu_data["data"] @@ -74,7 +75,7 @@ async def _(user: User = Depends(token_to_user)) -> Result: ) -async def get_system_data(user: User = Depends(token_to_user)): +async def get_system_data(): """ 说明: 获取系统信息,资源文件大小,网络状态等 @@ -105,7 +106,7 @@ async def get_system_data(user: User = Depends(token_to_user)): ) -def _get_system_status(user: User = Depends(token_to_user)) -> SystemStatus: +def _get_system_status() -> SystemStatus: """ 说明: 获取系统信息等 @@ -123,7 +124,7 @@ def _get_system_status(user: User = Depends(token_to_user)) -> SystemStatus: def _get_system_disk( - type_: Optional[str], user: User = Depends(token_to_user) + type_: Optional[str], ) -> Union[SystemFolderSize, Dict[str, Union[float, datetime]]]: """ 说明: diff --git a/plugins/web_ui/auth/__init__.py b/plugins/web_ui/auth/__init__.py index 4fce1d36..3983cf84 100644 --- a/plugins/web_ui/auth/__init__.py +++ b/plugins/web_ui/auth/__init__.py @@ -1,16 +1,18 @@ import json from datetime import datetime, timedelta -from configs.path_config import DATA_PATH from typing import Optional -from starlette import status + +import nonebot from fastapi import Depends, HTTPException from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from pydantic import BaseModel -from configs.config import Config from jose import JWTError, jwt -import nonebot +from pydantic import BaseModel +from starlette import status -from ..config import Result +from configs.config import Config +from configs.path_config import DATA_PATH + +from ..config import Result, router app = nonebot.get_app() @@ -19,14 +21,14 @@ SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="webui/login") +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/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')) + token_data = json.load(open(token_file, "r", encoding="utf8")) class User(BaseModel): @@ -39,11 +41,6 @@ class Token(BaseModel): token_type: str -# USER_LIST = [ -# User(username="admin", password="123") -# ] - - def get_user(uname: str) -> Optional[User]: username = Config.get_config("web-ui", "username") password = Config.get_config("web-ui", "password") @@ -59,24 +56,26 @@ form_exception = HTTPException( def create_token(user: User, expires_delta: Optional[timedelta] = None): - expire = datetime.utcnow() + expires_delta or timedelta(minutes=15) + expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15)) return jwt.encode( claims={"sub": user.username, "exp": expire}, key=SECRET_KEY, - algorithm=ALGORITHM + algorithm=ALGORITHM, ) -@app.post("/webui/login") +@router.post("/login") async def login_get_token(form_data: OAuth2PasswordRequestForm = Depends()): - user: User = get_user(form_data.username) + user = get_user(form_data.username) 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)) + 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:] - with open(token_file, 'w', encoding="utf8") as f: + with open(token_file, "w", encoding="utf8") as f: json.dump(token_data, f, ensure_ascii=False, indent=4) return {"access_token": access_token, "token_type": "bearer"} @@ -88,20 +87,21 @@ credentials_exception = HTTPException( ) -@app.post("/webui/auth") +@app.post("/auth") def token_to_user(token: str = Depends(oauth2_scheme)): 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) + user = get_user(username) # type: ignore if user is None: raise JWTError except JWTError: return Result(code=401) - return Result(code=200, data="ok") + return Result(code=200, info="登录成功") -if __name__ == '__main__': +if __name__ == "__main__": import uvicorn + uvicorn.run(app, host="127.0.0.1", port=8080) diff --git a/plugins/web_ui/config.py b/plugins/web_ui/config.py index ffda27b9..5b5b9c07 100644 --- a/plugins/web_ui/config.py +++ b/plugins/web_ui/config.py @@ -1,9 +1,10 @@ -from typing import Optional, List, Any, Union, Dict -from pydantic import BaseModel -from fastapi.middleware.cors import CORSMiddleware from datetime import datetime -import nonebot +from typing import Any, Dict, List, Optional, Union +import nonebot +from fastapi import APIRouter +from fastapi.middleware.cors import CORSMiddleware +from pydantic import BaseModel app = nonebot.get_app() @@ -17,11 +18,14 @@ app.add_middleware( allow_headers=["*"], ) +router = APIRouter(tags=["api"]) + class CdLimit(BaseModel): """ Cd 限制 """ + cd: int status: bool check_type: str @@ -33,6 +37,7 @@ class BlockLimit(BaseModel): """ Block限制 """ + status: bool check_type: str limit_type: str @@ -43,6 +48,7 @@ class CountLimit(BaseModel): """ Count限制 """ + max_count: int status: bool limit_type: str @@ -53,6 +59,7 @@ class PluginManager(BaseModel): """ 插件信息 """ + plugin_name: str # 插件名称 status: Optional[bool] # 插件状态 error: Optional[bool] # 加载状态 @@ -65,6 +72,7 @@ class PluginSettings(BaseModel): """ 插件基本设置 """ + level: Optional[int] # 群权限等级 default_status: Optional[bool] # 默认开关 limit_superuser: Optional[bool] # 是否限制超级用户 @@ -77,6 +85,7 @@ class PluginConfig(BaseModel): """ 插件配置项 """ + id: int key: str value: Optional[Any] @@ -88,6 +97,7 @@ class Plugin(BaseModel): """ 插件 """ + model: str # 模块 plugin_settings: Optional[PluginSettings] plugin_manager: Optional[PluginManager] @@ -101,6 +111,7 @@ class Group(BaseModel): """ 群组信息 """ + group_id: int group_name: str member_count: int @@ -111,6 +122,7 @@ class Task(BaseModel): """ 被动技能 """ + name: str nameZh: str status: bool @@ -120,6 +132,7 @@ class GroupResult(BaseModel): """ 群组返回数据 """ + group: Group level: int status: bool @@ -131,6 +144,7 @@ class RequestResult(BaseModel): """ 好友/群组请求管理 """ + oid: str id: int flag: str @@ -148,6 +162,7 @@ class RequestParma(BaseModel): """ 操作请求接收数据 """ + id: int handle: str type: str @@ -157,6 +172,7 @@ class SystemStatus(BaseModel): """ 系统状态 """ + cpu: int memory: int disk: int @@ -167,6 +183,7 @@ class SystemNetwork(BaseModel): """ 系统网络状态 """ + baidu: int google: int @@ -175,6 +192,7 @@ class SystemFolderSize(BaseModel): """ 资源文件占比 """ + font_dir_size: float image_dir_size: float text_dir_size: float @@ -189,6 +207,7 @@ class SystemStatusList(BaseModel): """ 状态记录 """ + cpu_data: List[Dict[str, Union[float, str]]] memory_data: List[Dict[str, Union[float, str]]] disk_data: List[Dict[str, Union[float, str]]] @@ -198,6 +217,7 @@ class SystemResult(BaseModel): """ 系统api返回 """ + status: SystemStatus network: SystemNetwork disk: SystemFolderSize @@ -208,5 +228,7 @@ class Result(BaseModel): """ 总体返回 """ - code: int - data: Any + + code: int = 200 + info: str = "操作成功" + data: Any = None diff --git a/resources/image/_icon/abrasion_white.png b/resources/image/_icon/abrasion_white.png new file mode 100644 index 00000000..ec08c67d Binary files /dev/null and b/resources/image/_icon/abrasion_white.png differ diff --git a/resources/image/_icon/name_white.png b/resources/image/_icon/name_white.png new file mode 100644 index 00000000..0c2afdb4 Binary files /dev/null and b/resources/image/_icon/name_white.png differ diff --git a/resources/image/_icon/tone_white.png b/resources/image/_icon/tone_white.png new file mode 100644 index 00000000..8e8434ba Binary files /dev/null and b/resources/image/_icon/tone_white.png differ diff --git a/utils/image_utils.py b/utils/image_utils.py index eb265ba5..7686ce9e 100755 --- a/utils/image_utils.py +++ b/utils/image_utils.py @@ -160,6 +160,7 @@ class BuildImage: h: int, paste_image_width: int = 0, paste_image_height: int = 0, + paste_space: int = 0, color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = None, image_mode: ModeType = "RGBA", font_size: int = 10, @@ -177,6 +178,7 @@ class BuildImage: :param h: 自定义图片的高度,h=0时为图片原本高度 :param paste_image_width: 当图片做为背景图时,设置贴图的宽度,用于贴图自动换行 :param paste_image_height: 当图片做为背景图时,设置贴图的高度,用于贴图自动换行 + :param paste_space: 自动贴图间隔 :param color: 生成图片的颜色 :param image_mode: 图片的类型 :param font_size: 文字大小 @@ -190,6 +192,7 @@ class BuildImage: self.h = int(h) self.paste_image_width = int(paste_image_width) self.paste_image_height = int(paste_image_height) + self.paste_space = int(paste_space) self._current_w = 0 self._current_h = 0 self.uid = uuid.uuid1() @@ -277,7 +280,9 @@ class BuildImage: :param center_type: 居中类型,可能的值 center: 完全居中,by_width: 水平居中,by_height: 垂直居中 :param allow_negative: 允许使用负数作为坐标且不超出图片范围,从右侧开始计算 """ - await self.loop.run_in_executor(None, self.paste, img, pos, alpha, center_type, allow_negative) + await self.loop.run_in_executor( + None, self.paste, img, pos, alpha, center_type, allow_negative + ) def paste( self, @@ -324,7 +329,7 @@ class BuildImage: img = img.markImg if self._current_w >= self.w: self._current_w = 0 - self._current_h += self.paste_image_height + self._current_h += self.paste_image_height + self.paste_space if not pos: pos = (self._current_w, self._current_h) if alpha: @@ -335,7 +340,7 @@ class BuildImage: self.markImg.paste(img, pos, img) else: self.markImg.paste(img, pos) - self._current_w += self.paste_image_width + self._current_w += self.paste_image_width + self.paste_space @classmethod def get_text_size(cls, msg: str, font: str, font_size: int) -> Tuple[int, int]: @@ -469,7 +474,7 @@ class BuildImage: "center_type must be 'center', 'by_width' or 'by_height'" ) w, h = self.w, self.h - longgest_text = '' + longgest_text = "" sentence = text.split("\n") for x in sentence: longgest_text = x if len(x) > len(longgest_text) else longgest_text