更新开箱指令

This commit is contained in:
HibiKier 2023-03-12 19:50:08 +08:00
parent 5b9218251e
commit a43a7b5f75
7 changed files with 407 additions and 89 deletions

View File

@ -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 尝试获取 用户[<u><e>{user_qq}</e></u>] 群聊[<u><e>{group_id}</e></u>] 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 获取 用户[<u><e>{user_qq}</e></u>] 群聊[<u><e>{group_id}</e></u>] UID: {user.uid}"
)
return user.uid
@classmethod

View File

@ -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",
)

View File

@ -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

View File

@ -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",

View File

@ -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)

View File

@ -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():
"""
重置每日开箱

View File

@ -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:
"""
次数检测工具检测调用次数是否超过设定值