Compare commits

..
8 Commits
Author SHA1 Message Date
HibiKier 1059a0aae0 Update README.md 2022-05-03 15:40:19 +08:00
HibiKier e6576e7f40 Update README.md 2022-05-03 15:34:47 +08:00
HibiKier 5837144095 Update data_source.py 2022-05-03 15:31:34 +08:00
HibiKier d30a5c4207 Update data_source.py 2022-05-03 10:03:27 +08:00
HibiKier 7d169b0e5e Update README.md 2022-05-03 09:46:06 +08:00
HibiKier 1f54226673 update ShopRegister 2022-05-03 09:43:38 +08:00
HibiKier 901a90ff13 update v0.1.5.1 2022-05-03 02:03:06 +08:00
HibiKier 56573d1d34 update black_word 2022-05-01 15:53:52 +08:00
21 changed files with 1158 additions and 210 deletions
-1
View File
@@ -142,6 +142,5 @@ test.py
server_ip.py server_ip.py
member_activity_handle.py member_activity_handle.py
Yu-Gi-Oh/ Yu-Gi-Oh/
black_word/
csgo/ csgo/
fantasy_card/ fantasy_card/
+12 -1
View File
@@ -242,7 +242,18 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
## 更新 ## 更新
### 2022/4/26 ### 2022/5/3 \[v0.1.5.2]
* 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数
* 添加商品注册装饰器shop_register
* 修复商品函数kwargs无法获取参数值
### 2022/5/1
* 删除了`group_last_chat`插件(该功能可由`chat_history`替代
* 新增敏感词检测(全新反击系统,是时候重拳出击了
### 2022/4/26 \[v0.5.1.0]
* 修复了群白名单无法正确添加 * 修复了群白名单无法正确添加
* 优化了管理员帮助图片,背景图层将位于最下层 * 优化了管理员帮助图片,背景图层将位于最下层
+1 -1
View File
@@ -1 +1 @@
__version__: v0.1.5.0 __version__: v0.1.5.1
@@ -42,7 +42,7 @@ __plugin_settings__ = {
} }
msg_handler = on_regex(r"(周|月)?消息统计(des|DES)?(n=[0-9]{1,2})?", priority=5, block=True) msg_handler = on_regex(r"^(周|月)?消息统计(des|DES)?(n=[0-9]{1,2})?$", priority=5, block=True)
@msg_handler.handle() @msg_handler.handle()
+2 -2
View File
@@ -277,7 +277,7 @@ def _create_help_img(
0, 0,
plain_text=msg, plain_text=msg,
font_size=24, font_size=24,
font="yuanshen.ttf", font="HYWenHei-85W.ttf",
) )
B.paste(text, (w, h), True) B.paste(text, (w, h), True)
h += 50 h += 50
@@ -289,7 +289,7 @@ def _create_help_img(
0, 0,
plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护", plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护",
font_size=24, font_size=24,
font="yuanshen.ttf", font="HYWenHei-85W.ttf",
font_color=(231, 74, 57) font_color=(231, 74, 57)
), ),
(300, 10), (300, 10),
+52 -34
View File
@@ -7,6 +7,7 @@ from typing import Optional, Union
from configs.config import Config from configs.config import Config
from nonebot import Driver from nonebot import Driver
from nonebot.plugin import require from nonebot.plugin import require
from utils.decorator.shop import shop_register
import nonebot import nonebot
import time import time
@@ -20,24 +21,26 @@ async def init_default_shop_goods():
""" """
导入内置的三个商品 导入内置的三个商品
""" """
async def sign_card(**kwargs):
user_id = kwargs['user_id'] @shop_register(
group_id = kwargs['group_id'] name=("好感度双倍加持卡Ⅰ", "好感度双倍加持卡Ⅱ", "好感度双倍加持卡Ⅲ"),
prob = kwargs["prob"] price=(30, 150, 250),
des=(
"下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)",
"下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)",
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
),
load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
)
async def sign_card(user_id: int, group_id: int, prob: float):
user = await SignGroupUser.ensure(user_id, group_id) user = await SignGroupUser.ensure(user_id, group_id)
await user.update(add_probability=prob).apply() await user.update(add_probability=prob).apply()
if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
await register_goods( @driver.on_bot_connect
"好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)" async def _():
) await shop_register.load_register()
use.register_use("好感度双倍加持卡Ⅰ", sign_card, **{"prob": 0.1})
await register_goods("好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)")
use.register_use("好感度双倍加持卡Ⅱ", sign_card, **{"prob": 0.2})
await register_goods(
"好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"
)
use.register_use("好感度双倍加持卡Ⅲ", sign_card, **{"prob": 0.3})
# 创建商店界面 # 创建商店界面
@@ -59,9 +62,7 @@ async def create_shop_help() -> str:
A = BuildImage(1000, h, color="#f9f6f2") A = BuildImage(1000, h, color="#f9f6f2")
current_h = 0 current_h = 0
for goods in _list: for goods in _list:
bk = BuildImage( bk = BuildImage(700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf"
)
goods_image = BuildImage( goods_image = BuildImage(
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf" 600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
) )
@@ -92,10 +93,18 @@ async def create_shop_help() -> str:
await bk.apaste(goods_image, alpha=True) await bk.apaste(goods_image, alpha=True)
# 添加限时图标和时间 # 添加限时图标和时间
if goods.goods_limit_time > 0: if goods.goods_limit_time > 0:
_limit_time_logo = BuildImage(40, 40, background=f"{IMAGE_PATH}/other/time.png") _limit_time_logo = BuildImage(
40, 40, background=f"{IMAGE_PATH}/other/time.png"
)
await bk.apaste(_limit_time_logo, (600, 0), True) await bk.apaste(_limit_time_logo, (600, 0), True)
await bk.apaste(BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"), (640, 10), True) await bk.apaste(
limit_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)).split() BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"),
(640, 10),
True,
)
limit_time = time.strftime(
"%Y-%m-%d %H:%M", time.localtime(goods.goods_limit_time)
).split()
y_m_d = limit_time[0] y_m_d = limit_time[0]
_h_m = limit_time[1].split(":") _h_m = limit_time[1].split(":")
h_m = _h_m[0] + "时 " + _h_m[1] + "分" h_m = _h_m[0] + "时 " + _h_m[1] + "分"
@@ -125,12 +134,12 @@ async def create_shop_help() -> str:
async def register_goods( async def register_goods(
name: str, name: str,
price: int, price: int,
des: str, des: str,
discount: Optional[float] = 1, discount: Optional[float] = 1,
limit_time: Optional[int] = 0, limit_time: Optional[int] = 0,
**kwargs, **kwargs,
): ):
""" """
添加商品 添加商品
@@ -151,12 +160,17 @@ async def register_goods(
des = kwargs.get("des") des = kwargs.get("des")
discount = kwargs.get("discount") discount = kwargs.get("discount")
limit_time = kwargs.get("time_limit") limit_time = kwargs.get("time_limit")
limit_time = float(limit_time) if limit_time else limit_time if await GoodsInfo.get_goods_info(name):
discount = discount if discount is None else 1 limit_time = float(limit_time) if limit_time else limit_time
limit_time = int(time.time() + limit_time * 60 * 60) if limit_time is not None and limit_time != 0 else 0 discount = discount if discount is None else 1
return await GoodsInfo.add_goods( limit_time = (
name, int(price), des, float(discount), limit_time int(time.time() + limit_time * 60 * 60)
) if limit_time is not None and limit_time != 0
else 0
)
return await GoodsInfo.add_goods(
name, int(price), des, float(discount), limit_time
)
# 删除商品 # 删除商品
@@ -230,7 +244,11 @@ async def update_goods(**kwargs) -> "str, str, int":
int(price), int(price),
des, des,
float(discount), float(discount),
int(time.time() + limit_time * 60 * 60 if limit_time != 0 and new_time else 0), int(
time.time() + limit_time * 60 * 60
if limit_time != 0 and new_time
else 0
),
), ),
name, name,
tmp[:-1], tmp[:-1],
+80 -31
View File
@@ -1,7 +1,11 @@
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment
from services.log import logger from services.log import logger
from nonebot.adapters.onebot.v11 import Bot from nonebot.adapters.onebot.v11 import Bot
from pydantic import create_model
from utils.models import ShopParam
from typing import Optional, Union from typing import Optional, Union
from types import MappingProxyType
import inspect
import asyncio import asyncio
@@ -30,24 +34,52 @@ class GoodsUseFuncManager:
:param goods_name: 商品名称 :param goods_name: 商品名称
""" """
if self.exists(goods_name): if self.exists(goods_name):
return self._data[goods_name]["kwargs"]["_max_num_limit"] return self._data[goods_name]["kwargs"]["max_num_limit"]
return 1 return 1
async def use(self, **kwargs) -> Optional[Union[str, MessageSegment]]: async def use(
self, param: ShopParam, **kwargs
) -> Optional[Union[str, MessageSegment]]:
""" """
使用道具 使用道具
:param param: BaseModel
:param kwargs: kwargs :param kwargs: kwargs
""" """
goods_name = kwargs.get("goods_name") def parse_args(args_: MappingProxyType):
param_list_ = []
_bot = param.bot
param.bot = None
param_json = param.dict()
param_json["bot"] = _bot
for par in args_.keys():
if par in ["shop_param"]:
param_list_.append(param)
elif par not in ["args", "kwargs"]:
param_list_.append(param_json.get(par))
if kwargs.get(par) is not None:
del kwargs[par]
return param_list_
goods_name = param.goods_name
if self.exists(goods_name): if self.exists(goods_name):
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]): args = inspect.signature(self._data[goods_name]["func"]).parameters
return await self._data[goods_name]["func"]( if args and list(args.keys())[0] != "kwargs":
**kwargs, if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
) return await self._data[goods_name]["func"](
*parse_args(args)
)
else:
return self._data[goods_name]["func"](
**kwargs,
)
else: else:
return self._data[goods_name]["func"]( if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
**kwargs, return await self._data[goods_name]["func"](
) **kwargs,
)
else:
return self._data[goods_name]["func"](
**kwargs,
)
def check_send_success_message(self, goods_name: str) -> bool: def check_send_success_message(self, goods_name: str) -> bool:
""" """
@@ -67,6 +99,18 @@ class GoodsUseFuncManager:
return self._data[goods_name]["kwargs"] return self._data[goods_name]["kwargs"]
return {} return {}
def init_model(self, goods_name: str, bot: Bot, event: GroupMessageEvent, num: int):
return self._data[goods_name]["model"](
**{
"goods_name": goods_name,
"bot": bot,
"event": event,
"user_id": event.user_id,
"group_id": event.group_id,
"num": num,
}
)
func_manager = GoodsUseFuncManager() func_manager = GoodsUseFuncManager()
@@ -83,22 +127,23 @@ async def effect(
:return: 使用是否成功 :return: 使用是否成功
""" """
# 优先使用注册的商品插件 # 优先使用注册的商品插件
try: # try:
if func_manager.exists(goods_name): if func_manager.exists(goods_name):
_kwargs = func_manager.get_kwargs(goods_name) _kwargs = func_manager.get_kwargs(goods_name)
return await func_manager.use( return await func_manager.use(
**{ func_manager.init_model(goods_name, bot, event, num),
**_kwargs, **{
"_bot": bot, **_kwargs,
"event": event, "_bot": bot,
"group_id": event.group_id, "event": event,
"user_id": event.user_id, "group_id": event.group_id,
"num": num, "user_id": event.user_id,
"goods_name": goods_name, "num": num,
} "goods_name": goods_name,
) },
except Exception as e: )
logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}") # except Exception as e:
# logger.error(f"use 商品生效函数effect 发生错误 {type(e)}:{e}")
return None return None
@@ -112,10 +157,14 @@ def register_use(goods_name: str, func, **kwargs):
if func_manager.exists(goods_name): if func_manager.exists(goods_name):
raise ValueError("该商品使用函数已被注册!") raise ValueError("该商品使用函数已被注册!")
# 发送使用成功信息 # 发送使用成功信息
if kwargs.get("send_success_msg") is None: kwargs["send_success_msg"] = kwargs.get("send_success_msg", True)
kwargs["send_success_msg"] = True kwargs["max_num_limit"] = kwargs.get("max_num_limit", 1)
kwargs["_max_num_limit"] = ( func_manager.register_use(
kwargs.get("_max_num_limit") if kwargs.get("_max_num_limit") else 1 goods_name,
**{
"func": func,
"model": create_model(f"{goods_name}_model", __base__=ShopParam, **kwargs),
"kwargs": kwargs,
},
) )
func_manager.register_use(goods_name, **{"func": func, "kwargs": kwargs})
logger.info(f"register_use 成功注册商品:{goods_name} 的使用函数") logger.info(f"register_use 成功注册商品:{goods_name} 的使用函数")
+33 -29
View File
@@ -126,35 +126,39 @@ async def xie_ai(text: str) -> str:
""" """
res = await AsyncHttpx.get(f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}") res = await AsyncHttpx.get(f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}")
content = "" content = ""
data = json.loads(res.text) try:
if data["result"] == 0: data = json.loads(res.text)
content = data["content"] if data["result"] == 0:
if "菲菲" in content: content = data["content"]
content = content.replace("菲菲", NICKNAME) if "菲菲" in content:
if "艳儿" in content: content = content.replace("菲菲", NICKNAME)
content = content.replace("艳儿", NICKNAME) if "艳儿" in content:
if "公众号" in content: content = content.replace("艳儿", NICKNAME)
content = "" if "公众号" in content:
if "{br}" in content: content = ""
content = content.replace("{br}", "\n") if "{br}" in content:
if "提示" in content: content = content.replace("{br}", "\n")
content = content[: content.find("提示")] if "提示" in content:
if "淘宝" in content or "taobao.com" in content: content = content[: content.find("提示")]
return "" if "淘宝" in content or "taobao.com" in content:
while True: return ""
r = re.search("{face:(.*)}", content) while True:
if r: r = re.search("{face:(.*)}", content)
id_ = r.group(1) if r:
content = content.replace( id_ = r.group(1)
"{" + f"face:{id_}" + "}", str(face(int(id_))) content = content.replace(
) "{" + f"face:{id_}" + "}", str(face(int(id_)))
else: )
break else:
return ( break
content return (
if not content and not Config.get_config("ai", "ALAPI_AI_CHECK") content
else await check_text(content) if not content and not Config.get_config("ai", "ALAPI_AI_CHECK")
) else await check_text(content)
)
except Exception as e:
logger.error(f"Ai xie_ai 发生错误 {type(e)}:{e}")
return ""
def hello() -> str: def hello() -> str:
+249
View File
@@ -0,0 +1,249 @@
from nonebot.adapters.onebot.v11 import (
Event,
MessageEvent,
GroupMessageEvent,
Message,
Bot,
)
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor
from utils.image_utils import BuildImage
from utils.utils import get_message_text, is_number
from nonebot.params import RegexGroup, CommandArg
from .utils import black_word_manager
from nonebot import on_command, on_message, on_regex
from configs.config import Config, NICKNAME
from nonebot.permission import SUPERUSER
from .data_source import show_black_text_image, set_user_punish
from services.log import logger
from models.ban_user import BanUser
from datetime import datetime
from utils.message_builder import image
from .model import BlackWord
from typing import Tuple, Any
__zx_plugin_name__ = "敏感词检测"
__plugin_usage__ = """
usage:
注意你的发言!
指令:
惩罚机制
""".strip()
__plugin_superuser_usage__ = """
usage:
查看和设置惩罚
Regex:^记录名单(u:\d*)?(g:\d*)?(d[=><]\d*-\d{1,2}-\d{1,2})?$
设置惩罚id需要通过 '记录名单u:xxxxxxxx' 获取
指令:
记录名单
设置惩罚 [user_id] [id] [punish_level]
示例:记录名单
示例:记录名单u:12345678
示例:设置惩罚 12345678 1 4
""".strip()
__plugin_des__ = "请注意你的发言!!"
__plugin_type__ = ("其他",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_cmd__ = ["惩罚机制", "记录名单 [_superuser]", "设置惩罚 [_superuser]"]
__plugin_settings__ = {
"cmd": ["敏感词检测"],
}
Config.add_plugin_config(
"black_word", "CYCLE_DAYS", 30, name="敏感词检测与惩罚", help_="黑名单词汇记录周期", default_value=30
)
Config.add_plugin_config(
"black_word",
"TOLERATE_COUNT",
[5, 1, 1, 1, 1],
help_="各个级别惩罚的容忍次数,依次为:1, 2, 3, 4, 5",
default_value=[5, 1, 1, 1, 1],
)
Config.add_plugin_config(
"black_word", "AUTO_PUNISH", True, help_="是否启动自动惩罚机制", default_value=True
)
# Config.add_plugin_config(
# "black_word", "IGNORE_GROUP", [], help_="退出群聊惩罚中忽略的群聊,即不会退出的群聊", default_value=[]
# )
Config.add_plugin_config(
"black_word",
"BAN_4_DURATION",
360,
help_="Union[int, List[int, int]]Ban时长(分钟),四级惩罚,可以为指定数字或指定列表区间(随机),例如 [30, 360]",
default_value=360,
)
Config.add_plugin_config(
"black_word",
"BAN_3_DURATION",
7,
help_="Union[int, List[int, int]]Ban时长(天),三级惩罚,可以为指定数字或指定列表区间(随机),例如 [7, 30]",
default_value=360,
)
Config.add_plugin_config(
"black_word",
"WARNING_RESULT",
f"请注意对{NICKNAME}的发言内容",
help_="口头警告内容",
default_value=f"请注意对{NICKNAME}的发言内容",
)
Config.add_plugin_config(
"black_word",
"AUTO_ADD_PUNISH_LEVEL",
True,
help_="自动提级机制,当周期内处罚次数大于某一特定值就提升惩罚等级",
default_value=True,
)
Config.add_plugin_config(
"black_word",
"ADD_PUNISH_LEVEL_TO_COUNT",
3,
help_="在CYCLE_DAYS周期内触发指定惩罚次数后提升惩罚等级",
default_value=3,
)
Config.add_plugin_config(
"black_word",
"ALAPI_CHECK_FLAG",
False,
help_="当未检测到已收录的敏感词时,开启ALAPI文本检测并将疑似文本发送给超级用户",
default_value=False,
)
Config.add_plugin_config(
"black_word",
"CONTAIN_BLACK_STOP_PROPAGATION",
True,
help_="当文本包含任意敏感词时,停止向下级插件传递,即不触发ai",
default_value=True,
)
message_matcher = on_message(priority=1, block=False)
set_punish = on_command("设置惩罚", priority=1, permission=SUPERUSER, block=True)
show_black = on_regex(
r"^记录名单(u:\d*)?(g:\d*)?(d[=><]\d*-\d{1,2}-\d{1,2})?$",
priority=1,
permission=SUPERUSER,
block=True,
)
show_punish = on_command("惩罚机制", aliases={"敏感词检测"}, priority=1, block=True)
# 黑名单词汇检测
@run_preprocessor
async def _(
bot: Bot,
matcher: Matcher,
event: Event,
):
if (
isinstance(event, MessageEvent)
and event.is_tome()
and matcher.plugin_name == "black_word"
and not await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
):
user_id = event.user_id
group_id = event.group_id if isinstance(event, GroupMessageEvent) else None
msg = get_message_text(event.json())
if await black_word_manager.check(user_id, group_id, msg) and Config.get_config(
"black_word", "CONTAIN_BLACK_STOP_PROPAGATION"
):
matcher.stop_propagation()
@show_black.handle()
async def _(bot: Bot, reg_group: Tuple[Any, ...] = RegexGroup()):
user_id, group_id, date = reg_group
date_type = "="
if date:
date_type = date[1]
date = date[2:]
try:
date = datetime.strptime(date, "%Y-%m-%d")
except ValueError:
await show_black.finish("日期格式错误,需要:年-月-日")
pic = await show_black_text_image(
bot,
int(user_id.split(":")[1]) if user_id else None,
int(group_id.split(":")[1]) if group_id else None,
date,
date_type,
)
await show_black.send(image(b64=pic.pic2bs4()))
@show_punish.handle()
async def _():
text = f"""
** 惩罚机制 **
惩罚前包含容忍机制,在指定周期内会容忍偶尔少次数的敏感词只会进行警告提醒
多次触发同级惩罚会使惩罚等级提高,即惩罚自动提级机制
目前公开的惩罚等级:
1级:永久ban
2级:删除好友
3级:ban指定/随机天数
4级:ban指定/随机时长
5级:警告
备注:
该功能为测试阶段,如果你有被误封情况,请联系管理员,会从数据库中提取出你的数据进行审核后判断
目前该功能暂不完善,部分情况会由管理员鉴定,请注意对真寻的发言
关于敏感词:
记住不要骂{NICKNAME}就对了!
""".strip()
max_width = 0
for m in text.split("\n"):
max_width = len(m) * 20 if len(m) * 20 > max_width else max_width
max_height = len(text.split("\n")) * 24
A = BuildImage(
max_width, max_height, font="CJGaoDeGuo.otf", font_size=24, color="#E3DBD1"
)
A.text((10, 10), text)
await show_punish.send(image(b64=A.pic2bs4()))
@set_punish.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip().split()
if (
len(msg) < 3
or not is_number(msg[0])
or not is_number(msg[1])
or not is_number(msg[2])
):
await set_punish.finish("参数错误,请查看帮助...", at_sender=True)
uid = int(msg[0])
id_ = int(msg[1])
punish_level = int(msg[2])
print(uid, id_, punish_level)
rst = await set_user_punish(uid, id_, punish_level)
await set_punish.send(rst)
logger.info(
f"USER {event.user_id} 设置惩罚 uid:{uid} id_:{id_} punish_level:{punish_level} --> {rst}"
)
+118
View File
@@ -0,0 +1,118 @@
from nonebot.adapters.onebot.v11 import Bot
from utils.image_utils import BuildImage, text2image
from services.log import logger
from typing import Optional
from datetime import datetime
from .model import BlackWord
from .utils import _get_punish, Config
async def show_black_text_image(
bot: Bot,
user: Optional[int],
group_id: Optional[int],
date: Optional[datetime],
data_type: str = "=",
) -> BuildImage:
"""
展示记录名单
:param bot: bot
:param user: 用户qq
:param group_id: 群聊
:param date: 日期
:param data_type: 日期搜索类型
:return:
"""
data = await BlackWord.get_black_data(user, group_id, date, data_type)
A = BuildImage(0, 0, color="#f9f6f2", font_size=20)
image_list = []
friend_str = await bot.get_friend_list()
id_str = ""
uname_str = ""
uid_str = ""
gid_str = ""
plant_text_str = ""
black_word_str = ""
punish_str = ""
punish_level_str = ""
create_time_str = ""
for i, x in enumerate(data):
try:
if x.group_id:
user_name = (
await bot.get_group_member_info(
group_id=x.group_id, user_id=x.user_qq
)
)["card"]
else:
user_name = [
u["nickname"] for u in friend_str if u["user_id"] == x.user_qq
][0]
except Exception as e:
logger.warning(
f"show_black_text_image 获取 USER {x.user_qq} user_name 失败 {type(e)}:{e}"
)
user_name = x.user_qq
id_str += f"{i}\n"
uname_str += f"{user_name}\n"
uid_str += f"{x.user_qq}\n"
gid_str += f"{x.group_id}\n"
plant_text = " ".join(x.plant_text.split("\n"))
if A.getsize(plant_text)[0] > 200:
plant_text = plant_text[:20] + "..."
plant_text_str += f"{plant_text}\n"
black_word_str += f"{x.black_word}\n"
punish_str += f"{x.punish}\n"
punish_level_str += f"{x.punish_level}\n"
create_time_str += f"{x.create_time.replace(microsecond=0)}\n"
_tmp_img = BuildImage(0, 0, font_size=35, font="CJGaoDeGuo.otf")
for s, type_ in [
(id_str, "Id"),
(uname_str, "昵称"),
(uid_str, "UID"),
(gid_str, "GID"),
(plant_text_str, "文本"),
(black_word_str, "检测"),
(punish_str, "惩罚"),
(punish_level_str, "等级"),
(create_time_str, "记录日期"),
]:
img = await text2image(s, color="#f9f6f2", _add_height=3.32)
w = _tmp_img.getsize(type_)[0] if _tmp_img.getsize(type_)[0] > img.w else img.w
A = BuildImage(w + 11, img.h + 50, color="#f9f6f2", font_size=35, font="CJGaoDeGuo.otf")
await A.atext((10, 10), type_)
await A.apaste(img, (0, 50))
image_list.append(A)
horizontal_line = []
w, h = 0, 0
for img in image_list:
w += img.w + 20
h = img.h if img.h > h else h
horizontal_line.append(img.w)
A = BuildImage(w, h, color="#f9f6f2")
current_w = 0
for img in image_list:
await A.apaste(img, (current_w, 0))
current_w += img.w + 20
return A
async def set_user_punish(user_id: int, id_: int, punish_level: int) -> str:
"""
设置惩罚
:param user_id: 用户id
:param id_: 记录下标
:param punish_level: 惩罚等级
"""
result = await _get_punish(punish_level, user_id)
punish = {
1: "永久ban",
2: "删除好友",
3: f"ban {result} 天",
4: f"ban {result} 分钟",
5: "口头警告"
}
if await BlackWord.set_user_punish(user_id, punish[punish_level], id_=id_):
return f"已对 USER {user_id} 进行 {punish[punish_level]} 处罚。"
else:
return "操作失败,可能未找到用户,id或敏感词"
+149
View File
@@ -0,0 +1,149 @@
from services.db_context import db
from typing import Optional, List
from datetime import datetime, timedelta
class BlackWord(db.Model):
__tablename__ = "black_word"
id = db.Column(db.Integer(), primary_key=True, autoincrement=True)
user_qq = db.Column(db.BigInteger(), nullable=False, primary_key=True)
group_id = db.Column(db.BigInteger())
plant_text = db.Column(db.String())
black_word = db.Column(db.String())
punish = db.Column(db.String(), default="")
punish_level = db.Column(db.Integer())
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
@classmethod
async def add_user_black_word(
cls,
user_qq: int,
group_id: Optional[int],
black_word: str,
plant_text: str,
punish_level: int,
):
"""
说明:
添加用户发送的敏感词
参数:
:param user_qq: 用户id
:param group_id: 群号
:param black_word: 黑名单词汇
:param plant_text: 消息文本
:param punish_level: 惩罚等级
"""
await cls.create(
user_qq=user_qq,
group_id=group_id,
plant_text=plant_text,
black_word=black_word,
punish_level=punish_level,
create_time=datetime.now(),
)
@classmethod
async def set_user_punish(
cls,
user_qq: int,
punish: str,
black_word: Optional[str] = None,
id_: Optional[int] = None,
) -> bool:
"""
说明:
设置处罚
参数:
:param user_qq: 用户id
:param punish: 处罚
:param black_word: 黑名单词汇
:param id_: 记录下标
"""
user = None
if (not black_word and not id_) or not punish:
return False
query = cls.query.where(cls.user_qq == user_qq).with_for_update()
if black_word:
user = await query.where(cls.black_word == black_word).order_by(cls.id.desc()).gino.first()
elif id_:
user_list = await query.gino.all()
print(len(user_list))
if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)):
return False
user = user_list[id_]
if not user:
return False
await user.update(punish=cls.punish + punish + " ").apply()
return True
@classmethod
async def get_user_count(
cls, user_qq: int, days: int = 7, punish_level: Optional[int] = None
) -> int:
"""
说明:
获取用户规定周期内的犯事次数
参数:
:param user_qq: 用户qq
:param days: 周期天数
:param punish_level: 惩罚等级
"""
setattr(BlackWord, "count", db.func.count(cls.id).label("count"))
query = cls.select("count").where(
(cls.user_qq == user_qq)
& (cls.punish_level != -1)
& (cls.create_time > datetime.now() - timedelta(days=days))
)
if punish_level is not None:
query = query.where(cls.punish_level == punish_level)
return (await query.gino.first())[0]
@classmethod
async def get_user_punish_level(cls, user_qq: int, days: int = 7) -> Optional[int]:
"""
说明:
获取用户最近一次的惩罚记录等级
参数:
:param user_qq: 用户qq
:param days: 周期天数
"""
if (
query := await cls.query.where(cls.user_qq == user_qq)
.where(cls.create_time > datetime.now() - timedelta(days=days))
.order_by(cls.id.desc())
.gino.first()
):
return query.punish_level
return None
@classmethod
async def get_black_data(
cls,
user_qq: Optional[int],
group_id: Optional[int],
date: Optional[datetime],
date_type: str = "=",
) -> List["BlackWord"]:
"""
说明:
通过指定条件查询数据
参数:
:param user_qq: 用户qq
:param group_id: 群号
:param date: 日期
:param date_type: 日期查询类型
"""
query = cls.query
if user_qq:
query = query.where(cls.user_qq == user_qq)
if group_id:
query = query.where(cls.group_id == group_id)
if date:
if date_type == "=":
query = query.where(cls.create_time == date)
elif date_type == ">":
query = query.where(cls.create_time > date)
elif date_type == "<":
query = query.where(cls.create_time < date)
return await query.gino.all()
+324
View File
@@ -0,0 +1,324 @@
from utils.utils import cn2py, get_bot
from configs.path_config import DATA_PATH
from typing import Optional, Union, Tuple
from .model import BlackWord
from configs.config import Config
from pathlib import Path
from services.log import logger
from models.ban_user import BanUser
from nonebot.adapters.onebot.v11.exception import ActionFailed
from models.group_member_info import GroupInfoUser
from utils.http_utils import AsyncHttpx
import random
try:
import ujson as json
except ModuleNotFoundError:
import json
class BlackWordManager:
"""
敏感词管理( 拒绝恶意
"""
def __init__(self, word_file: Path, py_file: Path):
self._word_list = {
"1": [],
"2": [],
"3": [],
"4": ["sb", "nmsl", "mdzz", "2b", "jb", "操", "废物", "憨憨", "cnm", "rnm"],
"5": [],
}
self._py_list = {
"1": [],
"2": [],
"3": [],
"4": [
"shabi",
"wocaonima",
"sima",
"sabi",
"zhizhang",
"naocan",
"caonima",
"rinima",
"simadongxi",
"simawanyi",
"hanbi",
"hanpi",
"laji",
"fw"
],
"5": [],
}
word_file.parent.mkdir(parents=True, exist_ok=True)
if word_file.exists():
# 清空默认配置
with open(word_file, "r", encoding="utf8") as f:
self._word_list = json.load(f)
else:
with open(word_file, "w", encoding="utf8") as f:
json.dump(
self._word_list,
f,
ensure_ascii=False,
indent=4,
)
if py_file.exists():
# 清空默认配置
with open(py_file, "r", encoding="utf8") as f:
self._py_list = json.load(f)
else:
with open(py_file, "w", encoding="utf8") as f:
json.dump(
self._py_list,
f,
ensure_ascii=False,
indent=4,
)
async def check(
self, user_id: int, group_id: Optional[int], message: str
) -> Optional[Union[str, bool]]:
"""
检查是否包含黑名单词汇
:param user_id: 用户id
:param group_id: 群号
:param message: 消息
"""
print(user_id, group_id, message)
if data := self._check(message):
print(data)
if data[0]:
await _add_user_black_word(
user_id, group_id, data[0], message, int(data[1])
)
return True
if Config.get_config(
"black_word", "ALAPI_CHECK_FLAG"
) and not await check_text(message):
await send_msg(
0, None, f"USER {user_id} GROUP {group_id} ALAPI 疑似检测:{message}"
)
return False
def _check(self, message: str) -> Tuple[Optional[str], int]:
"""
检测文本是否违规
:param message: 检测消息
"""
# 移除空格
message = message.replace(" ", "")
py_msg = cn2py(message).lower()
# 完全匹配
for x in [self._word_list, self._py_list]:
for level in x:
if message in x[level] or py_msg in x[level]:
return message if message in x[level] else py_msg, level
# 模糊匹配
for x in [self._word_list, self._py_list]:
for level in x:
for m in x[level]:
if m in message or m in py_msg:
return m, -1
return None, 0
async def _add_user_black_word(
user_id: int,
group_id: Optional[int],
black_word: str,
message: str,
punish_level: int,
):
"""
添加敏感词数据
:param user_id: 用户id
:param group_id: 群号
:param black_word: 触发的黑名单词汇
:param message: 原始文本
:param punish_level: 惩罚等级
"""
cycle_days = Config.get_config("black_word", "CYCLE_DAYS") or 7
user_count = await BlackWord.get_user_count(user_id, cycle_days, punish_level)
# 周期内超过次数直接提升惩罚
if Config.get_config(
"black_word", "AUTO_ADD_PUNISH_LEVEL"
) and user_count > Config.get_config("black_word", "ADD_PUNISH_LEVEL_TO_COUNT"):
punish_level -= 1
await BlackWord.add_user_black_word(
user_id, group_id, black_word, message, punish_level
)
logger.info(
f"已将 USER {user_id} GROUP {group_id} 添加至黑名单词汇记录 Black_word:{black_word} Plant_text:{message}"
)
# 自动惩罚
if Config.get_config("black_word", "AUTO_PUNISH") and punish_level != -1:
await _punish_handle(user_id, group_id, punish_level, black_word)
async def _punish_handle(
user_id: int, group_id: Optional[int], punish_level: int, black_word: str
):
"""
惩罚措施,级别越低惩罚越严
:param user_id: 用户id
:param group_id: 群号
:param black_word: 触发的黑名单词汇
"""
logger.info(f"BlackWord USER {user_id} 触发 {punish_level} 级惩罚...")
# 周期天数
cycle_days = Config.get_config("black_word", "CYCLE_DAYS") or 7
# 用户周期内触发punish_level级惩罚的次数
user_count = await BlackWord.get_user_count(user_id, cycle_days, punish_level)
# 获取最近一次的惩罚等级,将在此基础上增加
punish_level = await BlackWord.get_user_punish_level(user_id, cycle_days) or punish_level
# 容忍次数:List[int]
tolerate_count = Config.get_config("black_word", "TOLERATE_COUNT")
if not tolerate_count or len(tolerate_count) < 5:
tolerate_count = [5, 2, 2, 2, 2]
if punish_level == 1 and user_count > tolerate_count[punish_level - 1]:
# 永久ban
await _get_punish(1, user_id, group_id)
await BlackWord.set_user_punish(user_id, "永久ban 删除好友", black_word)
elif punish_level == 2 and user_count > tolerate_count[punish_level - 1]:
# 删除好友
await _get_punish(2, user_id, group_id)
await BlackWord.set_user_punish(user_id, "删除好友", black_word)
elif punish_level == 3 and user_count > tolerate_count[punish_level - 1]:
# 永久ban
ban_day = await _get_punish(3, user_id, group_id)
await BlackWord.set_user_punish(user_id, f"ban {ban_day} 天", black_word)
elif punish_level == 4 and user_count > tolerate_count[punish_level - 1]:
# ban指定时长
ban_time = await _get_punish(4, user_id, group_id)
await BlackWord.set_user_punish(user_id, f"ban {ban_time} 分钟", black_word)
elif punish_level == 5 and user_count > tolerate_count[punish_level - 1]:
# 口头警告
warning_result = await _get_punish(5, user_id, group_id)
await BlackWord.set_user_punish(user_id, f"口头警告:{warning_result}", black_word)
else:
await BlackWord.set_user_punish(user_id, f"提示!", black_word)
await send_msg(
user_id,
group_id,
f"BlackWordChecker:该条发言已被记录,目前你在{cycle_days}天内的发表{punish_level}级"
f"言论记录次数为:{user_count}次,请注意你的发言\n"
f"* 如果你不清楚惩罚机制,请发送“惩罚机制” *",
)
async def _get_punish(
id_: int, user_id: int, group_id: Optional[int] = None
) -> Optional[Union[int, str]]:
"""
通过id_获取惩罚
:param id_: id
:param user_id: 用户id
:param group_id: 群号
"""
bot = get_bot()
# 忽略的群聊
# _ignore_group = Config.get_config("black_word", "IGNORE_GROUP")
# 处罚 id 4 ban 时间:int,List[int]
ban_3_duration = Config.get_config("black_word", "BAN_3_DURATION")
# 处罚 id 4 ban 时间:int,List[int]
ban_4_duration = Config.get_config("black_word", "BAN_4_DURATION")
# 口头警告内容
warning_result = Config.get_config("black_word", "WARNING_RESULT")
try:
uname = (await GroupInfoUser.get_member_info(user_id, group_id)).user_name
except AttributeError:
uname = user_id
# 永久ban
if id_ == 1:
if str(user_id) not in bot.config.superusers:
await BanUser.ban(user_id, 10, 99999999)
await send_msg(user_id, group_id, f"BlackWordChecker 永久ban USER {uname}({user_id})")
logger.info(f"BlackWord 永久封禁 USER {user_id}...")
# 删除好友(有的话
elif id_ == 2:
if str(user_id) not in bot.config.superusers:
try:
await bot.delete_friend(user_id=user_id)
await send_msg(
user_id, group_id, f"BlackWordChecker 删除好友 USER {uname}({user_id})"
)
logger.info(f"BlackWord 删除好友 {user_id}...")
except ActionFailed:
pass
# 封禁用户指定时间,默认7天
elif id_ == 3:
if isinstance(ban_3_duration, list):
ban_3_duration = random.randint(ban_3_duration[0], ban_3_duration[1])
await BanUser.ban(user_id, 9, ban_4_duration * 60 * 60 * 24)
await send_msg(
user_id,
group_id,
f"BlackWordChecker 对用户 USER {uname}({user_id}) 进行封禁 {ban_3_duration} 天处罚。",
)
logger.info(f"BlackWord 封禁 USER {uname}({user_id}) {ban_3_duration} 天...")
return ban_3_duration
# 封禁用户指定时间,默认360分钟
elif id_ == 4:
if isinstance(ban_4_duration, list):
ban_4_duration = random.randint(ban_4_duration[0], ban_4_duration[1])
await BanUser.ban(user_id, 9, ban_4_duration * 60)
await send_msg(
user_id,
group_id,
f"BlackWordChecker 对用户 USER {uname}({user_id}) 进行封禁 {ban_4_duration} 分钟处罚。",
)
logger.info(f"BlackWord 封禁 USER {uname}({user_id}) {ban_4_duration} 分钟...")
return ban_4_duration
# 口头警告
elif id_ == 5:
if group_id:
await bot.send_group_msg(group_id=group_id, message=warning_result)
else:
await bot.send_private_msg(user_id=user_id, message=warning_result)
logger.info(f"BlackWord 口头警告 USER {user_id}")
return warning_result
return None
async def send_msg(user_id: int, group_id: Optional[int], message: str):
"""
发送消息
:param user_id: user_id
:param group_id: group_id
:param message: message
"""
bot = get_bot()
if not user_id:
user_id = int(list(bot.config.superusers)[0])
if group_id:
await bot.send_group_msg(group_id=group_id, message=message)
else:
await bot.send_private_msg(user_id=user_id, message=message)
async def check_text(text: str) -> bool:
"""
ALAPI文本检测,检测输入违规
:param text: 回复
"""
if not Config.get_config("alapi", "ALAPI_TOKEN"):
return True
params = {"token": Config.get_config("alapi", "ALAPI_TOKEN"), "text": text}
try:
data = (
await AsyncHttpx.get(
"https://v2.alapi.cn/api/censor/text", timeout=4, params=params
)
).json()
if data["code"] == 200:
return data["data"]["conclusion_type"] == 2
except Exception as e:
logger.error(f"检测违规文本错误...{type(e)}:{e}")
return True
black_word_manager = BlackWordManager(DATA_PATH / "black_word" / "black_word.json", DATA_PATH / "black_word" / "black_py.json")
-34
View File
@@ -1,34 +0,0 @@
from nonebot import on_message
from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from .data_source import cancel_all_notice, save_data, get_data, set_data_value
from services.log import logger
import time
__zx_plugin_name__ = "群聊最后聊天时间记录 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
last_chat = on_message(priority=1, block=False, permission=GROUP)
@last_chat.handle()
async def _(event: GroupMessageEvent):
time_data = await get_data()
set_data_value(event.group_id, time.time())
if event.group_id in time_data["_group"]:
time_data["_group"].remove(event.group_id)
set_data_value("_group", time_data["_group"])
for key in time_data.keys():
if key not in ["check_time", "_group"]:
if key not in time_data["_group"]:
if time.time() - time_data[key] > 60 * 60 * 36:
await cancel_all_notice(key)
time_data["_group"].append(key)
set_data_value("_group", time_data["_group"])
logger.info(f"GROUP {event.group_id} 因群内发言时间大于36小时被取消全部通知")
if time.time() - time_data["check_time"] > 60 * 60 * 1:
set_data_value("check_time", time.time())
save_data()
-67
View File
@@ -1,67 +0,0 @@
from configs.path_config import DATA_PATH
from utils.utils import get_bot
from datetime import datetime
import time
from services.log import logger
from utils.manager import group_manager
try:
import ujson as json
except ModuleNotFoundError:
import json
time_data = {}
async def init():
global time_data
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
data = read_data("group_last_chat_time.json")
for g in gl:
if not data.get(g):
time_data[g] = time.time()
if not time_data.get("check_time"):
time_data["check_time"] = time.time()
if not time_data.get("_group"):
time_data["_group"] = []
save_data()
return time_data
def read_data(file_name: str):
try:
with open(DATA_PATH / file_name, "r", encoding="utf8") as f:
return json.load(f)
except (ValueError, FileNotFoundError):
return {}
def save_data():
with open(DATA_PATH / "group_last_chat_time.json", "w") as f:
json.dump(time_data, f, indent=4)
logger.info(
f'自动存储 group_last_chat_time.json 时间:{str(datetime.now()).split(".")[0]}'
)
# 取消全部通知
async def cancel_all_notice(group_id):
group_id = int(group_id)
for command in group_manager.get_task_data():
if await group_manager.check_group_task_status(group_id, command):
await group_manager.close_group_task(group_id, command)
logger.info(f"关闭了 {group_id} 群的全部通知")
async def get_data():
global time_data
if not time_data:
time_data = await init()
return time_data
def set_data_value(key, value):
global time_data
time_data[key] = value
@@ -139,7 +139,7 @@ async def update_setu_img(flag: bool = False):
f"--> /{path}/{image.local_id}.jpg" f"--> /{path}/{image.local_id}.jpg"
) )
os.rename( os.rename(
TEMP_PATH / f"/{image.local_id}.jpg", TEMP_PATH / f"{image.local_id}.jpg",
path / f"{image.local_id}.jpg", path / f"{image.local_id}.jpg",
) )
except FileNotFoundError: except FileNotFoundError:
+7 -5
View File
@@ -1,3 +1,5 @@
from typing import Tuple, Any
from .group_user_checkin import ( from .group_user_checkin import (
group_user_check_in, group_user_check_in,
group_user_check, group_user_check,
@@ -8,9 +10,9 @@ from .group_user_checkin import (
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP from nonebot.adapters.onebot.v11.permission import GROUP
from utils.message_builder import image from utils.message_builder import image
from nonebot import on_command from nonebot import on_command, on_regex
from utils.utils import scheduler from utils.utils import scheduler
from nonebot.params import CommandArg from nonebot.params import CommandArg, RegexGroup
from pathlib import Path from pathlib import Path
from configs.path_config import DATA_PATH from configs.path_config import DATA_PATH
from services.log import logger from services.log import logger
@@ -68,7 +70,7 @@ except (FileNotFoundError, ValueError, TypeError):
data = {"0": []} data = {"0": []}
sign = on_command("签到", priority=5, permission=GROUP, block=True) sign = on_regex("^签到(all)?$", priority=5, permission=GROUP, block=True)
my_sign = on_command( my_sign = on_command(
cmd="我的签到", aliases={"好感度"}, priority=5, permission=GROUP, block=True cmd="我的签到", aliases={"好感度"}, priority=5, permission=GROUP, block=True
) )
@@ -85,13 +87,13 @@ total_sign_rank = on_command(
@sign.handle() @sign.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()): async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
nickname = event.sender.card or event.sender.nickname nickname = event.sender.card or event.sender.nickname
await sign.send( await sign.send(
await group_user_check_in(nickname, event.user_id, event.group_id), await group_user_check_in(nickname, event.user_id, event.group_id),
at_sender=True, at_sender=True,
) )
if arg.extract_plain_text().strip() == "all": if reg_group[0]:
await check_in_all(nickname, event.user_id) await check_in_all(nickname, event.user_id)
View File
+110
View File
@@ -0,0 +1,110 @@
from typing import Callable, Union, Tuple
from nonebot.plugin import require
use = require("use")
shop = require("shop_handle")
class ShopRegister(dict):
def __init__(self, *args, **kwargs):
super(ShopRegister, self).__init__(*args, **kwargs)
self._data = {}
self._flag = True
def register(
self,
name: Tuple[str, ...],
price: Tuple[float, ...],
des: Tuple[str, ...],
load_status: Tuple[bool, ...],
**kwargs,
):
def add_register_item(func: Callable):
if name in self._data.keys():
raise ValueError("该商品已注册,请替换其他名称!")
for n, p, d, s in zip(name, price, des, load_status):
if s:
_temp_kwargs = {}
for key, value in kwargs.items():
if key.startswith(f"{n}_"):
_temp_kwargs[key.split("_", maxsplit=1)[-1]] = value
self._data[n] = {
"price": p,
"des": d,
"func": func,
"kwargs": _temp_kwargs,
}
return func
return lambda func: add_register_item(func)
async def load_register(self):
# 统一进行注册
if self._flag:
# 只进行一次注册
self._flag = False
for name in self._data.keys():
await shop.register_goods(
name, self._data[name]["price"], self._data[name]["des"]
)
use.register_use(
name, self._data[name]["func"], **self._data[name]["kwargs"]
)
def __call__(
self,
name: Union[str, Tuple[str, ...]],
price: Union[float, Tuple[float, ...]],
des: Union[str, Tuple[str, ...]],
load_status: Union[bool, Tuple[bool, ...]] = True,
**kwargs,
):
_tuple_list = []
_current_len = -1
for x in [name, price, des, load_status]:
if isinstance(x, tuple):
if _current_len == -1:
_current_len = len(x)
if _current_len != len(x):
raise ValueError(f"注册商品 {name} 中 name,price,des,load_status 数量不符!")
_current_len = _current_len if _current_len > -1 else 1
_name = name if isinstance(name, tuple) else tuple(name)
_price = (
price
if isinstance(price, tuple)
else tuple([price for _ in range(_current_len)])
)
_des = (
des if isinstance(des, tuple) else tuple([des for _ in range(_current_len)])
)
_load_status = (
load_status
if isinstance(load_status, tuple)
else tuple([load_status for _ in range(_current_len)])
)
return self.register(_name, _price, _des, _load_status, **kwargs)
def __setitem__(self, key, value):
self._data[key] = value
def __getitem__(self, key):
return self._data[key]
def __contains__(self, key):
return key in self._data
def __str__(self):
return str(self._data)
def keys(self):
return self._data.keys()
def values(self):
return self._data.values()
def items(self):
return self._data.items()
shop_register = ShopRegister()
View File
+5 -3
View File
@@ -1336,6 +1336,7 @@ async def text2image(
font: str = "CJGaoDeGuo.otf", font: str = "CJGaoDeGuo.otf",
font_color: Union[str, Tuple[int, int, int]] = "black", font_color: Union[str, Tuple[int, int, int]] = "black",
padding: Union[int, Tuple[int, int, int, int]] = 0, padding: Union[int, Tuple[int, int, int, int]] = 0,
_add_height: float = 0,
) -> BuildImage: ) -> BuildImage:
""" """
说明: 说明:
@@ -1358,6 +1359,7 @@ async def text2image(
:param font: 普通字体 :param font: 普通字体
:param font_color: 普通字体颜色 :param font_color: 普通字体颜色
:param padding: 文本外边距,元组类型时为 (上,左,下,右) :param padding: 文本外边距,元组类型时为 (上,左,下,右)
:param _add_height: 由于get_size无法返回正确的高度,采用手动方式额外添加高度
""" """
pw = ph = top_padding = left_padding = 0 pw = ph = top_padding = left_padding = 0
if padding: if padding:
@@ -1489,17 +1491,17 @@ async def text2image(
else: else:
width = 0 width = 0
height = 0 height = 0
_tmp = BuildImage(0, 0, font_size=font_size) _tmp = BuildImage(0, 0, font=font, font_size=font_size)
for x in text.split("\n"): for x in text.split("\n"):
x = x if x.strip() else "正" x = x if x.strip() else "正"
w, h = _tmp.getsize(x) w, h = _tmp.getsize(x)
height += h height += h + _add_height
width = width if width > w else w width = width if width > w else w
width += pw width += pw
height += ph height += ph
A = BuildImage( A = BuildImage(
width + left_padding, width + left_padding,
height + top_padding, height + top_padding + 2,
font_size=font_size, font_size=font_size,
color=color, color=color,
font=font, font=font,
+14
View File
@@ -0,0 +1,14 @@
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
from pydantic import BaseModel, create_model
from typing import Any
class ShopParam(BaseModel):
goods_name: str
user_id: int
group_id: int
bot: Any
event: MessageEvent
num: int # 道具单次使用数量
send_success_msg: bool = True # 是否发送使用成功信息
max_num_limit: int = 1 # 单次使用最大次数