mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 14:22:55 +08:00
修改优化开箱显示图片
This commit is contained in:
parent
4e35090ba6
commit
0c7c7f3987
@ -331,6 +331,11 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
|
|||||||
|
|
||||||
## 更新
|
## 更新
|
||||||
|
|
||||||
|
### 2023/4/1
|
||||||
|
|
||||||
|
* 修复开箱偶尔出现`未抽取到任何皮肤`
|
||||||
|
* 修改优化开箱显示图片
|
||||||
|
|
||||||
### 2023/3/28
|
### 2023/3/28
|
||||||
|
|
||||||
* 补全注释`SCRIPT`中的sql语句
|
* 补全注释`SCRIPT`中的sql语句
|
||||||
|
|||||||
@ -235,7 +235,7 @@ async def _(event: MessageEvent, arg: Message = CommandArg(), cmd: str = OneComm
|
|||||||
await update_case.finish(f"未登录, 已停止更新...")
|
await update_case.finish(f"未登录, 已停止更新...")
|
||||||
rand = random.randint(300, 500)
|
rand = random.randint(300, 500)
|
||||||
result = f"更新全部{type_}完成"
|
result = f"更新全部{type_}完成"
|
||||||
if i < len(case_list):
|
if i < len(case_list) - 1:
|
||||||
next_case = case_list[i + 1]
|
next_case = case_list[i + 1]
|
||||||
result = f"将在 {rand} 秒后更新下一{type_}: {next_case}"
|
result = f"将在 {rand} 秒后更新下一{type_}: {next_case}"
|
||||||
await update_case.send(f"{info}, {result}")
|
await update_case.send(f"{info}, {result}")
|
||||||
@ -248,7 +248,9 @@ async def _(event: MessageEvent, arg: Message = CommandArg(), cmd: str = OneComm
|
|||||||
else:
|
else:
|
||||||
await update_case.send(f"开始{cmd}: {msg}, 请稍等")
|
await update_case.send(f"开始{cmd}: {msg}, 请稍等")
|
||||||
try:
|
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:
|
except Exception as e:
|
||||||
logger.error(f"{cmd}: {msg}", e=e)
|
logger.error(f"{cmd}: {msg}", e=e)
|
||||||
await update_case.send(f"成功{cmd}: {msg} 发生错误: {type(e)}: {e}")
|
await update_case.send(f"成功{cmd}: {msg} 发生错误: {type(e)}: {e}")
|
||||||
|
|||||||
@ -14,6 +14,56 @@ BASE_PATH = IMAGE_PATH / "csgo_cases"
|
|||||||
ICON_PATH = IMAGE_PATH / "_icon"
|
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]:
|
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"
|
file_path = BASE_PATH / cn2py(skin.case_name.split(",")[0]) / f"{cn2py(name)}.jpg"
|
||||||
if not file_path.exists():
|
if not file_path.exists():
|
||||||
logger.warning(f"皮肤图片: {name} 不存在", "查看武器箱")
|
logger.warning(f"皮肤图片: {name} 不存在", "查看武器箱")
|
||||||
return None
|
|
||||||
if skin.color == "CASE":
|
if skin.color == "CASE":
|
||||||
skin_img = BuildImage(200, 200, background=file_path)
|
|
||||||
case_bk = BuildImage(
|
case_bk = BuildImage(
|
||||||
700, 200, color=(25, 25, 25, 100), font_size=25, font="CJGaoDeGuo.otf"
|
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((250, 10, 250, 190))
|
||||||
await case_bk.aline((280, 160, 660, 160))
|
await case_bk.aline((280, 160, 660, 160))
|
||||||
name_icon = BuildImage(30, 30, background=ICON_PATH / "box_white.png")
|
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(
|
skin_bk = BuildImage(
|
||||||
235, 250, color=(25, 25, 25, 100), font_size=25, font="CJGaoDeGuo.otf"
|
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(
|
update_count_icon = BuildImage(
|
||||||
35, 35, background=ICON_PATH / "reload_white.png"
|
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.aline((10, 180, 220, 180))
|
||||||
await skin_bk.atext((10, 10), skin.name, (255, 255, 255))
|
await skin_bk.atext((10, 10), skin.name, (255, 255, 255))
|
||||||
await skin_bk.apaste(update_count_icon, (140, 10), True)
|
await skin_bk.apaste(update_count_icon, (140, 10), True)
|
||||||
|
|||||||
@ -72,7 +72,7 @@ class BuffSkin(Model):
|
|||||||
) -> List["BuffSkin"]: # type: ignore
|
) -> List["BuffSkin"]: # type: ignore
|
||||||
query = cls
|
query = cls
|
||||||
if case_name:
|
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)
|
query = query.filter(abrasion=abrasion, is_stattrak=is_stattrak, color=color)
|
||||||
skin_list = await query.annotate(rand=Random()).limit(num) # type:ignore
|
skin_list = await query.annotate(rand=Random()).limit(num) # type:ignore
|
||||||
num_ = num
|
num_ = num
|
||||||
|
|||||||
@ -14,6 +14,7 @@ from utils.image_utils import BuildImage
|
|||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from utils.utils import cn2py
|
from utils.utils import cn2py
|
||||||
|
|
||||||
|
from .build_image import draw_card
|
||||||
from .config import *
|
from .config import *
|
||||||
from .models.open_cases_log import OpenCasesLog
|
from .models.open_cases_log import OpenCasesLog
|
||||||
from .models.open_cases_user import OpenCasesUser
|
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)
|
logger.debug(f"添加 1 条开箱日志", "开箱", user_qq, group_id)
|
||||||
over_count = max_count - user.today_open_total
|
over_count = max_count - user.today_open_total
|
||||||
|
img = await draw_card(skin, rand)
|
||||||
return (
|
return (
|
||||||
f"开启{case_name}武器箱.\n剩余开箱次数:{over_count}.\n"
|
f"开启{case_name}武器箱.\n剩余开箱次数:{over_count}.\n"
|
||||||
+ image(img_path)
|
+ image(img)
|
||||||
+ "\n"
|
+ f"\n箱子单价:{case_price}\n花费:{17 + case_price:.2f}\n:{ridicule_result}"
|
||||||
+ 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}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -191,12 +189,7 @@ async def open_multiple_case(
|
|||||||
f"今天开箱次数不足{num}次噢,请单抽试试看(也许单抽运气更好?)"
|
f"今天开箱次数不足{num}次噢,请单抽试试看(也许单抽运气更好?)"
|
||||||
f"\n剩余开箱次数:{max_count - user.today_open_total}"
|
f"\n剩余开箱次数:{max_count - user.today_open_total}"
|
||||||
)
|
)
|
||||||
if num < 5:
|
logger.debug(f"尝试开启武器箱: {case_name}", "开箱", user_qq, group_id)
|
||||||
h = 270
|
|
||||||
elif num % 5 == 0:
|
|
||||||
h = 270 * int(num / 5)
|
|
||||||
else:
|
|
||||||
h = 270 * int(num / 5) + 270
|
|
||||||
case = cn2py(case_name)
|
case = cn2py(case_name)
|
||||||
skin_count = {}
|
skin_count = {}
|
||||||
img_list = []
|
img_list = []
|
||||||
@ -212,32 +205,19 @@ async def open_multiple_case(
|
|||||||
case_price = 0
|
case_price = 0
|
||||||
if case_skin := await BuffSkin.get_or_none(case_name=case_name, color="CASE"):
|
if case_skin := await BuffSkin.get_or_none(case_name=case_name, color="CASE"):
|
||||||
case_price = case_skin.sell_min_price
|
case_price = case_skin.sell_min_price
|
||||||
cnt = 0
|
img_w, img_h = 0, 0
|
||||||
for skin, rand in skin_list:
|
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
|
total_price += skin.sell_min_price
|
||||||
rand = str(rand)[:11]
|
|
||||||
add_count(user, skin, case_price)
|
|
||||||
color_name = COLOR2CN[skin.color]
|
color_name = COLOR2CN[skin.color]
|
||||||
if skin.is_stattrak:
|
|
||||||
color_name += "(暗金)"
|
|
||||||
if not skin_count.get(color_name):
|
if not skin_count.get(color_name):
|
||||||
skin_count[color_name] = 0
|
skin_count[color_name] = 0
|
||||||
skin_count[color_name] += 1
|
skin_count[color_name] += 1
|
||||||
name = skin.name + "-" + skin.skin_name + "-" + skin.abrasion
|
add_count(user, skin, case_price)
|
||||||
img_path = IMAGE_PATH / "csgo_cases" / case / f"{cn2py(name)}.jpg"
|
img_list.append(img)
|
||||||
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)
|
|
||||||
logger.info(
|
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,
|
user_qq,
|
||||||
group_id,
|
group_id,
|
||||||
@ -261,16 +241,26 @@ async def open_multiple_case(
|
|||||||
if log_list:
|
if log_list:
|
||||||
await OpenCasesLog.bulk_create(log_list, 10)
|
await OpenCasesLog.bulk_create(log_list, 10)
|
||||||
logger.debug(f"添加 {len(log_list)} 条开箱日志", "开箱", user_qq, group_id)
|
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:
|
for img in img_list:
|
||||||
markImg.paste(img)
|
markImg.paste(img, alpha=True)
|
||||||
over_count = max_count - user.today_open_total
|
over_count = max_count - user.today_open_total
|
||||||
result = ""
|
result = ""
|
||||||
for color_name in skin_count:
|
for color_name in skin_count:
|
||||||
result += f"[{color_name}:{skin_count[color_name]}] "
|
result += f"[{color_name}:{skin_count[color_name]}] "
|
||||||
return (
|
return (
|
||||||
f"开启{case_name}武器箱\n剩余开箱次数:{over_count}\n"
|
f"开启{case_name}武器箱\n剩余开箱次数:{over_count}\n"
|
||||||
+ image(markImg.pic2bs4())
|
+ image(markImg)
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ result[:-1]
|
+ result[:-1]
|
||||||
+ f"\n箱子单价:{case_price}\n总获取金额:{total_price:.2f}\n总花费:{(17 + case_price) * num:.2f}"
|
+ f"\n箱子单价:{case_price}\n总获取金额:{total_price:.2f}\n总花费:{(17 + case_price) * num:.2f}"
|
||||||
|
|||||||
@ -45,9 +45,19 @@ class CaseManager:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def reload(cls):
|
async def reload(cls):
|
||||||
cls.CURRENT_CASES = (
|
cls.CURRENT_CASES = []
|
||||||
await BuffSkin.filter(case_name__not="未知武器箱").annotate().distinct().values_list("case_name", flat=True) # type: ignore
|
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:
|
async def update_skin_data(name: str, is_update_case_name: bool = False) -> str:
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from pydantic.error_wrappers import ValidationError
|
from pydantic.error_wrappers import ValidationError
|
||||||
|
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from utils.manager import group_manager
|
from utils.manager import group_manager
|
||||||
from utils.utils import get_bot
|
from utils.utils import get_bot
|
||||||
@ -7,8 +8,8 @@ from ..auth import Depends, User, token_to_user
|
|||||||
from ..config import *
|
from ..config import *
|
||||||
|
|
||||||
|
|
||||||
@app.get("/webui/group")
|
@router.get("/group", dependencies=[token_to_user()])
|
||||||
async def _(user: User = Depends(token_to_user)) -> Result:
|
async def _() -> Result:
|
||||||
"""
|
"""
|
||||||
获取群信息
|
获取群信息
|
||||||
"""
|
"""
|
||||||
@ -47,8 +48,8 @@ async def _(user: User = Depends(token_to_user)) -> Result:
|
|||||||
return Result(code=200, data=group_list_result)
|
return Result(code=200, data=group_list_result)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/webui/group")
|
@router.post("/group", dependencies=[token_to_user()])
|
||||||
async def _(group: GroupResult, user: User = Depends(token_to_user)) -> Result:
|
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)
|
group_manager.turn_on_group_bot_status(group_id)
|
||||||
else:
|
else:
|
||||||
group_manager.shutdown_group_bot_status(group_id)
|
group_manager.shutdown_group_bot_status(group_id)
|
||||||
return Result(code=200, data="修改成功!")
|
return Result(data="修改成功!")
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
|
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from utils.manager import (plugins2block_manager, plugins2cd_manager,
|
from utils.manager import (
|
||||||
plugins2count_manager, plugins2settings_manager,
|
plugins2block_manager,
|
||||||
plugins_manager)
|
plugins2cd_manager,
|
||||||
|
plugins2count_manager,
|
||||||
|
plugins2settings_manager,
|
||||||
|
plugins_manager,
|
||||||
|
)
|
||||||
from utils.utils import get_matchers
|
from utils.utils import get_matchers
|
||||||
|
|
||||||
from ..auth import Depends, User, token_to_user
|
from ..auth import Depends, User, token_to_user
|
||||||
@ -12,8 +17,8 @@ from ..config import *
|
|||||||
plugin_name_list = None
|
plugin_name_list = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/webui/plugins")
|
@router.get("/plugins", dependencies=[token_to_user()])
|
||||||
def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
|
def _(type_: Optional[str]) -> Result:
|
||||||
"""
|
"""
|
||||||
获取插件列表
|
获取插件列表
|
||||||
:param type_: 类型 normal, superuser, hidden, admin
|
: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)
|
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:
|
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):
|
) or isinstance(c.default_value, float):
|
||||||
c.value = float(c.value)
|
c.value = float(c.value)
|
||||||
elif isinstance(c.value, str) and (
|
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))
|
or isinstance(c.default_value, (list, tuple))
|
||||||
):
|
):
|
||||||
default_value = Config.get_config(plugin.model, c.key, c.value)
|
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():
|
for key in plugins2settings_manager.keys():
|
||||||
if isinstance(plugins2settings_manager[key].cmd, str):
|
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()
|
plugins2settings_manager.save()
|
||||||
plugins_manager.save()
|
plugins_manager.save()
|
||||||
return Result(code=200, data="修改成功!")
|
return Result(code=200, data="修改成功!")
|
||||||
|
|||||||
@ -6,8 +6,8 @@ from ..auth import Depends, User, token_to_user
|
|||||||
from ..config import *
|
from ..config import *
|
||||||
|
|
||||||
|
|
||||||
@app.get("/webui/request")
|
@router.get("/webui/request", dependencies=[token_to_user()])
|
||||||
def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
|
def _(type_: Optional[str]) -> Result:
|
||||||
req_data = requests_manager.get_data()
|
req_data = requests_manager.get_data()
|
||||||
req_list = []
|
req_list = []
|
||||||
if type_ in ["group", "private"]:
|
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)
|
return Result(code=200, data=req_list)
|
||||||
|
|
||||||
|
|
||||||
@app.delete("/webui/request")
|
@router.delete("/webui/request", dependencies=[token_to_user()])
|
||||||
def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
|
def _(type_: Optional[str]) -> Result:
|
||||||
"""
|
"""
|
||||||
清空请求
|
清空请求
|
||||||
:param type_: 类型
|
:param type_: 类型
|
||||||
@ -29,8 +29,8 @@ def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
|
|||||||
return Result(code=200)
|
return Result(code=200)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/webui/request")
|
@router.post("/webui/request", dependencies=[token_to_user()])
|
||||||
async def _(parma: RequestParma, user: User = Depends(token_to_user)) -> Result:
|
async def _(parma: RequestParma) -> Result:
|
||||||
"""
|
"""
|
||||||
操作请求
|
操作请求
|
||||||
:param parma: 参数
|
:param parma: 参数
|
||||||
|
|||||||
@ -4,6 +4,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
import ujson as json
|
import ujson as json
|
||||||
|
|
||||||
from configs.path_config import (
|
from configs.path_config import (
|
||||||
DATA_PATH,
|
DATA_PATH,
|
||||||
FONT_PATH,
|
FONT_PATH,
|
||||||
@ -28,21 +29,21 @@ memory_data = {"data": []}
|
|||||||
disk_data = {"data": []}
|
disk_data = {"data": []}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/webui/system")
|
@router.get("/system", dependencies=[token_to_user()])
|
||||||
async def _() -> Result:
|
async def _() -> Result:
|
||||||
return await get_system_data()
|
return await get_system_data()
|
||||||
|
|
||||||
|
|
||||||
@app.get("/webui/system/status")
|
@router.get("/webui/system/status", dependencies=[token_to_user()])
|
||||||
async def _(user: User = Depends(token_to_user)) -> Result:
|
async def _() -> Result:
|
||||||
return Result(
|
return Result(
|
||||||
code=200,
|
code=200,
|
||||||
data=await asyncio.get_event_loop().run_in_executor(None, _get_system_status),
|
data=await asyncio.get_event_loop().run_in_executor(None, _get_system_status),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/webui/system/disk")
|
@router.get("/webui/system/disk", dependencies=[token_to_user()])
|
||||||
async def _(type_: Optional[str] = None, user: User = Depends(token_to_user)) -> Result:
|
async def _(type_: Optional[str] = None) -> Result:
|
||||||
return Result(
|
return Result(
|
||||||
code=200,
|
code=200,
|
||||||
data=await asyncio.get_event_loop().run_in_executor(
|
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")
|
@router.get("/webui/system/statusList", dependencies=[token_to_user()])
|
||||||
async def _(user: User = Depends(token_to_user)) -> Result:
|
async def _() -> Result:
|
||||||
global cpu_data, memory_data, disk_data
|
global cpu_data, memory_data, disk_data
|
||||||
await asyncio.get_event_loop().run_in_executor(None, _get_system_status)
|
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"]
|
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(
|
def _get_system_disk(
|
||||||
type_: Optional[str], user: User = Depends(token_to_user)
|
type_: Optional[str],
|
||||||
) -> Union[SystemFolderSize, Dict[str, Union[float, datetime]]]:
|
) -> Union[SystemFolderSize, Dict[str, Union[float, datetime]]]:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
import json
|
import json
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from configs.path_config import DATA_PATH
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from starlette import status
|
|
||||||
|
import nonebot
|
||||||
from fastapi import Depends, HTTPException
|
from fastapi import Depends, HTTPException
|
||||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||||
from pydantic import BaseModel
|
|
||||||
from configs.config import Config
|
|
||||||
from jose import JWTError, jwt
|
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()
|
app = nonebot.get_app()
|
||||||
|
|
||||||
@ -19,14 +21,14 @@ SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
|
|||||||
ALGORITHM = "HS256"
|
ALGORITHM = "HS256"
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
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 = DATA_PATH / "web_ui" / "token.json"
|
||||||
token_file.parent.mkdir(parents=True, exist_ok=True)
|
token_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
token_data = {"token": []}
|
token_data = {"token": []}
|
||||||
if token_file.exists():
|
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):
|
class User(BaseModel):
|
||||||
@ -39,11 +41,6 @@ class Token(BaseModel):
|
|||||||
token_type: str
|
token_type: str
|
||||||
|
|
||||||
|
|
||||||
# USER_LIST = [
|
|
||||||
# User(username="admin", password="123")
|
|
||||||
# ]
|
|
||||||
|
|
||||||
|
|
||||||
def get_user(uname: str) -> Optional[User]:
|
def get_user(uname: str) -> Optional[User]:
|
||||||
username = Config.get_config("web-ui", "username")
|
username = Config.get_config("web-ui", "username")
|
||||||
password = Config.get_config("web-ui", "password")
|
password = Config.get_config("web-ui", "password")
|
||||||
@ -59,24 +56,26 @@ form_exception = HTTPException(
|
|||||||
|
|
||||||
|
|
||||||
def create_token(user: User, expires_delta: Optional[timedelta] = None):
|
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(
|
return jwt.encode(
|
||||||
claims={"sub": user.username, "exp": expire},
|
claims={"sub": user.username, "exp": expire},
|
||||||
key=SECRET_KEY,
|
key=SECRET_KEY,
|
||||||
algorithm=ALGORITHM
|
algorithm=ALGORITHM,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/webui/login")
|
@router.post("/login")
|
||||||
async def login_get_token(form_data: OAuth2PasswordRequestForm = Depends()):
|
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:
|
if not user or user.password != form_data.password:
|
||||||
raise form_exception
|
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)
|
token_data["token"].append(access_token)
|
||||||
if len(token_data["token"]) > 3:
|
if len(token_data["token"]) > 3:
|
||||||
token_data["token"] = token_data["token"][1:]
|
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)
|
json.dump(token_data, f, ensure_ascii=False, indent=4)
|
||||||
return {"access_token": access_token, "token_type": "bearer"}
|
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)):
|
def token_to_user(token: str = Depends(oauth2_scheme)):
|
||||||
if token not in token_data["token"]:
|
if token not in token_data["token"]:
|
||||||
try:
|
try:
|
||||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||||
username, expire = payload.get("sub"), payload.get("exp")
|
username, expire = payload.get("sub"), payload.get("exp")
|
||||||
user = get_user(username)
|
user = get_user(username) # type: ignore
|
||||||
if user is None:
|
if user is None:
|
||||||
raise JWTError
|
raise JWTError
|
||||||
except JWTError:
|
except JWTError:
|
||||||
return Result(code=401)
|
return Result(code=401)
|
||||||
return Result(code=200, data="ok")
|
return Result(code=200, info="登录成功")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
uvicorn.run(app, host="127.0.0.1", port=8080)
|
uvicorn.run(app, host="127.0.0.1", port=8080)
|
||||||
|
|||||||
@ -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
|
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()
|
app = nonebot.get_app()
|
||||||
|
|
||||||
@ -17,11 +18,14 @@ app.add_middleware(
|
|||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
router = APIRouter(tags=["api"])
|
||||||
|
|
||||||
|
|
||||||
class CdLimit(BaseModel):
|
class CdLimit(BaseModel):
|
||||||
"""
|
"""
|
||||||
Cd 限制
|
Cd 限制
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cd: int
|
cd: int
|
||||||
status: bool
|
status: bool
|
||||||
check_type: str
|
check_type: str
|
||||||
@ -33,6 +37,7 @@ class BlockLimit(BaseModel):
|
|||||||
"""
|
"""
|
||||||
Block限制
|
Block限制
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status: bool
|
status: bool
|
||||||
check_type: str
|
check_type: str
|
||||||
limit_type: str
|
limit_type: str
|
||||||
@ -43,6 +48,7 @@ class CountLimit(BaseModel):
|
|||||||
"""
|
"""
|
||||||
Count限制
|
Count限制
|
||||||
"""
|
"""
|
||||||
|
|
||||||
max_count: int
|
max_count: int
|
||||||
status: bool
|
status: bool
|
||||||
limit_type: str
|
limit_type: str
|
||||||
@ -53,6 +59,7 @@ class PluginManager(BaseModel):
|
|||||||
"""
|
"""
|
||||||
插件信息
|
插件信息
|
||||||
"""
|
"""
|
||||||
|
|
||||||
plugin_name: str # 插件名称
|
plugin_name: str # 插件名称
|
||||||
status: Optional[bool] # 插件状态
|
status: Optional[bool] # 插件状态
|
||||||
error: Optional[bool] # 加载状态
|
error: Optional[bool] # 加载状态
|
||||||
@ -65,6 +72,7 @@ class PluginSettings(BaseModel):
|
|||||||
"""
|
"""
|
||||||
插件基本设置
|
插件基本设置
|
||||||
"""
|
"""
|
||||||
|
|
||||||
level: Optional[int] # 群权限等级
|
level: Optional[int] # 群权限等级
|
||||||
default_status: Optional[bool] # 默认开关
|
default_status: Optional[bool] # 默认开关
|
||||||
limit_superuser: Optional[bool] # 是否限制超级用户
|
limit_superuser: Optional[bool] # 是否限制超级用户
|
||||||
@ -77,6 +85,7 @@ class PluginConfig(BaseModel):
|
|||||||
"""
|
"""
|
||||||
插件配置项
|
插件配置项
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
key: str
|
key: str
|
||||||
value: Optional[Any]
|
value: Optional[Any]
|
||||||
@ -88,6 +97,7 @@ class Plugin(BaseModel):
|
|||||||
"""
|
"""
|
||||||
插件
|
插件
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model: str # 模块
|
model: str # 模块
|
||||||
plugin_settings: Optional[PluginSettings]
|
plugin_settings: Optional[PluginSettings]
|
||||||
plugin_manager: Optional[PluginManager]
|
plugin_manager: Optional[PluginManager]
|
||||||
@ -101,6 +111,7 @@ class Group(BaseModel):
|
|||||||
"""
|
"""
|
||||||
群组信息
|
群组信息
|
||||||
"""
|
"""
|
||||||
|
|
||||||
group_id: int
|
group_id: int
|
||||||
group_name: str
|
group_name: str
|
||||||
member_count: int
|
member_count: int
|
||||||
@ -111,6 +122,7 @@ class Task(BaseModel):
|
|||||||
"""
|
"""
|
||||||
被动技能
|
被动技能
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
nameZh: str
|
nameZh: str
|
||||||
status: bool
|
status: bool
|
||||||
@ -120,6 +132,7 @@ class GroupResult(BaseModel):
|
|||||||
"""
|
"""
|
||||||
群组返回数据
|
群组返回数据
|
||||||
"""
|
"""
|
||||||
|
|
||||||
group: Group
|
group: Group
|
||||||
level: int
|
level: int
|
||||||
status: bool
|
status: bool
|
||||||
@ -131,6 +144,7 @@ class RequestResult(BaseModel):
|
|||||||
"""
|
"""
|
||||||
好友/群组请求管理
|
好友/群组请求管理
|
||||||
"""
|
"""
|
||||||
|
|
||||||
oid: str
|
oid: str
|
||||||
id: int
|
id: int
|
||||||
flag: str
|
flag: str
|
||||||
@ -148,6 +162,7 @@ class RequestParma(BaseModel):
|
|||||||
"""
|
"""
|
||||||
操作请求接收数据
|
操作请求接收数据
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
handle: str
|
handle: str
|
||||||
type: str
|
type: str
|
||||||
@ -157,6 +172,7 @@ class SystemStatus(BaseModel):
|
|||||||
"""
|
"""
|
||||||
系统状态
|
系统状态
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cpu: int
|
cpu: int
|
||||||
memory: int
|
memory: int
|
||||||
disk: int
|
disk: int
|
||||||
@ -167,6 +183,7 @@ class SystemNetwork(BaseModel):
|
|||||||
"""
|
"""
|
||||||
系统网络状态
|
系统网络状态
|
||||||
"""
|
"""
|
||||||
|
|
||||||
baidu: int
|
baidu: int
|
||||||
google: int
|
google: int
|
||||||
|
|
||||||
@ -175,6 +192,7 @@ class SystemFolderSize(BaseModel):
|
|||||||
"""
|
"""
|
||||||
资源文件占比
|
资源文件占比
|
||||||
"""
|
"""
|
||||||
|
|
||||||
font_dir_size: float
|
font_dir_size: float
|
||||||
image_dir_size: float
|
image_dir_size: float
|
||||||
text_dir_size: float
|
text_dir_size: float
|
||||||
@ -189,6 +207,7 @@ class SystemStatusList(BaseModel):
|
|||||||
"""
|
"""
|
||||||
状态记录
|
状态记录
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cpu_data: List[Dict[str, Union[float, str]]]
|
cpu_data: List[Dict[str, Union[float, str]]]
|
||||||
memory_data: List[Dict[str, Union[float, str]]]
|
memory_data: List[Dict[str, Union[float, str]]]
|
||||||
disk_data: List[Dict[str, Union[float, str]]]
|
disk_data: List[Dict[str, Union[float, str]]]
|
||||||
@ -198,6 +217,7 @@ class SystemResult(BaseModel):
|
|||||||
"""
|
"""
|
||||||
系统api返回
|
系统api返回
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status: SystemStatus
|
status: SystemStatus
|
||||||
network: SystemNetwork
|
network: SystemNetwork
|
||||||
disk: SystemFolderSize
|
disk: SystemFolderSize
|
||||||
@ -208,5 +228,7 @@ class Result(BaseModel):
|
|||||||
"""
|
"""
|
||||||
总体返回
|
总体返回
|
||||||
"""
|
"""
|
||||||
code: int
|
|
||||||
data: Any
|
code: int = 200
|
||||||
|
info: str = "操作成功"
|
||||||
|
data: Any = None
|
||||||
|
|||||||
BIN
resources/image/_icon/abrasion_white.png
Normal file
BIN
resources/image/_icon/abrasion_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
BIN
resources/image/_icon/name_white.png
Normal file
BIN
resources/image/_icon/name_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
BIN
resources/image/_icon/tone_white.png
Normal file
BIN
resources/image/_icon/tone_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
@ -160,6 +160,7 @@ class BuildImage:
|
|||||||
h: int,
|
h: int,
|
||||||
paste_image_width: int = 0,
|
paste_image_width: int = 0,
|
||||||
paste_image_height: int = 0,
|
paste_image_height: int = 0,
|
||||||
|
paste_space: int = 0,
|
||||||
color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = None,
|
color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = None,
|
||||||
image_mode: ModeType = "RGBA",
|
image_mode: ModeType = "RGBA",
|
||||||
font_size: int = 10,
|
font_size: int = 10,
|
||||||
@ -177,6 +178,7 @@ class BuildImage:
|
|||||||
:param h: 自定义图片的高度,h=0时为图片原本高度
|
:param h: 自定义图片的高度,h=0时为图片原本高度
|
||||||
:param paste_image_width: 当图片做为背景图时,设置贴图的宽度,用于贴图自动换行
|
:param paste_image_width: 当图片做为背景图时,设置贴图的宽度,用于贴图自动换行
|
||||||
:param paste_image_height: 当图片做为背景图时,设置贴图的高度,用于贴图自动换行
|
:param paste_image_height: 当图片做为背景图时,设置贴图的高度,用于贴图自动换行
|
||||||
|
:param paste_space: 自动贴图间隔
|
||||||
:param color: 生成图片的颜色
|
:param color: 生成图片的颜色
|
||||||
:param image_mode: 图片的类型
|
:param image_mode: 图片的类型
|
||||||
:param font_size: 文字大小
|
:param font_size: 文字大小
|
||||||
@ -190,6 +192,7 @@ class BuildImage:
|
|||||||
self.h = int(h)
|
self.h = int(h)
|
||||||
self.paste_image_width = int(paste_image_width)
|
self.paste_image_width = int(paste_image_width)
|
||||||
self.paste_image_height = int(paste_image_height)
|
self.paste_image_height = int(paste_image_height)
|
||||||
|
self.paste_space = int(paste_space)
|
||||||
self._current_w = 0
|
self._current_w = 0
|
||||||
self._current_h = 0
|
self._current_h = 0
|
||||||
self.uid = uuid.uuid1()
|
self.uid = uuid.uuid1()
|
||||||
@ -277,7 +280,9 @@ class BuildImage:
|
|||||||
:param center_type: 居中类型,可能的值 center: 完全居中,by_width: 水平居中,by_height: 垂直居中
|
:param center_type: 居中类型,可能的值 center: 完全居中,by_width: 水平居中,by_height: 垂直居中
|
||||||
:param allow_negative: 允许使用负数作为坐标且不超出图片范围,从右侧开始计算
|
: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(
|
def paste(
|
||||||
self,
|
self,
|
||||||
@ -324,7 +329,7 @@ class BuildImage:
|
|||||||
img = img.markImg
|
img = img.markImg
|
||||||
if self._current_w >= self.w:
|
if self._current_w >= self.w:
|
||||||
self._current_w = 0
|
self._current_w = 0
|
||||||
self._current_h += self.paste_image_height
|
self._current_h += self.paste_image_height + self.paste_space
|
||||||
if not pos:
|
if not pos:
|
||||||
pos = (self._current_w, self._current_h)
|
pos = (self._current_w, self._current_h)
|
||||||
if alpha:
|
if alpha:
|
||||||
@ -335,7 +340,7 @@ class BuildImage:
|
|||||||
self.markImg.paste(img, pos, img)
|
self.markImg.paste(img, pos, img)
|
||||||
else:
|
else:
|
||||||
self.markImg.paste(img, pos)
|
self.markImg.paste(img, pos)
|
||||||
self._current_w += self.paste_image_width
|
self._current_w += self.paste_image_width + self.paste_space
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_text_size(cls, msg: str, font: str, font_size: int) -> Tuple[int, int]:
|
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'"
|
"center_type must be 'center', 'by_width' or 'by_height'"
|
||||||
)
|
)
|
||||||
w, h = self.w, self.h
|
w, h = self.w, self.h
|
||||||
longgest_text = ''
|
longgest_text = ""
|
||||||
sentence = text.split("\n")
|
sentence = text.split("\n")
|
||||||
for x in sentence:
|
for x in sentence:
|
||||||
longgest_text = x if len(x) > len(longgest_text) else longgest_text
|
longgest_text = x if len(x) > len(longgest_text) else longgest_text
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user