refactor🎨: 重构红包功能

This commit is contained in:
HibiKier
2023-08-28 13:30:17 +08:00
parent 0a4df8296e
commit 81ddbc30f4
8 changed files with 671 additions and 335 deletions
+213 -257
View File
@@ -1,6 +1,8 @@
import random
import re
import time
from datetime import datetime, timedelta
from typing import Dict, List, Optional
from apscheduler.jobstores.base import JobLookupError
from nonebot import on_command, on_notice
@@ -21,15 +23,16 @@ from nonebot.rule import to_me
from configs.config import NICKNAME
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.message_builder import image
from utils.depends import AtList, GetConfig
from utils.message_builder import at, image
from utils.utils import is_number, scheduler
from .config import FESTIVE_KEY, GroupRedBag, RedBag
from .data_source import (
build_open_result_image,
check_gold,
generate_open_redbag_pic,
generate_send_redbag_pic,
open_redbag,
return_gold,
end_festive_red_bag,
random_red_bag_background,
)
__zx_plugin_name__ = "金币红包"
@@ -37,7 +40,7 @@ __plugin_usage__ = """
usage:
在群内发送指定金额的红包,拼手气项目
指令:
塞红包 [金币数] ?[红包数=5]: 塞入红包
塞红包 [金币数] ?[红包数=5] ?[at指定人]: 塞入红包
开/抢/*戳一戳*: 打开红包
退回: 退回未开完的红包,必须在一分钟后使用
示例:塞红包 1000
@@ -51,7 +54,7 @@ usage:
""".strip()
__plugin_des__ = "运气项目又来了"
__plugin_cmd__ = [
"塞红包 [金币数] ?[红包数=5]",
"塞红包 [金币数] ?[红包数=5] ?[at指定人]",
"开/抢",
"退回",
"节日红包 [金额] [数量] ?[祝福语] ?[指定群] [_superuser]",
@@ -64,14 +67,35 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["金币红包", "塞红包"],
}
__plugin_resources__ = {"prts": IMAGE_PATH}
__plugin_cd_limit__ = {"rst": "急什么急什么,待会再发!"}
__plugin_configs__ = {
"DEFAULT_TIMEOUT": {
"value": 600,
"help": "普通红包默认超时时间",
"default_value": 600,
"type": int,
},
"DEFAULT_INTERVAL": {
"value": 60,
"help": "用户发送普通红包最小间隔时间",
"default_value": 60,
"type": int,
},
"RANK_NUM": {
"value": 10,
"help": "结算排行显示前N位",
"default_value": 10,
"type": int,
},
}
# __plugin_resources__ = {"prts": IMAGE_PATH}
async def rule(event: GroupMessageEvent) -> bool:
return check_on_gold_red(event)
gold_redbag = on_command(
gold_red_bag = on_command(
"塞红包", aliases={"金币红包"}, priority=5, block=True, permission=GROUP
)
@@ -87,167 +111,197 @@ festive_redbag = on_command(
"节日红包", priority=5, block=True, permission=SUPERUSER, rule=to_me()
)
redbag_data = {}
GROUP_DATA: Dict[int, GroupRedBag] = {}
festive_redbag_data = {}
PATTERN = r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~,。;‘、"""
# 阻断其他poke
@run_preprocessor
# @run_preprocessor
# async def _(
# matcher: Matcher,
# event: PokeNotifyEvent,
# ):
# try:
# if matcher.type == "notice" and event.self_id == event.target_id:
# flag = check_on_gold_red(event)
# if flag:
# if matcher.plugin_name == "poke":
# raise IgnoredException("目前正在抢红包...")
# else:
# if matcher.plugin_name == "gold_red_bag":
# raise IgnoredException("目前没有红包...")
# except AttributeError:
# pass
@gold_red_bag.handle()
async def _(
matcher: Matcher,
event: PokeNotifyEvent,
bot: Bot,
event: GroupMessageEvent,
arg: Message = CommandArg(),
at_list: List[int] = AtList(),
default_interval: int = GetConfig(config="DEFAULT_INTERVAL"),
):
try:
if matcher.type == "notice" and event.self_id == event.target_id:
flag = check_on_gold_red(event)
if flag:
if matcher.plugin_name == "poke":
raise IgnoredException("目前正在抢红包...")
else:
if matcher.plugin_name == "gold_redbag":
raise IgnoredException("目前没有红包...")
except AttributeError:
pass
@gold_redbag.handle()
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
global redbag_data, festive_redbag_data
try:
if time.time() - redbag_data[event.group_id]["time"] > 60:
amount = (
redbag_data[event.group_id]["amount"]
- redbag_data[event.group_id]["open_amount"]
)
await return_gold(
redbag_data[event.group_id]["user_id"], str(event.group_id), amount
)
await gold_redbag.send(
f'{redbag_data[event.group_id]["nickname"]}的红包过时未开完,退还{amount}金币...'
)
redbag_data[event.group_id] = {}
else:
await gold_redbag.finish(
f'目前 {redbag_data[event.group_id]["nickname"]} 的红包还没有开完噢,'
f'还剩下 {len(redbag_data[event.group_id]["redbag"])} 个红包!'
f'(或等待{str(60 - time.time() + redbag_data[event.group_id]["time"])[:2]}秒红包过时)'
)
except KeyError:
pass
msg = arg.extract_plain_text().strip()
msg = msg.split()
group_red_bag: Optional[GroupRedBag] = GROUP_DATA.get(event.group_id)
if not group_red_bag:
group_red_bag = GroupRedBag(event.group_id)
GROUP_DATA[event.group_id] = group_red_bag
# 剩余过期时间
time_remaining = group_red_bag.check_timeout(event.user_id)
if time_remaining != -1:
# 判断用户红包是否存在且是否过时覆盖
if user_red_bag := group_red_bag.get_user_red_bag(event.user_id):
now = time.time()
if now < user_red_bag.start_time + default_interval:
await gold_red_bag.finish(
f"你的红包还没消化完捏...还剩下 {user_red_bag.num - len(user_red_bag.open_user)} 个! 请等待红包领取完毕..."
f"(或等待{time_remaining}秒红包cd)"
)
msg = arg.extract_plain_text().strip().split()
if not msg:
await gold_red_bag.finish("不塞钱发什么红包!")
amount = msg[0]
if len(msg) == 1:
flag, amount = await check_gold(str(event.user_id), str(event.group_id), msg[0])
flag, tip = await check_gold(str(event.user_id), str(event.group_id), amount)
if not flag:
await gold_redbag.finish(str(amount))
await gold_red_bag.finish(tip, at_sender=True)
num = 5
else:
amount = msg[0]
num = msg[1]
if not is_number(num) or int(num) < 1:
await gold_redbag.finish("红包个数给我输正确啊!", at_sender=True)
flag, amount = await check_gold(str(event.user_id), str(event.group_id), amount)
await gold_red_bag.finish("红包个数给我输正确啊!", at_sender=True)
flag, tip = await check_gold(str(event.user_id), str(event.group_id), amount)
if not flag:
await gold_redbag.finish(str(amount), at_sender=True)
await gold_red_bag.finish(tip, at_sender=True)
group_member_num = (await bot.get_group_info(group_id=event.group_id))[
"member_count"
]
num = int(num)
if num > group_member_num:
await gold_redbag.send("你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...")
await gold_red_bag.send("你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...")
num = group_member_num
nickname = event.sender.card or event.sender.nickname
flag, result = init_redbag(
await group_red_bag.add_red_bag(
f"{nickname}的红包",
int(amount),
1 if at_list else num,
nickname or "",
str(event.user_id),
str(event.group_id),
nickname or str(event.user_id),
amount,
num,
int(bot.self_id),
assigner=str(at_list[0]) if at_list else None,
)
await gold_red_bag.send(
f"{nickname}发起了金币红包\n金额: {amount}\n数量: {num}\n"
+ image(await random_red_bag_background(event.user_id))
)
if not flag:
await gold_redbag.finish(result, at_sender=True)
else:
await gold_redbag.send(
f"{nickname}发起了金币红包\n金额:{amount}\n数量:{num}\n"
+ image(
b64=await generate_send_redbag_pic(
redbag_data[str(event.group_id)]["user_id"]
)
)
)
logger.info(f"塞入 {num} 个红包,共 {amount} 金币", "金币红包", event.user_id, event.group_id)
@open_.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
global redbag_data, festive_redbag_data
msg = arg.extract_plain_text().strip()
msg = (
msg.replace("!", "")
.replace("!", "")
.replace(",", "")
.replace(",", "")
.replace(".", "")
.replace("。", "")
)
if msg:
async def _(
event: GroupMessageEvent,
arg: Message = CommandArg(),
rank_num: int = GetConfig(config="RANK_NUM"),
):
if msg := arg.extract_plain_text().strip():
msg = re.sub(PATTERN, "", msg)
if "红包" not in msg:
return
try:
await open_.send(
image(b64=await get_redbag_img(str(event.user_id), str(event.group_id))),
at_sender=True,
)
except KeyError:
await open_.finish("真贪心,明明已经开过这个红包了的说...", at_sender=True)
group_red_bag: Optional[GroupRedBag] = GROUP_DATA.get(event.group_id)
if group_red_bag:
open_data, settlement_list = await group_red_bag.open(event.user_id)
send_msg = ""
for _, item in open_data.items():
amount, red_bag = item
result_image = await build_open_result_image(red_bag, event.user_id, amount)
send_msg += (
f"开启了 {red_bag.promoter} 的红包, 获取 {amount} 个金币\n"
+ image(result_image)
+ "\n"
)
logger.info(
f"抢到了 {red_bag.promoter}({red_bag.promoter_id}) 的红包,获取了{amount}个金币",
"开红包",
event.user_id,
event.group_id,
)
send_msg = send_msg[:-1] if send_msg else "没有红包给你开!"
await open_.send(send_msg, at_sender=True)
if settlement_list:
for red_bag in settlement_list:
await open_.send(
f"{red_bag.name}已结算\n"
+ image(await red_bag.build_amount_rank(rank_num))
)
@poke_.handle()
async def _poke_(event: PokeNotifyEvent):
global redbag_data, festive_redbag_data
if event.self_id == event.target_id:
flag = check_on_gold_red(event)
if not flag:
return
await poke_.send(
image(b64=await get_redbag_img(str(event.user_id), str(event.group_id))),
at_sender=True,
)
# @poke_.handle()
# async def _poke_(event: PokeNotifyEvent):
# group_id = getattr(event, "group_id", None)
# if event.self_id == event.target_id and group_id:
# is_open = check_on_gold_red(event)
# if not is_open:
# return
# group_red_bag: Optional[GroupRedBag] = GROUP_DATA.get(group_id)
# if group_red_bag:
# open_data, settlement_list = await group_red_bag.open(event.user_id)
# send_msg = ""
# for _, item in open_data.items():
# amount, red_bag = item
# result_image = await build_open_result_image(
# red_bag, event.user_id, amount
# )
# send_msg += (
# f"开启了 {red_bag.promoter} 的红包, 获取 {amount} 个金币\n"
# + image(result_image)
# + "\n"
# )
# logger.info(
# f"抢到了 {red_bag.promoter}({red_bag.promoter_id}) 的红包,获取了{amount}个金币",
# "开红包",
# event.user_id,
# event.group_id,
# )
# if send_msg:
# await open_.send(send_msg, at_sender=True)
# if settlement_list:
# for red_bag in settlement_list:
# await open_.send(
# f"{red_bag.name}已结算\n"
# + image(await red_bag.build_amount_rank())
# )
@return_.handle()
async def _(event: GroupMessageEvent):
global redbag_data
try:
if redbag_data[event.group_id]["user_id"] != event.user_id:
await return_.finish("不是你的红包你退回什么!", at_sender=True)
if time.time() - redbag_data[event.group_id]["time"] <= 60:
await return_.finish(
f'你的红包还没有过时,在 {str(60 - time.time() + redbag_data[event.group_id]["time"])[:2]} '
f"秒后可以退回..",
at_sender=True,
)
await return_gold(
str(event.user_id),
str(event.group_id),
redbag_data[event.group_id]["amount"]
- redbag_data[event.group_id]["open_amount"],
)
await return_.send(
f"已成功退还了 "
f"{redbag_data[event.group_id]['amount'] - redbag_data[event.group_id]['open_amount']} "
f"金币",
at_sender=True,
)
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 退回了"
f"红包 {redbag_data[event.group_id]['amount'] - redbag_data[event.group_id]['open_amount']} 金币"
)
redbag_data[event.group_id] = {}
except KeyError:
await return_.finish("目前没有红包可以退回...", at_sender=True)
async def _(
event: GroupMessageEvent,
default_interval: int = GetConfig(config="DEFAULT_INTERVAL"),
rank_num: int = GetConfig(config="RANK_NUM"),
):
group_red_bag: GroupRedBag = GROUP_DATA[event.group_id]
if group_red_bag:
if user_red_bag := group_red_bag.get_user_red_bag(event.user_id):
now = time.time()
if now - user_red_bag.start_time < default_interval:
await return_.finish(
f"你的红包还没有过时, 在 {int(default_interval - now + user_red_bag.start_time)} "
f"秒后可以退回...",
at_sender=True,
)
user_red_bag = group_red_bag.get_user_red_bag(event.user_id)
if user_red_bag and (
return_amount := await group_red_bag.settlement(event.user_id)
):
logger.info(
f"退回了红包 {return_amount} 金币", "红包退回", event.user_id, event.group_id
)
await return_.send(
f"已成功退还了 "
f"{return_amount} 金币\n"
+ image(await user_red_bag.build_amount_rank(rank_num)),
at_sender=True,
)
await return_.send("目前没有红包可以退回...", at_sender=True)
@festive_redbag.handle()
@@ -280,138 +334,40 @@ async def _(bot: Bot, arg: Message = CommandArg()):
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
group_red_bag: Optional[GroupRedBag] = GROUP_DATA.get(g)
if not group_red_bag:
group_red_bag = GroupRedBag(g)
GROUP_DATA[g] = group_red_bag
try:
scheduler.remove_job(f"festive_redbag_{g}")
await end_festive_redbag(bot, g)
scheduler.remove_job(f"{FESTIVE_KEY}_{g}")
await end_festive_red_bag(bot, group_red_bag)
except JobLookupError:
pass
init_redbag(bot.self_id, g, f"{NICKNAME}", amount, num, int(bot.self_id), 1)
await group_red_bag.add_red_bag(
f"{NICKNAME}的红包", int(amount), num, NICKNAME, FESTIVE_KEY, True
)
scheduler.add_job(
end_festive_redbag,
end_festive_red_bag,
"date",
run_date=(datetime.now() + timedelta(hours=24)).replace(microsecond=0),
id=f"festive_redbag_{g}",
args=[bot, g],
# run_date=(datetime.now() + timedelta(hours=24)).replace(microsecond=0),
run_date=(datetime.now() + timedelta(seconds=30)).replace(
microsecond=0
),
id=f"{FESTIVE_KEY}_{g}",
args=[bot, group_red_bag],
)
try:
await bot.send_group_msg(
group_id=g,
message=f"{NICKNAME}发起了金币红包\n金额:{amount}\n数量:{num}\n"
+ image(
b64=await generate_send_redbag_pic(int(bot.self_id), greetings)
),
+ image(await random_red_bag_background(bot.self_id, greetings)),
)
logger.debug("节日红包图片信息发送成功...", "节日红包", group_id=g)
except ActionFailed:
logger.warning(f"节日红包 GROUP {g} 发送失败..")
pass
# 红包数据初始化
def init_redbag(
user_id: str,
group_id: str,
nickname: str,
amount: int,
num: int,
bot_self_id: int,
mode: int = 0,
):
global redbag_data, festive_redbag_data
data = redbag_data if mode == 0 else festive_redbag_data
if not data.get(group_id):
data[group_id] = {}
try:
if data[group_id]["user_id"] and user_id != bot_self_id:
return False, f'{data[group_id]["nickname"]}的红包还没抢完呢...'
except KeyError:
pass
data[group_id]["user_id"] = user_id
data[group_id]["nickname"] = nickname
data[group_id]["amount"] = amount
data[group_id]["num"] = num
data[group_id]["open_amount"] = 0
data[group_id]["time"] = time.time()
data[group_id]["redbag"] = random_redbag(amount, num)
data[group_id]["open_user"] = []
if mode == 0:
redbag_data = data
else:
festive_redbag_data = data
return True, ""
# 随机红包排列
def random_redbag(amount: int, num: int) -> list:
redbag_lst = []
for _ in range(num - 1):
tmp = int(amount / random.choice(range(3, num + 3)))
redbag_lst.append(tmp)
amount -= tmp
redbag_lst.append(amount)
return redbag_lst
# 返回开红包图片
async def get_redbag_img(user_id: str, group_id: str):
global redbag_data, festive_redbag_data
data = redbag_data
mode = 0
if festive_redbag_data.get(group_id):
try:
if user_id not in festive_redbag_data[group_id]["open_user"]:
data = festive_redbag_data
mode = 1
except KeyError:
pass
amount, data = await open_redbag(user_id, group_id, data)
text = (
f"已领取"
f'{data[group_id]["num"] - len(data[group_id]["redbag"])}'
f'/{data[group_id]["num"]}个,'
f'共{data[group_id]["open_amount"]}/{data[group_id]["amount"]}金币'
)
logger.info(
f"USER {user_id} GROUP {group_id} 抢到了 {data[group_id]['user_id']} 的红包,获取了{amount}金币"
)
b64 = await generate_open_redbag_pic(
data[group_id]["user_id"], data[group_id]["nickname"], amount, text
)
if data[group_id]["open_amount"] == data[group_id]["amount"]:
data[group_id] = {}
if mode == 0:
redbag_data = data
else:
festive_redbag_data = data
return b64
async def end_festive_redbag(bot: Bot, group_id: int):
global festive_redbag_data
message = (
f"{NICKNAME}的节日红包过时了,一共开启了 "
f"{festive_redbag_data[group_id]['num'] - len(festive_redbag_data[group_id]['redbag'])}"
f" 个红包,共 {festive_redbag_data[group_id]['open_amount']} 金币"
)
await bot.send_group_msg(group_id=group_id, message=message)
festive_redbag_data[group_id] = {}
logger.warning(f"节日红包图片信息发送失败...", "节日红包", group_id=g)
def check_on_gold_red(event) -> bool:
flag1 = True
flag2 = True
try:
if festive_redbag_data[str(event.group_id)]["user_id"]:
if event.user_id in festive_redbag_data[str(event.group_id)]["open_user"]:
flag1 = False
except KeyError:
flag1 = False
try:
if redbag_data[str(event.group_id)]["user_id"]:
if event.user_id in redbag_data[str(event.group_id)]["open_user"]:
flag2 = False
except KeyError:
flag2 = False
if flag1 or flag2:
return True
else:
return False
if group_red_bag := GROUP_DATA.get(event.group_id):
return group_red_bag.check_open(event.user_id)
return False