From a43a7b5f75c47963ab4173108a906bd875fe98ec Mon Sep 17 00:00:00 2001
From: HibiKier <775757368@qq.com>
Date: Sun, 12 Mar 2023 19:50:08 +0800
Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=BC=80=E7=AE=B1=E6=8C=87?=
=?UTF-8?q?=E4=BB=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
models/group_member_info.py | 11 +-
plugins/open_cases/__init__.py | 130 ++++++++++++++----------
plugins/open_cases/build_image.py | 94 +++++++++++++++++
plugins/open_cases/config.py | 36 +++++++
plugins/open_cases/open_cases_c.py | 34 ++-----
plugins/open_cases/utils.py | 157 +++++++++++++++++++++++++++--
utils/utils.py | 34 +++++++
7 files changed, 407 insertions(+), 89 deletions(-)
create mode 100644 plugins/open_cases/build_image.py
diff --git a/models/group_member_info.py b/models/group_member_info.py
index 74d856c0..fc03b32f 100755
--- a/models/group_member_info.py
+++ b/models/group_member_info.py
@@ -5,6 +5,7 @@ from tortoise import fields
from configs.config import Config
from services.db_context import Model
+from services.log import logger
class GroupInfoUser(Model):
@@ -39,7 +40,7 @@ class GroupInfoUser(Model):
"""
return set(
await cls.filter(group_id=group_id).values_list("user_qq", flat=True)
- )
+ ) # type: ignore
@classmethod
async def set_user_nickname(cls, user_qq: int, group_id: int, nickname: str):
@@ -67,7 +68,7 @@ class GroupInfoUser(Model):
"""
return list(
await cls.filter(user_qq=user_qq).values_list("group_id", flat=True)
- )
+ ) # type: ignore
@classmethod
async def get_user_nickname(cls, user_qq: int, group_id: int) -> str:
@@ -90,6 +91,9 @@ class GroupInfoUser(Model):
@classmethod
async def get_group_member_uid(cls, user_qq: int, group_id: int) -> Optional[int]:
+ logger.debug(
+ f"GroupInfoUser 尝试获取 用户[{user_qq}] 群聊[{group_id}] UID"
+ )
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
_max_uid_user, _ = await cls.get_or_create(user_qq=114514, group_id=114514)
_max_uid = _max_uid_user.uid
@@ -101,6 +105,9 @@ class GroupInfoUser(Model):
user.uid = _max_uid + 1
_max_uid_user.uid = _max_uid + 1
await cls.bulk_update([user, _max_uid_user], ["uid"])
+ logger.debug(
+ f"GroupInfoUser 获取 用户[{user_qq}] 群聊[{group_id}] UID: {user.uid}"
+ )
return user.uid
@classmethod
diff --git a/plugins/open_cases/__init__.py b/plugins/open_cases/__init__.py
index e8fefd18..caebe66e 100755
--- a/plugins/open_cases/__init__.py
+++ b/plugins/open_cases/__init__.py
@@ -1,4 +1,6 @@
+import asyncio
import random
+from datetime import datetime, timedelta
from typing import Any, List, Tuple
from nonebot import on_command
@@ -12,17 +14,25 @@ from nonebot.typing import T_State
from configs.config import Config
from configs.path_config import IMAGE_PATH
-from utils.utils import is_number, scheduler
+from services.log import logger
+from utils.message_builder import image
+from utils.utils import CN2NUM, is_number, scheduler
from .open_cases_c import (
+ auto_update,
get_my_knifes,
group_statistics,
open_case,
open_multiple_case,
total_open_statistics,
- update,
)
-from .utils import CASE2ID, CaseManager, reset_count_daily, update_case_data
+from .utils import (
+ CASE2ID,
+ CaseManager,
+ build_case_image,
+ reset_count_daily,
+ update_case_data,
+)
__zx_plugin_name__ = "开箱"
__plugin_usage__ = """
@@ -35,14 +45,10 @@ usage:
我的开箱
我的金色
群开箱统计
+ 查看武器箱?[武器箱]
* 不包含[武器箱]时随机开箱 *
- 目前支持的武器箱:
- 1.狂牙大行动武器箱
- 2.突围大行动武器箱
- 3.命悬一线武器箱
- 4.裂空武器箱
- 5.光谱武器箱
- 示例:开箱 命悬一线
+ 示例: 查看武器箱
+ 示例: 查看武器箱英勇
""".strip()
__plugin_superuser_usage__ = """
usage:
@@ -61,6 +67,7 @@ __plugin_cmd__ = [
"我的开箱",
"我的金色",
"群开箱统计",
+ "查看武器箱?[武器箱]",
"更新开箱图片 ?[武器箱] [_superuser]",
"更新开箱价格 ?[武器箱] [_superuser]",
]
@@ -89,10 +96,7 @@ __plugin_configs__ = {
"default_value": 3,
"type": int,
},
- "COOKIE": {
- "value": None,
- "help": "BUFF的cookie",
- },
+ "COOKIE": {"value": None, "help": "BUFF的cookie", "type": str},
"BUFF_PROXY": {"value": None, "help": "使用代理访问BUFF"},
"DAILY_UPDATE": {
"value": None,
@@ -121,8 +125,11 @@ total_case_data = cases_matcher_group.on_command(
)
group_open_case_statistics = cases_matcher_group.on_command("群开箱统计")
open_multiple = cases_matcher_group.on_regex("(.*)连开箱(.*)?")
-update_data = on_command("更新武器箱", priority=1, permission=SUPERUSER, block=True)
+update_case = on_command("更新武器箱", priority=1, permission=SUPERUSER, block=True)
+show_case = on_command("查看武器箱", priority=5, block=True)
my_knifes = on_command("我的金色", priority=1, permission=GROUP, block=True)
+show_skin = on_command("查看皮肤", priority=5, block=True)
+# show_case = on_command("test", priority=1, permission=GROUP, block=True)
@reload_count.handle()
@@ -163,9 +170,9 @@ async def _(
event: GroupMessageEvent, state: T_State, reg_group: Tuple[Any, ...] = RegexGroup()
):
num, case_name = reg_group
- if is_number(num) or num_dict.get(num):
+ if is_number(num) or CN2NUM.get(num):
try:
- num = num_dict[num]
+ num = CN2NUM[num]
except KeyError:
num = int(num)
if num > 30:
@@ -181,41 +188,7 @@ async def _(
)
-num_dict = {
- "一": 1,
- "二": 2,
- "三": 3,
- "四": 4,
- "五": 5,
- "六": 6,
- "七": 7,
- "八": 8,
- "九": 9,
- "十": 10,
- "十一": 11,
- "十二": 12,
- "十三": 13,
- "十四": 14,
- "十五": 15,
- "十六": 16,
- "十七": 17,
- "十八": 18,
- "十九": 19,
- "二十": 20,
- "二十一": 21,
- "二十二": 22,
- "二十三": 23,
- "二十四": 24,
- "二十五": 25,
- "二十六": 26,
- "二十七": 27,
- "二十八": 28,
- "二十九": 29,
- "三十": 30,
-}
-
-
-@update_data.handle()
+@update_case.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
if not msg:
@@ -225,9 +198,38 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
case_list.append(f"{i+1}.{case_name} [已更新]")
else:
case_list.append(f"{i+1}.{case_name}")
- await update_data.finish("未指定武器箱, 当前已包含武器箱\n" + "\n".join(case_list))
- await update_data.send(f"开始更新武器箱: {msg}, 请稍等")
- await update_data.send(await update_case_data(msg), at_sender=True)
+ await update_case.finish("未指定武器箱, 当前已包含武器箱\n" + "\n".join(case_list))
+ if msg == "ALL":
+ await update_case.send(f"即将更新所有武器箱, 请稍等")
+ case_list = list(CASE2ID.keys())
+ for i, case_name in enumerate(case_list):
+ try:
+ await update_case_data(case_name)
+ rand = random.randint(300, 500)
+ result = "更新全部武器箱完成"
+ if i < len(case_list):
+ next_case = case_list[i + 1]
+ result = f"将在 {rand} 秒后更新下一武器箱: {next_case}"
+ await update_case.send(f"成功更新武器箱: {case_name}, {result}")
+ logger.info(f"成功更新武器箱: {case_name}, {result}", "更新武器箱")
+ await asyncio.sleep(rand)
+ except Exception as e:
+ logger.error(f"自动更新武器箱: {case_name}", e=e)
+ await update_case.send(f"成功自动更新武器箱: {case_name} 发生错误: {type(e)}: {e}")
+ await update_case.send(f"开始更新全部武器箱完成")
+ else:
+ await update_case.send(f"开始更新武器箱: {msg}, 请稍等")
+ await update_case.send(await update_case_data(msg), at_sender=True)
+
+
+@show_case.handle()
+async def _(arg: Message = CommandArg()):
+ msg = arg.extract_plain_text().strip()
+ result = await build_case_image(msg)
+ if isinstance(result, str):
+ await show_case.send(result)
+ else:
+ await show_case.send(image(result))
# 重置开箱
@@ -238,3 +240,21 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
)
async def _():
await reset_count_daily()
+
+
+@scheduler.scheduled_job(
+ "cron",
+ hour=23,
+ minute=48,
+)
+async def _():
+ now = datetime.now()
+ hour = random.choice([0, 1, 2, 3])
+ date = now + timedelta(minutes=1)
+ logger.debug(f"将在 {date} 时自动更新武器箱...", "更新武器箱")
+ scheduler.add_job(
+ auto_update,
+ "date",
+ run_date=date.replace(microsecond=0),
+ id=f"auto_update_csgo_cases",
+ )
diff --git a/plugins/open_cases/build_image.py b/plugins/open_cases/build_image.py
new file mode 100644
index 00000000..c60a6a42
--- /dev/null
+++ b/plugins/open_cases/build_image.py
@@ -0,0 +1,94 @@
+from datetime import timedelta, timezone
+from typing import Optional
+
+from configs.path_config import IMAGE_PATH
+from services.log import logger
+from utils.image_utils import BuildImage
+from utils.utils import cn2py
+
+from .config import COLOR2COLOR, COLOR2NAME
+from .models.buff_skin import BuffSkin
+
+BASE_PATH = IMAGE_PATH / "csgo_cases"
+
+ICON_PATH = IMAGE_PATH / "_icon"
+
+
+async def generate_skin(skin: BuffSkin) -> Optional[BuildImage]:
+ """构造皮肤图片
+
+ Args:
+ skin (BuffSkin): BuffSkin
+
+ Returns:
+ Optional[BuildImage]: 图片
+ """
+ name = skin.name + "-" + skin.skin_name + "-" + skin.abrasion
+ file_path = BASE_PATH / cn2py(skin.case_name) / 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)
+ 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")
+ await case_bk.apaste(name_icon, (260, 25), True)
+ await case_bk.atext((295, 30), "名称:", (255, 255, 255))
+ await case_bk.atext((345, 25), skin.case_name, (255, 0, 38), font_size=30)
+
+ type_icon = BuildImage(30, 30, background=ICON_PATH / "type_white.png")
+ await case_bk.apaste(type_icon, (260, 70), True)
+ await case_bk.atext((295, 75), "类型:", (255, 255, 255))
+ await case_bk.atext((345, 72), "武器箱", (0, 157, 255), font_size=30)
+
+ price_icon = BuildImage(30, 30, background=ICON_PATH / "price_white.png")
+ await case_bk.apaste(price_icon, (260, 114), True)
+ await case_bk.atext((295, 120), "单价:", (255, 255, 255))
+ await case_bk.atext(
+ (340, 116), str(skin.sell_min_price), (0, 255, 98), font_size=30
+ )
+
+ price_icon = BuildImage(30, 30, background=ICON_PATH / "num_white.png")
+ await case_bk.apaste(price_icon, (455, 70), True)
+ await case_bk.atext((490, 75), "在售:", (255, 255, 255))
+ await case_bk.atext((535, 72), str(skin.sell_num), (144, 0, 255), font_size=30)
+
+ price_icon = BuildImage(30, 30, background=ICON_PATH / "want_buy_white.png")
+ await case_bk.apaste(price_icon, (455, 114), True)
+ await case_bk.atext((490, 120), "求购:", (255, 255, 255))
+ await case_bk.atext((535, 116), str(skin.buy_num), (144, 0, 255), font_size=30)
+
+ await case_bk.atext((275, 165), "更新时间", (255, 255, 255), font_size=22)
+ date = str(
+ skin.update_time.replace(microsecond=0).astimezone(
+ timezone(timedelta(hours=8))
+ )
+ ).split("+")[0]
+ await case_bk.atext(
+ (344, 170),
+ date,
+ (255, 255, 255),
+ font_size=30,
+ )
+ return case_bk
+ else:
+ skin_bk = BuildImage(
+ 235, 250, color=(25, 25, 25, 100), font_size=25, font="CJGaoDeGuo.otf"
+ )
+ skin_image = BuildImage(205, 153, background=file_path)
+ skin_bk.paste(skin_image, (10, 30), alpha=True)
+ # skin_bk.paste(circular_red, (-20, 10), True)
+ skin_bk.line((10, 180, 220, 180))
+ skin_bk.text((10, 10), skin.name, (255, 255, 255))
+ skin_bk.text((10, 185), f"{skin.skin_name}", (255, 255, 255), "by_width")
+ skin_bk.text((10, 218), "品质:", (255, 255, 255))
+ skin_bk.text((55, 218), COLOR2NAME[skin.color][:2], COLOR2COLOR[skin.color])
+ skin_bk.text((100, 218), "类型:", (255, 255, 255))
+ skin_bk.text((145, 218), skin.weapon_type, (255, 255, 255))
+ return skin_bk
+ return None
diff --git a/plugins/open_cases/config.py b/plugins/open_cases/config.py
index 36f8cc9b..469278e6 100755
--- a/plugins/open_cases/config.py
+++ b/plugins/open_cases/config.py
@@ -1,6 +1,7 @@
import random
from typing import List, Tuple
+from configs.path_config import IMAGE_PATH
from services.log import logger
from .models.buff_skin import BuffSkin
@@ -33,6 +34,41 @@ BATTLE_SCARED_S = 0.45
BATTLE_SCARED_E = 0.99999
+NAME2COLOR = {
+ "消费级": "WHITE",
+ "工业级": "LIGHTBLUE",
+ "军规级": "BLUE",
+ "受限": "PURPLE",
+ "保密": "PINK",
+ "隐秘": "RED",
+ "非凡": "KNIFE",
+}
+
+COLOR2NAME = {
+ "WHITE": "消费级",
+ "LIGHTBLUE": "工业级",
+ "BLUE": "军规级",
+ "PURPLE": "受限",
+ "PINK": "保密",
+ "RED": "隐秘",
+ "KNIFE": "非凡",
+}
+
+COLOR2COLOR = {
+ "WHITE": (255, 255, 255),
+ "LIGHTBLUE": (0, 179, 255),
+ "BLUE": (0, 85, 255),
+ "PURPLE": (149, 0, 255),
+ "PINK": (255, 0, 162),
+ "RED": (255, 34, 0),
+ "KNIFE": (255, 225, 0),
+}
+
+ABRASION_SORT = ["崭新出厂", "略有磨损", "久经沙场", "破损不堪", "战横累累"]
+
+CASE_BACKGROUND = IMAGE_PATH / "csgo_cases" / "_background" / "shu"
+
+
CASE2ID = {
"变革": "set_community_32",
"反冲": "set_community_31",
diff --git a/plugins/open_cases/open_cases_c.py b/plugins/open_cases/open_cases_c.py
index eddb5a61..9de630d2 100755
--- a/plugins/open_cases/open_cases_c.py
+++ b/plugins/open_cases/open_cases_c.py
@@ -12,7 +12,7 @@ from models.sign_group_user import SignGroupUser
from services.log import logger
from utils.image_utils import BuildImage
from utils.message_builder import image
-from utils.utils import cn2py, scheduler
+from utils.utils import cn2py
from .config import *
from .models.open_cases_log import OpenCasesLog
@@ -99,7 +99,7 @@ async def open_case(user_qq: int, group_id: int, case_name: str) -> Union[str, M
if not case_name:
case_name = random.choice(CaseManager.CURRENT_CASES) # type: ignore
if case_name not in CaseManager.CURRENT_CASES:
- return "武器箱未收录, 当前可用武器箱:\n" + "\n".join(CaseManager.CURRENT_CASES) # type: ignore
+ return "武器箱未收录, 当前可用武器箱:\n" + ", ".join(CaseManager.CURRENT_CASES) # type: ignore
logger.debug(f"尝试开启武器箱: {case_name}", "开箱", user_qq, group_id)
case = cn2py(case_name)
user = await OpenCasesUser.get_or_none(user_qq=user_qq, group_id=group_id)
@@ -152,7 +152,7 @@ async def open_case(user_qq: int, group_id: int, case_name: str) -> Union[str, M
+ "\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}\n"
+ f"价格:{price_result}\n箱子单价:{case_price}\n花费:{17 + case_price:.2f}\n"
f":{ridicule_result}"
)
@@ -176,7 +176,7 @@ async def open_multiple_case(
if not case_name:
case_name = random.choice(CaseManager.CURRENT_CASES) # type: ignore
if case_name not in CaseManager.CURRENT_CASES:
- return "武器箱未收录, 当前可用武器箱:\n" + "\n".join(CaseManager.CURRENT_CASES) # type: ignore
+ return "武器箱未收录, 当前可用武器箱:\n" + ", ".join(CaseManager.CURRENT_CASES) # type: ignore
user, _ = await OpenCasesUser.get_or_create(
user_qq=user_qq,
group_id=group_id,
@@ -208,7 +208,6 @@ 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
- print(user.today_open_total)
cnt = 0
for skin, rand in skin_list:
total_price += skin.sell_min_price
@@ -255,7 +254,6 @@ async def open_multiple_case(
)
)
await user.save()
- print(user.today_open_total)
if log_list:
await OpenCasesLog.bulk_create(log_list, 10)
logger.debug(f"添加 {len(log_list)} 条开箱日志", "开箱", user_qq, group_id)
@@ -271,7 +269,7 @@ async def open_multiple_case(
+ image(markImg.pic2bs4())
+ "\n"
+ result[:-1]
- + f"\n箱子单价:{case_price}\n总获取金额:{total_price:.2f}\n总花费:{(17 + case_price) * num}"
+ + f"\n箱子单价:{case_price}\n总获取金额:{total_price:.2f}\n总花费:{(17 + case_price) * num:.2f}"
)
@@ -427,24 +425,8 @@ async def get_old_knife(user_id: int, group_id: int) -> List[OpenCasesLog]:
return data_list
-@scheduler.scheduled_job(
- "cron",
- hour=0,
- minute=1,
-)
-async def _():
- now = datetime.now()
- hour = random.choice([0, 1, 2, 3])
- date = now + timedelta(hours=hour)
- scheduler.add_job(
- update,
- "date",
- run_date=date.replace(microsecond=0),
- id=f"auto_update_csgo_cases",
- )
-
-
-async def update():
+async def auto_update():
+ """自动更新武器箱"""
if case_list := Config.get_config("open_cases", "DAILY_UPDATE"):
logger.debug("尝试自动更新武器箱", "更新武器箱")
if "ALL" in case_list:
@@ -455,7 +437,7 @@ async def update():
try:
await update_case_data(case_name)
rand = random.randint(300, 500)
- logger.debug(f"成功自动更新武器箱: {case_name}, 将在 {rand} 秒后再次更新下一武器箱", "更新武器箱")
+ logger.info(f"成功自动更新武器箱: {case_name}, 将在 {rand} 秒后再次更新下一武器箱", "更新武器箱")
await asyncio.sleep(rand)
except Exception as e:
logger.error(f"自动更新武器箱: {case_name}", e=e)
diff --git a/plugins/open_cases/utils.py b/plugins/open_cases/utils.py
index 820d2d51..a28ed53e 100755
--- a/plugins/open_cases/utils.py
+++ b/plugins/open_cases/utils.py
@@ -1,4 +1,5 @@
import asyncio
+import os
import random
import time
from datetime import datetime
@@ -10,9 +11,11 @@ from configs.config import Config
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
+from utils.image_utils import BuildImage
from utils.utils import broadcast_group, cn2py
-from .config import CASE2ID
+from .build_image import generate_skin
+from .config import CASE2ID, CASE_BACKGROUND, COLOR2NAME, NAME2COLOR
from .models.buff_skin import BuffSkin
from .models.buff_skin_log import BuffSkinLog
from .models.open_cases_user import OpenCasesUser
@@ -20,9 +23,6 @@ from .models.open_cases_user import OpenCasesUser
URL = "https://buff.163.com/api/market/goods"
# proxies = 'http://49.75.59.242:3128'
-NAME2COLOR = {"消费级": "WHITE", "工业级": "LIGHTBLUE", "军规级": "BLUE", "受限": "PURPLE", "保密": "PINK", "隐秘": "RED", "非凡": "KNIFE"}
-
-CURRENT_CASES = []
driver = nonebot.get_driver()
@@ -220,10 +220,10 @@ async def search_skin_page(
obj["weapon_type"] = tags["type"]["localized_name"] # 枪械类型
if obj["weapon_type"] in ["音乐盒", "印花", "探员"]:
continue
- if obj["weapon_type"] in ["匕首", "手套"]:
+ elif obj["weapon_type"] in ["匕首", "手套"]:
obj["color"] = "KNIFE"
obj["name"] = data["short_name"].split("(")[0].strip() # 名称
- if obj["weapon_type"] in ["武器箱"]:
+ elif obj["weapon_type"] in ["武器箱"]:
obj["color"] = "CASE"
obj["name"] = data["short_name"]
else:
@@ -260,6 +260,151 @@ async def search_skin_page(
return f'访问失败: {json_data["error"]}', -1
+async def build_case_image(case_name: str) -> Union[BuildImage, str]:
+ """构造武器箱图片
+
+ Args:
+ case_name (str): 名称
+
+ Returns:
+ Union[BuildImage, str]: 图片
+ """
+ background = random.choice(os.listdir(CASE_BACKGROUND))
+ background_img = BuildImage(0, 0, background=CASE_BACKGROUND / background)
+ if case_name:
+ skin_list_ = await BuffSkin.filter(case_name=case_name).all()
+ case = None
+ skin_list: List[BuffSkin] = []
+ exists_name = []
+ for skin in skin_list_:
+ if skin.color == "CASE":
+ case = skin
+ else:
+ name = skin.name + skin.skin_name
+ if name not in exists_name:
+ skin_list.append(skin)
+ exists_name.append(name)
+ generate_img = {}
+ for skin in skin_list:
+ skin_img = await generate_skin(skin)
+ if skin_img:
+ if not generate_img.get(skin.color):
+ generate_img[skin.color] = []
+ generate_img[skin.color].append(skin_img)
+ skin_image_list = []
+ for color in COLOR2NAME:
+ if generate_img.get(color):
+ skin_image_list = skin_image_list + generate_img[color]
+ img = skin_image_list[0]
+ img_w, img_h = img.size
+ total_size = (img_w + 25) * (img_h + 10) * len(skin_image_list) # 总面积
+ new_size = get_bk_image_size(total_size, background_img.size, img.size, 250)
+ A = BuildImage(
+ new_size[0] + 50, new_size[1], background=CASE_BACKGROUND / background
+ )
+ await A.afilter("GaussianBlur", 2)
+ if case:
+ case_img = await generate_skin(case)
+ if case_img:
+ A.paste(case_img, (25, 25), True)
+ w = 25
+ h = 230
+ skin_image_list.reverse()
+ for image in skin_image_list:
+ A.paste(image, (w, h), True)
+ w += image.w + 20
+ if w + image.w - 25 > A.w:
+ h += image.h + 10
+ w = 25
+ if h + img_h + 100 < A.h:
+ await A.acrop((0, 0, A.w, h + img_h + 100))
+ return A
+ else:
+ skin_list = await BuffSkin.filter(color="CASE").all()
+ image_list: List[BuildImage] = []
+ for skin in skin_list:
+ if img := await generate_skin(skin):
+ image_list.append(img)
+ if not image_list:
+ return "未收录武器箱"
+ w = 25
+ h = 150
+ img = image_list[0]
+ img_w, img_h = img.size
+ total_size = (img_w + 25) * (img_h + 10) * len(image_list) # 总面积
+
+ new_size = get_bk_image_size(total_size, background_img.size, img.size, 155)
+ A = BuildImage(
+ new_size[0] + 50, new_size[1], background=CASE_BACKGROUND / background
+ )
+ await A.afilter("GaussianBlur", 2)
+ bk_img = BuildImage(
+ img_w, 120, color=(25, 25, 25, 100), font_size=60, font="CJGaoDeGuo.otf"
+ )
+ await bk_img.atext(
+ (0, 0), f"已收录 {len(image_list)} 个武器箱", (255, 255, 255), center_type="center"
+ )
+ await A.apaste(bk_img, (10, 10), True, "by_width")
+ for image in image_list:
+ A.paste(image, (w, h), True)
+ w += image.w + 20
+ if w + image.w - 25 > A.w:
+ h += image.h + 10
+ w = 25
+ if h + img_h + 100 < A.h:
+ await A.acrop((0, 0, A.w, h + img_h + 100))
+ return A
+
+
+def get_bk_image_size(
+ total_size: int,
+ base_size: Tuple[int, int],
+ img_size: Tuple[int, int],
+ extra_height: int = 0,
+):
+ """获取所需背景大小且不改变图片长宽比
+
+ Args:
+ total_size (int): 总面积
+ base_size (Tuple[int, int]): 初始背景大小
+ img_size (Tuple[int, int]): 贴图大小
+
+ Returns:
+ _type_: 满足所有贴图大小
+ """
+ bk_w, bk_h = base_size
+ img_w, img_h = img_size
+ is_add_title_size = False
+ left_dis = 0
+ right_dis = 0
+ old_size = (0, 0)
+ new_size = (0, 0)
+ ratio = 1.1
+ while 1:
+ w_ = int(ratio * bk_w)
+ h_ = int(ratio * bk_h)
+ size = w_ * h_
+ if size < total_size:
+ left_dis = size
+ else:
+ right_dis = size
+ r = w_ / (img_w + 25)
+ if right_dis and r - int(r) < 0.1:
+ if not is_add_title_size and extra_height:
+ total_size = int(total_size + w_ * extra_height)
+ is_add_title_size = True
+ right_dis = 0
+ continue
+ if total_size - left_dis > right_dis - total_size:
+ new_size = (w_, h_)
+ else:
+ new_size = old_size
+ break
+ old_size = (w_, h_)
+ ratio += 0.1
+ return new_size
+
+
async def reset_count_daily():
"""
重置每日开箱
diff --git a/utils/utils.py b/utils/utils.py
index 3e87e95e..50e8feb0 100755
--- a/utils/utils.py
+++ b/utils/utils.py
@@ -34,6 +34,40 @@ GDict = {
}
+CN2NUM = {
+ "一": 1,
+ "二": 2,
+ "三": 3,
+ "四": 4,
+ "五": 5,
+ "六": 6,
+ "七": 7,
+ "八": 8,
+ "九": 9,
+ "十": 10,
+ "十一": 11,
+ "十二": 12,
+ "十三": 13,
+ "十四": 14,
+ "十五": 15,
+ "十六": 16,
+ "十七": 17,
+ "十八": 18,
+ "十九": 19,
+ "二十": 20,
+ "二十一": 21,
+ "二十二": 22,
+ "二十三": 23,
+ "二十四": 24,
+ "二十五": 25,
+ "二十六": 26,
+ "二十七": 27,
+ "二十八": 28,
+ "二十九": 29,
+ "三十": 30,
+}
+
+
class CountLimiter:
"""
次数检测工具,检测调用次数是否超过设定值