mirror of
https://github.com/xuthus83/LittlePaimon.git
synced 2025-04-12 23:29:37 +08:00
✨ 深渊统计
ui美化,补充新武器图鉴
This commit is contained in:
parent
7f9759dd8d
commit
18faeb17ae
@ -62,7 +62,8 @@
|
||||
"10000102": ["散兵", "伞兵", "国崩", "卢本伟", "大炮", "sb"],
|
||||
"10000103": ["迪希雅"],
|
||||
"10000104": ["艾尔海森", "苏"],
|
||||
"10000105": ["白术"]
|
||||
"10000105": ["白术"],
|
||||
"10000106": ["莱依拉"]
|
||||
},
|
||||
"武器": {
|
||||
"磐岩结绿": [
|
||||
@ -641,6 +642,19 @@
|
||||
"西福斯的月光",
|
||||
"西福斯",
|
||||
"月光"
|
||||
],
|
||||
"赤沙之杖": [
|
||||
"赤沙之杖",
|
||||
"赤沙"
|
||||
],
|
||||
"风信之锋": [
|
||||
"风信之锋",
|
||||
"风信"
|
||||
],
|
||||
"玛海菈的水色": [
|
||||
"玛海菈的水色",
|
||||
"玛海菈",
|
||||
"水色"
|
||||
]
|
||||
},
|
||||
"圣遗物": {
|
||||
|
@ -1,45 +1,99 @@
|
||||
import datetime
|
||||
from typing import Dict, Any, Tuple
|
||||
from collections import defaultdict
|
||||
from nonebot import get_bot
|
||||
from LittlePaimon.database.models import AbyssInfo
|
||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
||||
from LittlePaimon.utils import aiorequests
|
||||
from LittlePaimon.utils.files import load_image
|
||||
from LittlePaimon.config import RESOURCE_BASE_PATH
|
||||
from LittlePaimon.utils.image import PMImage, font_manager as fm, get_qq_avatar
|
||||
from LittlePaimon.utils.message import MessageBuild
|
||||
|
||||
|
||||
async def get_user_avatar(user_id: str, size: Tuple[int, int] = (60, 60)):
|
||||
img = await get_qq_avatar(user_id)
|
||||
await img.resize(size)
|
||||
await img.to_circle('circle')
|
||||
return img
|
||||
|
||||
|
||||
async def get_group_avatar(group_id: str):
|
||||
img = await aiorequests.get_img(f'https://p.qlogo.cn/gh/{group_id}/{group_id}/100', size=(110, 110))
|
||||
img = PMImage(img)
|
||||
await img.to_circle('circle')
|
||||
return img
|
||||
|
||||
|
||||
|
||||
async def get_statistics(group_id: int):
|
||||
if not (info_list := await AbyssInfo.all()):
|
||||
return '本群还没有深渊战斗数据哦!'
|
||||
member_list = await get_bot().get_group_member_list(group_id=group_id)
|
||||
member_id_list = [str(member['user_id']) for member in member_list]
|
||||
info_list = [info for info in info_list if info.user_id in member_id_list and info.total_battle and info.total_star and info.max_damage and info.max_take_damage]
|
||||
info_list = [info for info in info_list if
|
||||
info.user_id in member_id_list and info.total_battle and info.total_star and info.max_damage and info.max_take_damage]
|
||||
now = datetime.datetime.now()
|
||||
if 1 <= now.day < 15:
|
||||
if now.day <= 15:
|
||||
left_day = 1
|
||||
right_day = 15
|
||||
else:
|
||||
left_day = 16
|
||||
right_day = 31
|
||||
info_list = [info for info in info_list if left_day <= info.update_time.day <= right_day]
|
||||
info_list = [info for info in info_list if left_day <= info.update_time.day <= right_day and info.update_time.month == now.month]
|
||||
if not info_list:
|
||||
return '本群还没有深渊战斗数据哦!'
|
||||
elif len(info_list) < 3:
|
||||
return '本群深渊有效战斗数据不足3人,无法生成统计图!'
|
||||
for info in info_list:
|
||||
for member in member_list:
|
||||
if info.user_id == str(member['user_id']):
|
||||
info.nickname = member['card'] or member['nickname']
|
||||
break
|
||||
data = {
|
||||
'群号': str(group_id),
|
||||
'群名称': (await get_bot().get_group_info(group_id=group_id))['group_name'],
|
||||
}
|
||||
# 数据数
|
||||
info_num = len(info_list)
|
||||
data['总人数'] = info_num
|
||||
# 满星人数
|
||||
full_star_num = len([info for info in info_list if info.total_star >= 36])
|
||||
data['满星人数'] = full_star_num
|
||||
# 平均星数
|
||||
average_star = round(sum(info.total_star for info in info_list) / info_num, 1)
|
||||
data['平均星数'] = average_star
|
||||
# 平均战斗次数
|
||||
average_battle_num = round(sum(info.total_battle for info in info_list) / info_num, 1)
|
||||
data['平均战斗次数'] = average_battle_num
|
||||
# 最高伤害角色
|
||||
max_damage = max(info_list, key=lambda x: x.max_damage.value)
|
||||
# print(max_damage)
|
||||
# return '123'
|
||||
max_damage_user = [m for m in member_list if str(m['user_id']) == max_damage.user_id][0]
|
||||
max_damage_user = max_damage_user['card'] or max_damage_user['nickname']
|
||||
# max_damage = max(info_list, key=lambda x: x.max_damage.value)
|
||||
max_damage = sorted(info_list, key=lambda x: x.max_damage.value, reverse=True)
|
||||
data['最高伤害'] = [
|
||||
{
|
||||
'图标': info.max_damage.icon,
|
||||
'稀有度': info.max_damage.rarity,
|
||||
'等级': info.max_damage.level,
|
||||
'数值': info.max_damage.value,
|
||||
# '命座': (await Character.filter(user_id=info.user_id, uid=info.uid, character_id=info.max_damage.character_id).first()).constellation,
|
||||
'用户名': info.nickname,
|
||||
'qq号': info.user_id,
|
||||
'uid': info.uid,
|
||||
} for info in max_damage[:3]
|
||||
]
|
||||
# 最多承伤角色
|
||||
max_take_damage = max(info_list, key=lambda x: x.max_take_damage.value)
|
||||
max_take_damage_user = [m for m in member_list if str(m['user_id']) == max_take_damage.user_id][0]
|
||||
max_take_damage_user = max_take_damage_user['card'] or max_take_damage_user['nickname']
|
||||
max_take_damage = sorted(info_list, key=lambda x: x.max_take_damage.value, reverse=True)
|
||||
data['最高承受伤害'] = [
|
||||
{
|
||||
'图标': info.max_take_damage.icon,
|
||||
'稀有度': info.max_take_damage.rarity,
|
||||
'等级': info.max_take_damage.level,
|
||||
'数值': info.max_take_damage.value,
|
||||
# '命座': (await Character.filter(user_id=info.user_id, uid=info.uid, character_id=info.max_damage.character_id).first()).constellation,
|
||||
'用户名': info.nickname,
|
||||
'qq号': info.user_id,
|
||||
'uid': info.uid,
|
||||
} for info in max_take_damage[:3]
|
||||
]
|
||||
# 11、12层阵容
|
||||
battle_characters_up11 = defaultdict(lambda: 0)
|
||||
battle_characters_down11 = defaultdict(lambda: 0)
|
||||
@ -49,32 +103,127 @@ async def get_statistics(group_id: int):
|
||||
if floor11 := info.floors.get(11):
|
||||
for battles in floor11.battles_up:
|
||||
for character in battles.characters:
|
||||
battle_characters_up11[character.name] += 1
|
||||
battle_characters_up11[f'{character.icon}-{character.rarity}'] += 1
|
||||
for battles in floor11.battles_down:
|
||||
for character in battles.characters:
|
||||
battle_characters_down11[character.name] += 1
|
||||
battle_characters_down11[f'{character.icon}-{character.rarity}'] += 1
|
||||
if floor12 := info.floors.get(12):
|
||||
for battles in floor12.battles_up:
|
||||
for character in battles.characters:
|
||||
battle_characters_up12[character.name] += 1
|
||||
battle_characters_up12[f'{character.icon}-{character.rarity}'] += 1
|
||||
for battles in floor12.battles_down:
|
||||
for character in battles.characters:
|
||||
battle_characters_down12[character.name] += 1
|
||||
up_sort11 = [character[0] for character in
|
||||
sorted(battle_characters_up11.items(), key=lambda x: x[1], reverse=True)[:4]]
|
||||
down_sort11 = [character[0] for character in
|
||||
sorted(battle_characters_down11.items(), key=lambda x: x[1], reverse=True)[:4]]
|
||||
up_sort12 = [character[0] for character in
|
||||
sorted(battle_characters_up12.items(), key=lambda x: x[1], reverse=True)[:4]]
|
||||
down_sort12 = [character[0] for character in
|
||||
sorted(battle_characters_down12.items(), key=lambda x: x[1], reverse=True)[:4]]
|
||||
battle_characters_down12[f'{character.icon}-{character.rarity}'] += 1
|
||||
data['11层上半'] = sorted(battle_characters_up11.items(), key=lambda x: x[1], reverse=True)[:4]
|
||||
data['11层下半'] = sorted(battle_characters_down11.items(), key=lambda x: x[1], reverse=True)[:4]
|
||||
data['12层上半'] = sorted(battle_characters_up12.items(), key=lambda x: x[1], reverse=True)[:4]
|
||||
data['12层下半'] = sorted(battle_characters_down12.items(), key=lambda x: x[1], reverse=True)[:4]
|
||||
return await draw_statistics_img(data)
|
||||
|
||||
|
||||
async def draw_statistics_img(data: Dict[str, Any]):
|
||||
img = PMImage(image=RESOURCE_BASE_PATH / 'abyss' / 'statistics_bg.png')
|
||||
box = {
|
||||
'4big': await load_image(RESOURCE_BASE_PATH / 'abyss' / '4bigbox.png'),
|
||||
'4small': await load_image(RESOURCE_BASE_PATH / 'abyss' / '4smallbox.png'),
|
||||
'5big': await load_image(RESOURCE_BASE_PATH / 'abyss' / '5bigbox.png'),
|
||||
'5small': await load_image(RESOURCE_BASE_PATH / 'abyss' / '5smallbox.png'),
|
||||
'4bg': await load_image(RESOURCE_BASE_PATH / 'icon' / 'star4_no_line.png', size=(95, 95)),
|
||||
'5bg': await load_image(RESOURCE_BASE_PATH / 'icon' / 'star5_no_line.png', size=(95, 95))
|
||||
}
|
||||
avatar = await get_group_avatar(data['群号'])
|
||||
await img.paste(avatar, (38, 47))
|
||||
await img.text(data['群名称'], 162, 63, fm.get('hywh', 48), '#040404')
|
||||
await img.text(data['群号'], 165, 116, fm.get('hywh', 36), '#040404')
|
||||
await img.text(f'CREATED BY LITTLEPAIMON AT {datetime.datetime.now().strftime("%m-%d %H:%M")}',
|
||||
1033, 194, fm.get('bahnschrift_regular.ttf', 30), '#8c4c2e', 'right')
|
||||
await img.text(str(data['总人数']), (233, 352), 296, fm.get('bahnschrift_regular.ttf', 48), '#040404', 'center')
|
||||
await img.text(str(data['平均星数']), (492, 586), 296, fm.get('bahnschrift_regular.ttf', 48), '#040404', 'center')
|
||||
await img.text(str(data['平均战斗次数']), (698, 840), 296, fm.get('bahnschrift_regular.ttf', 48), '#040404', 'center')
|
||||
# 满星人数
|
||||
full_num = [data['满星人数'] / data['总人数'], 1 - data['满星人数'] / data['总人数']]
|
||||
now_used_width = 36
|
||||
if full_num[0] > 0.03:
|
||||
await img.draw_rectangle((now_used_width, 402, now_used_width + int(1007 * full_num[0]), 449), '#b6d6f2')
|
||||
await img.text(str(data['满星人数']), now_used_width + 18, 413, fm.get('bahnschrift_regular.ttf', 30), '#3d6e99')
|
||||
now_used_width += int(1007 * full_num[0])
|
||||
if full_num[1] > 0.03:
|
||||
await img.draw_rectangle((now_used_width, 402, now_used_width + int(1007 * full_num[1]), 449), '#c8b6f2')
|
||||
await img.text(str(data['总人数'] - data['满星人数']), now_used_width + 18, 413, fm.get('bahnschrift_regular.ttf', 30), '#593d99')
|
||||
# 最高伤害
|
||||
await img.paste(box[f'{data["最高伤害"][0]["稀有度"]}big'], (39, 512))
|
||||
await img.paste(box[f'{data["最高伤害"][1]["稀有度"]}small'], (39, 664))
|
||||
await img.paste(box[f'{data["最高伤害"][2]["稀有度"]}small'], (296, 664))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高伤害"][0]["图标"]}.png', size=(124, 124)),
|
||||
(44, 525))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高伤害"][1]["图标"]}.png', size=(82, 82)),
|
||||
(45, 673))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高伤害"][2]["图标"]}.png', size=(82, 82)),
|
||||
(300, 673))
|
||||
await img.paste(await get_user_avatar(data['最高伤害'][0]['qq号']), (112, 588))
|
||||
await img.paste(await get_user_avatar(data['最高伤害'][1]['qq号'], (42, 42)), (87, 713))
|
||||
await img.paste(await get_user_avatar(data['最高伤害'][2]['qq号'], (42, 42)), (344, 713))
|
||||
await img.text('最强一击', 180, 515, fm.get('hywh', 30), '#040404')
|
||||
await img.text('第二名', 139, 668, fm.get('hywh', 22), '#040404')
|
||||
await img.text('第三名', 397, 668, fm.get('hywh', 22), '#040404')
|
||||
await img.text(str(data['最高伤害'][0]['数值']), 180, 544, fm.get('bahnschrift_regular.ttf', 72), '#040404')
|
||||
await img.text(str(data['最高伤害'][1]['数值']), 137, 690, fm.get('bahnschrift_regular.ttf', 44), '#040404')
|
||||
await img.text(str(data['最高伤害'][1]['数值']), 395, 690, fm.get('bahnschrift_regular.ttf', 44), '#040404')
|
||||
await img.text(data['最高伤害'][0]['用户名'][:11], 180, 610, fm.get('hywh', 30), '#040404')
|
||||
await img.text(data['最高伤害'][1]['用户名'][:6], 137, 726, fm.get('hywh', 22), '#040404')
|
||||
await img.text(data['最高伤害'][2]['用户名'][:6], 395, 726, fm.get('hywh', 22), '#040404')
|
||||
|
||||
# 最高承伤
|
||||
await img.paste(box[f'{data["最高承受伤害"][0]["稀有度"]}big'], (554, 512))
|
||||
await img.paste(box[f'{data["最高承受伤害"][1]["稀有度"]}small'], (552, 664))
|
||||
await img.paste(box[f'{data["最高承受伤害"][2]["稀有度"]}small'], (808, 664))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高承受伤害"][0]["图标"]}.png', size=(124, 124)),
|
||||
(560, 525))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高承受伤害"][1]["图标"]}.png', size=(82, 82)),
|
||||
(557, 673))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高承受伤害"][2]["图标"]}.png', size=(82, 82)),
|
||||
(815, 673))
|
||||
await img.paste(await get_user_avatar(data['最高承受伤害'][0]['qq号']), (623, 588))
|
||||
await img.paste(await get_user_avatar(data['最高承受伤害'][1]['qq号'], (42, 42)), (600, 713))
|
||||
await img.paste(await get_user_avatar(data['最高承受伤害'][2]['qq号'], (42, 42)), (857, 713))
|
||||
await img.text('最多承伤', 693, 515, fm.get('hywh', 30), '#040404')
|
||||
await img.text('第二名', 652, 668, fm.get('hywh', 22), '#040404')
|
||||
await img.text('第三名', 910, 668, fm.get('hywh', 22), '#040404')
|
||||
await img.text(str(data['最高承受伤害'][0]['数值']), 693, 544, fm.get('bahnschrift_regular.ttf', 72), '#040404')
|
||||
await img.text(str(data['最高承受伤害'][1]['数值']), 650, 690, fm.get('bahnschrift_regular.ttf', 44), '#040404')
|
||||
await img.text(str(data['最高承受伤害'][2]['数值']), 908, 690, fm.get('bahnschrift_regular.ttf', 44), '#040404')
|
||||
await img.text(data['最高承受伤害'][0]['用户名'][:11], 693, 610, fm.get('hywh', 30), '#040404')
|
||||
await img.text(data['最高承受伤害'][1]['用户名'][:6], 650, 726, fm.get('hywh', 22), '#040404')
|
||||
await img.text(data['最高承受伤害'][2]['用户名'][:6], 908, 726, fm.get('hywh', 22), '#040404')
|
||||
|
||||
tag = await load_image(RESOURCE_BASE_PATH / 'general' / 'tag.png')
|
||||
# 角色出场率
|
||||
for i in range(4):
|
||||
icon, rarity, count = data['11层上半'][i][0].split('-')[0], data['11层上半'][i][0].split('-')[1], data['11层上半'][i][1]
|
||||
await img.paste(box[f'{rarity}bg'], (182 + i * 101, 867))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)), (182 + i * 101, 867))
|
||||
await img.paste(tag, (236 + i * 101, 942))
|
||||
await img.text(str(count), (236 + i * 101, 277 + i * 101), 943, fm.get('bahnschrift_regular.ttf', 19), 'white', 'center')
|
||||
|
||||
icon, rarity, count = data['11层下半'][i][0].split('-')[0], data['11层下半'][i][0].split('-')[1], data['11层下半'][i][1]
|
||||
await img.paste(box[f'{rarity}bg'], (642 + i * 101, 867))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)), (642 + i * 101, 867))
|
||||
await img.paste(tag, (696 + i * 101, 942))
|
||||
await img.text(str(count), (696 + i * 101, 737 + i * 101), 943, fm.get('bahnschrift_regular.ttf', 19), 'white', 'center')
|
||||
|
||||
icon, rarity, count = data['12层上半'][i][0].split('-')[0], data['12层上半'][i][0].split('-')[1], data['12层上半'][i][1]
|
||||
await img.paste(box[f'{rarity}bg'], (182 + i * 101, 983))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)), (182 + i * 101, 983))
|
||||
await img.paste(tag, (236 + i * 101, 1058))
|
||||
await img.text(str(count), (236 + i * 101, 278 + i * 101), 1059, fm.get('bahnschrift_regular.ttf', 19), 'white', 'center')
|
||||
|
||||
icon, rarity, count = data['12层下半'][i][0].split('-')[0], data['12层下半'][i][0].split('-')[1], data['12层下半'][i][1]
|
||||
await img.paste(box[f'{rarity}bg'], (642 + i * 101, 983))
|
||||
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)), (642 + i * 101, 983))
|
||||
await img.paste(tag, (696 + i * 101, 1058))
|
||||
await img.text(str(count), (696 + i * 101, 737 + i * 101), 1059, fm.get('bahnschrift_regular.ttf', 19), 'white', 'center')
|
||||
i += 1
|
||||
|
||||
return MessageBuild.Image(img, mode='RGB', quality=80)
|
||||
|
||||
text = f'本群群友{now.strftime("%m月%d日")}深渊统计情况:\n满星人数/总人数: {full_star_num}/{info_num}\n平均星数: {average_star}\n平均战斗次数: {average_battle_num}\n最高伤害角色: {max_damage_user}的{max_damage.max_damage.name}({max_damage.max_damage.value})\n' \
|
||||
f'最高承伤角色: {max_take_damage_user}的{max_take_damage.max_take_damage.name}({max_take_damage.max_take_damage.value})\n' \
|
||||
f'11层出场率最高角色:\n 上半:{" ".join(up_sort11)}\n 下半:{" ".join(down_sort11)}\n' \
|
||||
f'12层出场率最高角色:\n 上半:{" ".join(up_sort12)}\n 下半:{" ".join(down_sort12)}\n' \
|
||||
f'Created by LittlePaimon'
|
||||
|
||||
img = PMImage(size=(500, 33 * 15), color=(255, 255, 255, 255))
|
||||
await img.text_box(text.replace('\n', '^'), (10, 490), (10, 33 * 15 - 10), fm.get('hywh', 25), 'black')
|
||||
return MessageBuild.Image(img, mode='RGB')
|
||||
|
@ -135,6 +135,8 @@ class AsyncPlaywright:
|
||||
path = Path(path)
|
||||
try:
|
||||
page = await cls.goto(url, wait_until=wait_until, **kwargs)
|
||||
if page is None:
|
||||
return MessageSegment.text('截图失败,无法访问网页,请稍候再试')
|
||||
await page.set_viewport_size(viewport_size)
|
||||
if element:
|
||||
if isinstance(element, str):
|
||||
|
Loading…
x
Reference in New Issue
Block a user