部分静态资源存本地,优化代码

This commit is contained in:
CMHopeSunshine 2022-05-21 17:16:12 +08:00
parent 20e9b3659e
commit 8a9690c4cd
11 changed files with 160 additions and 183 deletions

View File

@ -1,7 +1,5 @@
import random
import requests
from ssl import SSLCertVerificationError
from nonebot import on_regex, on_command, logger
from nonebot.matcher import matchers
from nonebot.rule import Rule
@ -10,6 +8,8 @@ from nonebot.exception import FinishedException
from utils.config import config
from utils.auth_util import FreqLimiter2
from utils.message_util import MessageBuild
from utils.file_handler import load_json_from_url
voice_url = 'https://static.cherishmoon.fun/LittlePaimon/voice/'
chat_lmt = FreqLimiter2(60)
@ -28,10 +28,7 @@ async def update_paimon_voice(event: MessageEvent):
try:
old_len = len([m for m in matchers[10] if m.plugin_name == 'Paimon_Chat'])
matchers[10] = [m for m in matchers[10] if m.plugin_name != 'Paimon_Chat']
try:
voice_list = requests.get('https://static.cherishmoon.fun/LittlePaimon/voice/voice_list.json').json()
except SSLCertVerificationError:
voice_list = requests.get('http://static.cherishmoon.fun/LittlePaimon/voice/voice_list.json').json()
voice_list = load_json_from_url('https://static.cherishmoon.fun/LittlePaimon/voice/voice_list.json')
for key, value in voice_list.items():
create_matcher(key, value['pattern'], value['cooldown'], value['pro'], value['files'])
new_len = len(voice_list) - old_len
@ -61,19 +58,13 @@ def create_matcher(chat_word: str, pattern: str, cooldown: int, pro: float, resp
if '.mp3' not in response:
await hammer.finish(response)
else:
try:
await hammer.finish(MessageSegment.record(file=voice_url + response))
except SSLCertVerificationError:
await hammer.finish(MessageSegment.record(file=voice_url.replace('https', 'http') + response))
await hammer.finish(await MessageBuild.StaticRecord(url=f'LittlePaimon/voice/{response}'))
except FinishedException:
raise
except Exception as e:
logger.error('派蒙发送语音失败', e)
try:
voice_list = requests.get('https://static.cherishmoon.fun/LittlePaimon/voice/voice_list.json').json()
except SSLCertVerificationError:
voice_list = requests.get('http://static.cherishmoon.fun/LittlePaimon/voice/voice_list.json').json()
voice_list = load_json_from_url('https://static.cherishmoon.fun/LittlePaimon/voice/voice_list.json')
for k, v in voice_list.items():
create_matcher(k, v['pattern'], v['cooldown'], v['pro'], v['files'])

View File

@ -5,6 +5,7 @@ from PIL import Image, ImageDraw, ImageFont
from utils import aiorequests
from utils.message_util import MessageBuild
from utils.file_handler import load_image
res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res')
@ -33,12 +34,12 @@ def get_chan_time(timeStamp1, timeStamp2):
async def draw_abyss_floor_card(floor, floor_n):
floor_img = Image.open(os.path.join(res_path, 'abyss', f'floor{floor_n}_long.png')).convert('RGBA')
floor_img = load_image(os.path.join(res_path, 'abyss', f'floor{floor_n}_long.png'), mode='RGBA')
floor_draw = ImageDraw.Draw(floor_img)
floor_draw.text((590, 68), f"{floor['star']}/9", font=get_font(30), fill='white')
h, h1, h2 = 188.3, 230, 360
for j in floor['levels']:
star = Image.open(os.path.join(res_path, 'abyss', 'star.png')).convert('RGBA')
star = load_image(os.path.join(res_path, 'abyss', 'star.png'), mode='RGBA')
star_w = 500
for i in range(0, j['star']):
floor_img.alpha_composite(star, (star_w, h1 + 94))
@ -54,8 +55,7 @@ async def draw_abyss_floor_card(floor, floor_n):
for role in battles[0]['avatars']:
id = role['id']
level = role['level']
role_img = Image.open(os.path.join(res_path, 'role_card', f'{id}.png')).convert('RGBA')
role_img = role_img.resize((90, 110))
role_img = load_image(os.path.join(res_path, 'role_card', f'{id}.png'), size=(90, 110), mode='RGBA')
role_draw = ImageDraw.Draw(role_img)
role_draw.text((25, 86), f'Lv.{level}', font=get_font(18), fill='black')
floor_img.alpha_composite(role_img, (w, h1))
@ -66,8 +66,7 @@ async def draw_abyss_floor_card(floor, floor_n):
for role in battles[1]['avatars']:
id = role['id']
level = role['level']
role_img = Image.open(os.path.join(res_path, 'role_card', f'{id}.png')).convert('RGBA')
role_img = role_img.resize((90, 110))
role_img = load_image(os.path.join(res_path, 'role_card', f'{id}.png'), size=(90, 110), mode='RGBA')
role_draw = ImageDraw.Draw(role_img)
role_draw.text((25, 86), f'Lv.{level}', font=get_font(18), fill='black')
floor_img.alpha_composite(role_img, (w, h2))
@ -95,7 +94,7 @@ async def draw_abyss_card(data, uid, floor_num):
total_star += str(d['star']) + '-'
total_star = total_star.strip('-') + ']'
time = (get_open_time(int(data['start_time']), int(data['end_time'])))
top_img = Image.open(os.path.join(res_path, 'abyss', 'abyss_total.png')).convert('RGBA')
top_img = load_image(os.path.join(res_path, 'abyss', 'abyss_total.png'), mode='RGBA')
top_draw = ImageDraw.Draw(top_img)
top_draw.text((15, 22), f'UID{uid}', font=get_font(21), fill='white')
top_draw.text((510, 22), time, font=get_font(21), fill='white')
@ -106,71 +105,32 @@ async def draw_abyss_card(data, uid, floor_num):
for role in data['reveal_rank']:
id = role['avatar_id']
times = role['value']
role_img = Image.open(os.path.join(res_path, 'role_card', f'{id}.png')).convert('RGBA')
role_img = role_img.resize((90, 110))
role_img = load_image(os.path.join(res_path, 'role_card', f'{id}.png'), size=(90, 110), mode='RGBA')
role_draw = ImageDraw.Draw(role_img)
role_draw.text((25, 86), f'{times}', font=get_font(18), fill='black')
top_img.alpha_composite(role_img, (width, 165))
width += 150
defeat_rank = data['defeat_rank'][0]
# if not os.path.exists(os.path.join(res_path, 'role_side_card', f"{defeat_rank['avatar_id']}.png")):
# async with ClientSession() as session:
# defeat_rank_img = await (await session.get(defeat_rank['avatar_icon'])).read()
# defeat_rank_img = Image.open(BytesIO(defeat_rank_img)).convert("RGBA").resize((60, 60))
# defeat_rank_img.save(os.path.join(res_path, 'role_side_card', f"{defeat_rank['avatar_id']}.png"))
# else:
# defeat_rank_img = Image.open(os.path.join(res_path, 'role_side_card', f"{defeat_rank['avatar_id']}.png"))
defeat_rank_img = await aiorequests.get_img(url=defeat_rank['avatar_icon'], size=(60, 60), mode='RGBA')
top_draw.text((160, 343), str(defeat_rank['value']), font=get_font(21), fill='white')
top_img.alpha_composite(defeat_rank_img, (280, 320))
damage_rank = data['damage_rank'][0]
# if not os.path.exists(os.path.join(res_path, 'role_side_card', f"{damage_rank['avatar_id']}.png")):
# async with ClientSession() as session:
# damage_rank_img = await (await session.get(damage_rank['avatar_icon'])).read()
# damage_rank_img = Image.open(BytesIO(damage_rank_img)).convert("RGBA").resize((60, 60))
# damage_rank_img.save(os.path.join(res_path, 'role_side_card', f"{damage_rank['avatar_id']}.png"))
# else:
# damage_rank_img = Image.open(os.path.join(res_path, 'role_side_card', f"{damage_rank['avatar_id']}.png"))
damage_rank_img = await aiorequests.get_img(url=damage_rank['avatar_icon'], size=(60, 60), mode='RGBA')
top_draw.text((495, 343), str(damage_rank['value']), font=get_font(21), fill='white')
top_img.alpha_composite(damage_rank_img, (590, 320))
take_damage_rank = data['take_damage_rank'][0]
# if not os.path.exists(os.path.join(res_path, 'role_side_card', f"{take_damage_rank['avatar_id']}.png")):
# async with ClientSession() as session:
# take_damage_rank_img = await (await session.get(take_damage_rank['avatar_icon'])).read()
# take_damage_rank_img = Image.open(BytesIO(take_damage_rank_img)).convert("RGBA").resize((60, 60))
# take_damage_rank_img.save(os.path.join(res_path, 'role_side_card', f"{take_damage_rank['avatar_id']}.png"))
# else:
# take_damage_rank_img = Image.open(
# os.path.join(res_path, 'role_side_card', f"{take_damage_rank['avatar_id']}.png"))
take_damage_rank_img = await aiorequests.get_img(url=take_damage_rank['avatar_icon'], size=(60, 60), mode='RGBA')
top_draw.text((180, 389), str(take_damage_rank['value']), font=get_font(21), fill='white')
top_img.alpha_composite(take_damage_rank_img, (280, 365))
energy_skill_rank = data['energy_skill_rank'][0]
# if not os.path.exists(os.path.join(res_path, 'role_side_card', f"{energy_skill_rank['avatar_id']}.png")):
# async with ClientSession() as session:
# energy_skill_rank_img = await (await session.get(energy_skill_rank['avatar_icon'])).read()
# energy_skill_rank_img = Image.open(BytesIO(energy_skill_rank_img)).convert("RGBA").resize((60, 60))
# energy_skill_rank_img.save(os.path.join(res_path, 'role_side_card', f"{energy_skill_rank['avatar_id']}.png"))
# else:
# energy_skill_rank_img = Image.open(
# os.path.join(res_path, 'role_side_card', f"{energy_skill_rank['avatar_id']}.png"))
energy_skill_rank_img = await aiorequests.get_img(url=energy_skill_rank['avatar_icon'], size=(60, 60), mode='RGBA')
top_draw.text((530, 389), str(energy_skill_rank['value']), font=get_font(21), fill='white')
top_img.alpha_composite(energy_skill_rank_img, (590, 365))
normal_skill_rank = data['normal_skill_rank'][0]
# if not os.path.exists(os.path.join(res_path, 'role_side_card', f"{normal_skill_rank['avatar_id']}.png")):
# async with ClientSession() as session:
# normal_skill_rank_img = await (await session.get(normal_skill_rank['avatar_icon'])).read()
# normal_skill_rank_img = Image.open(BytesIO(normal_skill_rank_img)).convert("RGBA").resize((60, 60))
# normal_skill_rank_img.save(os.path.join(res_path, 'role_side_card', f"{normal_skill_rank['avatar_id']}.png"))
# else:
# normal_skill_rank_img = Image.open(
# os.path.join(res_path, 'role_side_card', f"{normal_skill_rank['avatar_id']}.png"))
normal_skill_rank_img = await aiorequests.get_img(url=normal_skill_rank['avatar_icon'], size=(60, 60), mode='RGBA')
top_draw.text((195, 435), str(normal_skill_rank['value']), font=get_font(21), fill='white')
top_img.alpha_composite(normal_skill_rank_img, (280, 410))

View File

@ -7,6 +7,7 @@ from PIL import Image, ImageDraw, ImageFont
from utils import aiorequests
from utils.message_util import MessageBuild
from utils.file_handler import load_image
res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res')
@ -40,9 +41,10 @@ async def draw_daily_note_card(data, uid):
elif data['retcode'] != 0:
return f'派蒙获取数据失败了,获取状态:\n{data["message"]},{data["retcode"]}'
data = data['data']
circle_img = Image.open(os.path.join(res_path, 'daily_note', '透明圆.png'))
finished_icon = Image.open(os.path.join(res_path, 'daily_note', 'finished.png'))
bg_img = Image.open(os.path.join(res_path, 'daily_note', 'ssbq.png')).convert("RGBA")
circle_img = load_image(os.path.join(res_path, 'daily_note', '透明圆.png'))
finished_icon = load_image(os.path.join(res_path, 'daily_note', 'finished.png'))
bg_img = load_image(os.path.join(res_path, 'daily_note', 'ssbq.png'), mode='RGBA')
bg_draw = ImageDraw.Draw(bg_img)
# uid文字
bg_draw.text((152, 251), f"uid{uid}", fill='#5680d2', font=get_font(60, 'number.ttf'))
@ -143,8 +145,8 @@ async def draw_daily_note_card(data, uid):
bg_draw.text((1408, 1588), last_finish_str, fill="#5680d2",
font=get_font(60, '优设标题黑.ttf'))
role_img = Image.open(os.path.join(res_path, 'emoticons', random.choice(os.listdir(os.path.join(res_path, 'emoticons'))))).convert('RGBA')
role_img = role_img.resize((int(role_img.size[0] * 3.5), int(role_img.size[1] * 3.5)), Image.ANTIALIAS)
role_img = load_image(os.path.join(res_path, 'emoticons', random.choice(os.listdir(os.path.join(res_path, 'emoticons')))), size=3.5, mode='RGBA')
bg_img.alpha_composite(role_img, (1220, 200))
now = datetime.datetime.now().strftime('%m月%d%H:%M')
bg_draw.text((554, 1794), 'Created by LittlePaimon·' + now, fill='#5680d2', font=get_font(40, '优设标题黑.ttf'))

View File

@ -4,6 +4,7 @@ import random
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw, ImageFont
from utils.message_util import MessageBuild
from utils.file_handler import load_image
res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res')
@ -17,8 +18,8 @@ def get_font_bd(size):
async def get_box(t, num):
box = Image.open(os.path.join(res_path, 'monthinfo', 'box.png')).convert('RGBA')
img = Image.open(os.path.join(res_path, 'monthinfo', f'{t}.png')).convert('RGBA')
box = load_image(os.path.join(res_path, 'monthinfo', 'box.png'), mode='RGBA')
img = load_image(os.path.join(res_path, 'monthinfo', f'{t}.png'), mode='RGBA')
box.alpha_composite(img, (11, 11))
box_draw = ImageDraw.Draw(box)
box_draw.text((83, 18), f'{t}', font=get_font(25), fill='black')
@ -56,9 +57,9 @@ async def draw_monthinfo_card(data):
elif data['retcode'] != 0:
return f'派蒙获取数据失败了,获取状态:\n{data["message"]},{data["retcode"]}'
data = data['data']
bg_img = Image.open(os.path.join(res_path, 'monthinfo', 'bg.png')).convert('RGBA')
bg_img = load_image(os.path.join(res_path, 'monthinfo', 'bg.png'), mode='RGBA')
bg_draw = ImageDraw.Draw(bg_img)
line = Image.open(os.path.join(res_path, 'monthinfo', 'line.png')).convert('RGBA')
line = load_image(os.path.join(res_path, 'monthinfo', 'line.png'), mode='RGBA')
# 顶标题
bg_draw.text((60, 42), f'旅行者{data["data_month"]}月札记', font=get_font_bd(30), fill='#27384C')
bg_draw.text((300, 52), f'{data["nickname"]} {data["uid"]}', font=get_font(21), fill='#27384C')
@ -73,15 +74,15 @@ async def draw_monthinfo_card(data):
bg_img.alpha_composite(await get_box('摩拉', data['day_data']['current_mora']), (40, 388))
# 表情
emoticon1 = Image.open(os.path.join(res_path, 'emoticons', random.choice(os.listdir(os.path.join(res_path, 'emoticons'))))).convert('RGBA')
emoticon1 = load_image(os.path.join(res_path, 'emoticons', random.choice(os.listdir(os.path.join(res_path, 'emoticons')))), mode='RGBA')
bg_img.alpha_composite(emoticon1, (360, 140))
emoticon2 = Image.open(os.path.join(res_path, 'emoticons', random.choice(os.listdir(os.path.join(res_path, 'emoticons'))))).convert('RGBA')
emoticon2 = load_image(os.path.join(res_path, 'emoticons', random.choice(os.listdir(os.path.join(res_path, 'emoticons')))), mode='RGBA')
bg_img.alpha_composite(emoticon2, (360, 317))
bg_img.alpha_composite(line, (64, 480))
# 圆环比例图
bg_draw.text((60, 495), '原石收入组成:', font=get_font_bd(25), fill='#27384C')
circle = Image.open(os.path.join(res_path, 'monthinfo', 'circle.png')).convert('RGBA')
circle = load_image(os.path.join(res_path, 'monthinfo', 'circle.png'), mode='RGBA')
bg_img.alpha_composite(circle, (50, 550))
color = {'每日活跃': '#BD9A5A', '深境螺旋': '#739970', '活动奖励': '#5A7EA0', '邮件奖励': '#7A6CA7', '冒险奖励': '#D56564',

View File

@ -7,6 +7,7 @@ from PIL import Image, ImageDraw, ImageFont
from utils import aiorequests
from utils.message_util import MessageBuild
from utils.file_handler import load_image
res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res')
@ -28,30 +29,23 @@ def get_expl_per(percentage):
async def get_chara_card(data):
chara_card = Image.new("RGBA", (226, 313), (255, 255, 255, 255))
chara_img = Image.open(os.path.join(res_path, 'role_card', f'{data["id"]}.png'))
chara_img = load_image(os.path.join(res_path, 'role_card', f'{data["id"]}.png'))
chara_card.alpha_composite(chara_img, (0, 0))
b = Image.open(os.path.join(res_path, 'player_card', 'chara_botton.png'))
b = load_image(os.path.join(res_path, 'player_card', 'chara_botton.png'))
chara_card.alpha_composite(b, (0, 236))
# 命座
if data['name'] != '埃洛伊':
actived_constellation_num = Image.open(
actived_constellation_num = load_image(
os.path.join(res_path, 'player_card', f'命之座{data["actived_constellation_num"]}.png'))
chara_card.alpha_composite(actived_constellation_num, (155, 0))
# 好感度
if data['name'] != '旅行者':
fetter = Image.open(os.path.join(res_path, 'player_card', f'好感度{data["fetter"]}.png'))
fetter = load_image(os.path.join(res_path, 'player_card', f'好感度{data["fetter"]}.png'))
chara_card.alpha_composite(fetter, (155, 166))
# 武器背景
weapon_bg = Image.open(os.path.join(res_path, 'player_card', f'{data["weapon"]["rarity"]}星武器.png'))
weapon_bg = load_image(os.path.join(res_path, 'player_card', f'{data["weapon"]["rarity"]}星武器.png'))
chara_card.alpha_composite(weapon_bg, (0, 227))
# 武器图标
# weapon_name = data['weapon']['icon'].split('/')[-1]
# if not os.path.exists(os.path.join(res_path, 'weapon', weapon_name)):
# async with ClientSession() as session:
# weapon_icon = await (await session.get(data['weapon']['icon'])).read()
# weapon_icon = Image.open(BytesIO(weapon_icon)).convert("RGBA")
# weapon_icon.save(os.path.join(res_path, 'weapon', weapon_name))
# weapon_icon = Image.open(os.path.join(res_path, 'weapon', weapon_name)).resize((63, 63))
weapon_icon = await aiorequests.get_img(url=data['weapon']['icon'], size=(63, 63), mode='RGBA')
chara_card.alpha_composite(weapon_icon, (0, 230))
# 等级信息
@ -198,16 +192,15 @@ async def draw_player_card(data, chara_data, uid, nickname="旅行者"):
elif data['retcode'] != 0:
return f'派蒙获取数据失败了,获取状态:\n{data["message"]},{data["retcode"]}'
data = data['data']
bg_img = Image.open(os.path.join(res_path, 'player_card', '背景.png')).convert('RGBA')
bg_img = load_image(os.path.join(res_path, 'player_card', '背景.png'), mode='RGBA')
bg_draw = ImageDraw.Draw(bg_img)
# 头部名片
name_id = random.choice(data['avatars'][0:8])['id']
name_card = Image.open(os.path.join(res_path, 'name_card', f'{name_id}.png')).crop((0, 40, 840, 360)).resize(
(846, 322))
avatar = Image.open(os.path.join(res_path, 'role_profile', f'{name_id}.png')).resize((240, 240))
name_card = load_image(os.path.join(res_path, 'name_card', f'{name_id}.png'), crop=(0, 40, 840, 360), size=(846, 322))
avatar = load_image(os.path.join(res_path, 'role_profile', f'{name_id}.png'), size=(240, 240))
bg_img.alpha_composite(name_card, (57, 27))
bg_img.alpha_composite(avatar, (360, 25))
uid_bg = Image.open(os.path.join(res_path, 'player_card', 'UID_bg.png')).resize((280, 100))
uid_bg = load_image(os.path.join(res_path, 'player_card', 'UID_bg.png'), size=(280, 100))
bg_img.alpha_composite(uid_bg, (340, 247))
bg_draw.text((354, 259), f'昵称 {nickname}', font=get_font(30), fill='white')
bg_draw.text((354, 291), f'UID {uid}', font=get_font(30), fill='white')
@ -215,14 +208,14 @@ async def draw_player_card(data, chara_data, uid, nickname="旅行者"):
stats = data['stats']
await draw_stats_data(bg_draw, stats)
# 尘歌壶
h_lock = Image.open(os.path.join(res_path, 'player_card', '未解锁.png'))
h_lock = load_image(os.path.join(res_path, 'player_card', '未解锁.png'))
homes_list = {'罗浮洞': {'unlock': False, 'posi': (79, 852)}, '清琼岛': {'unlock': False, 'posi': (79, 1000)},
'翠黛峰': {'unlock': False, 'posi': (489, 852)}, '绘绮庭': {'unlock': False, 'posi': (489, 1000)}}
if data['homes']:
for hl in homes_list.items():
for h in data['homes']:
if hl[0] in h.values():
h_img = Image.open(os.path.join(res_path, 'player_card', f'{hl[0]}.png'))
h_img = load_image(os.path.join(res_path, 'player_card', f'{hl[0]}.png'))
bg_img.alpha_composite(h_img, hl[1]['posi'])
homes_list[hl[0]]['unlock'] = True
for hl in homes_list.items():
@ -257,30 +250,22 @@ async def draw_player_card(data, chara_data, uid, nickname="旅行者"):
# ysa
async def get_chara_card_long(data):
chara_card = Image.new("RGBA", (226, 382), (255, 255, 255, 255))
chara_img = Image.open(os.path.join(res_path, 'role_card', f'{data["id"]}.png'))
chara_img = load_image(os.path.join(res_path, 'role_card', f'{data["id"]}.png'))
chara_card.alpha_composite(chara_img, (0, 0))
b = Image.open(os.path.join(res_path, 'player_card', '角色卡底部.png'))
b = load_image(os.path.join(res_path, 'player_card', '角色卡底部.png'))
chara_card.alpha_composite(b, (0, 282))
# 命座
if data['name'] != '埃洛伊':
actived_constellation_num = Image.open(
actived_constellation_num = load_image(
os.path.join(res_path, 'player_card', f'命之座{data["actived_constellation_num"]}.png'))
chara_card.alpha_composite(actived_constellation_num, (155, 0))
# 好感度
if data['name'] != '旅行者':
fetter = Image.open(os.path.join(res_path, 'player_card', f'好感度{data["fetter"]}.png'))
fetter = load_image(os.path.join(res_path, 'player_card', f'好感度{data["fetter"]}.png'))
chara_card.alpha_composite(fetter, (155, 166))
# 武器背景
weapon_bg = Image.open(os.path.join(res_path, 'player_card', f'{data["weapon"]["rarity"]}星武器.png'))
weapon_bg = load_image(os.path.join(res_path, 'player_card', f'{data["weapon"]["rarity"]}星武器.png'))
chara_card.alpha_composite(weapon_bg, (3, 288))
# 武器图标
# weapon_name = data['weapon']['icon'].split('/')[-1]
# if not os.path.exists(os.path.join(res_path, 'weapon', weapon_name)):
# async with ClientSession() as session:
# weapon_icon = await (await session.get(data['weapon']['icon'])).read()
# weapon_icon = Image.open(BytesIO(weapon_icon)).convert("RGBA")
# weapon_icon.save(os.path.join(res_path, 'weapon', weapon_name))
# weapon_icon = Image.open(os.path.join(res_path, 'weapon', weapon_name)).resize((62, 62))
weapon_icon = await aiorequests.get_img(url=data['weapon']['icon'], size=(62, 62), mode='RGBA')
chara_card.alpha_composite(weapon_icon, (3, 291))
# 等级信息
@ -317,14 +302,14 @@ async def draw_all_chara_card(data, uid):
chara['rarity'] = 4.5
chara_list = sorted(data, key=lambda i: (
i['rarity'], i['actived_constellation_num'], i['level'], i['fetter'], i['weapon']['rarity']), reverse=True)
bg_top = Image.open(os.path.join(res_path, 'player_card', '卡片顶部.png'))
avatar = Image.open(os.path.join(res_path, 'role_profile', f'{chara_list[0]["id"]}.png')).resize((220, 220))
bg_top = load_image(os.path.join(res_path, 'player_card', '卡片顶部.png'))
avatar = load_image(os.path.join(res_path, 'role_profile', f'{chara_list[0]["id"]}.png'), size=(220, 220))
bg_top.alpha_composite(avatar, (542, 30))
draw = ImageDraw.Draw(bg_top)
draw.text((538, 235), f'UID {uid}', font=get_font(30), fill='black')
bg_middle = Image.open(os.path.join(res_path, 'player_card', '卡片身体.png')).resize((1304, 474))
bg_bottom = Image.open(os.path.join(res_path, 'player_card', '卡片底部.png'))
bg_middle = load_image(os.path.join(res_path, 'player_card', '卡片身体.png'), size=(1304, 474))
bg_bottom = load_image(os.path.join(res_path, 'player_card', '卡片底部.png'))
bg_img = Image.new('RGBA', (1304, 382 + col * 424 + (col - 1) * 50 + 87), (0, 0, 0, 0))
bg_img.paste(bg_top, (0, 0))
for i in range(0, col):
@ -340,18 +325,11 @@ async def draw_all_chara_card(data, uid):
# ysc
shadow = Image.open(os.path.join(res_path, 'other', 'shadow.png'))
shadow = load_image(os.path.join(res_path, 'other', 'shadow.png'))
async def draw_reli_icon(data):
base_icon = Image.open(os.path.join(res_path, 'other', f'star{data["rarity"]}.png')).resize((80, 80))
# if not os.path.exists(os.path.join(res_path, 'reliquaries', f'{data["id"]}.png')):
# async with ClientSession() as session:
# icon = await (await session.get(data["icon"])).read()
# icon = Image.open(BytesIO(icon)).convert("RGBA").resize((80, 80))
# icon.save(os.path.join(res_path, 'reliquaries', f'{data["id"]}.png'))
# else:
# icon = Image.open(os.path.join(res_path, 'reliquaries', f'{data["id"]}.png')).resize((80, 80))
base_icon = load_image(os.path.join(res_path, 'other', f'star{data["rarity"]}.png'), size=(80, 80))
icon = await aiorequests.get_img(url=data["icon"], size=(80, 80), mode='RGBA')
base_icon.alpha_composite(icon, (0, 0))
base_icon.alpha_composite(shadow, (40, 60))
@ -361,18 +339,11 @@ async def draw_reli_icon(data):
async def draw_const_skill_icon(data, name):
base_icon = Image.open(os.path.join(res_path, 'other', '命座.png')).resize((65, 65))
# if not os.path.exists(os.path.join(res_path, 'skill_constellations', f'{name}{data["id"]}.png')):
# async with ClientSession() as session:
# icon = await (await session.get(data["icon"])).read()
# icon = Image.open(BytesIO(icon)).convert("RGBA").resize((65, 65))
# icon.save(os.path.join(res_path, 'reliquaries', f'{name}{data["id"]}.png'))
# else:
# icon = Image.open(os.path.join(res_path, 'reliquaries', f'{name}{data["id"]}.png')).resize((65, 65))
base_icon = load_image(os.path.join(res_path, 'other', '命座.png'), size=(65, 65))
icon = await aiorequests.get_img(url=data["icon"], size=(65, 65), mode='RGBA')
base_icon.alpha_composite(icon, (0, 0))
if 'is_actived' in data and not data['is_actived']:
unlock_icon = Image.open(os.path.join(res_path, 'other', '命座未解锁.png')).resize((65, 65))
unlock_icon = load_image(os.path.join(res_path, 'other', '命座未解锁.png'), size=(65, 65))
base_icon.alpha_composite(unlock_icon, (0, 0))
return base_icon
@ -414,14 +385,14 @@ async def draw_chara_card(data, skill_data, chara_name, uid):
if not f:
return f'{chara_name[1][0]}不在你公开的8个角色中或你没有这个角色哦'
# 立绘
bg_img = Image.open(os.path.join(res_path, 'name_card', f'{character["id"]}.png'))
bg_img = load_image(os.path.join(res_path, 'name_card', f'{character["id"]}.png'))
bg_draw = ImageDraw.Draw(bg_img)
if character['id'] == 10000007:
chara_img = Image.open(os.path.join(res_path, 'role_splash', '荧.png')).convert('RGBA')
chara_img = load_image(os.path.join(res_path, 'role_splash', '荧.png'), mode='RGBA')
elif character['id'] == 10000005:
chara_img = Image.open(os.path.join(res_path, 'role_splash', '空.png')).convert('RGBA')
chara_img = load_image(os.path.join(res_path, 'role_splash', '空.png'), mode='RGBA')
else:
chara_img = Image.open(os.path.join(res_path, 'role_splash', f'{character["name"]}.png')).convert('RGBA')
chara_img = load_image(os.path.join(res_path, 'role_splash', f'{character["name"]}.png'), mode='RGBA')
W, H = chara_img.size
chara_img = chara_img.resize((int(W * 400 / H), 400))
bg_img.alpha_composite(chara_img, (0, 0))
@ -436,19 +407,18 @@ async def draw_chara_card(data, skill_data, chara_name, uid):
bg_img.alpha_composite(await draw_line(character['level'] / 90), (330, 92))
bg_img.alpha_composite(await draw_line(character['fetter'] / 10), (330, 137))
bg_draw.text((560, 83), f'Lv.{character["level"]}', font=get_font(25), fill='white')
fetter = Image.open(os.path.join(res_path, 'player_card', f'好感度{character["fetter"]}.png')).resize((57, 49))
fetter = load_image(os.path.join(res_path, 'player_card', f'好感度{character["fetter"]}.png'), size=(57, 49))
bg_img.alpha_composite(fetter, (560, 122))
# 武器
weapon_bg = Image.open(os.path.join(res_path, 'other', f'star{character["weapon"]["rarity"]}.png')).resize(
(100, 100))
weapon_bg = load_image(os.path.join(res_path, 'other', f'star{character["weapon"]["rarity"]}.png'), size=(100, 100))
weapon_icon = await aiorequests.get_img(url=character['weapon']['icon'], size=(100, 100), mode='RGBA')
bg_img.alpha_composite(weapon_bg, (293, 175))
bg_img.alpha_composite(weapon_icon, (293, 175))
bg_img.alpha_composite(shadow.resize((50, 25)), (344, 250))
bg_draw.text((348, 250), f'Lv.{character["weapon"]["level"]}', font=get_font(18), fill='white')
weapon_star = Image.open(
os.path.join(res_path, 'player_card', f'命之座{character["weapon"]["affix_level"]}.png')).resize((40, 40))
weapon_star = load_image(
os.path.join(res_path, 'player_card', f'命之座{character["weapon"]["affix_level"]}.png'), size=(40, 40))
bg_img.alpha_composite(weapon_star, (353, 175))
# 圣遗物

View File

@ -1,12 +1,12 @@
from utils.auth_util import get_headers, get_sign_headers, get_use_cookie, get_own_cookie, check_retcode
from utils.db_util import update_cookie_cache
from utils.decorator import cache
from utils.decorator import AsyncCache
from utils import aiorequests
import datetime
import re
@cache(ttl=datetime.timedelta(hours=1))
@AsyncCache(ttl=datetime.timedelta(hours=1))
async def get_abyss_data(user_id, uid, schedule_type="1", use_cache=True):
server_id = "cn_qd01" if uid[0] == '5' else "cn_gf01"
url = "https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/spiralAbyss"
@ -50,7 +50,7 @@ async def get_daily_note_data(uid):
return f'你的uid{uid}的cookie已过期,需要重新绑定哦!'
@cache(ttl=datetime.timedelta(hours=1))
@AsyncCache(ttl=datetime.timedelta(hours=1))
async def get_player_card_data(user_id, uid, use_cache=True):
server_id = "cn_qd01" if uid[0] == '5' else "cn_gf01"
url = "https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index"
@ -72,7 +72,7 @@ async def get_player_card_data(user_id, uid, use_cache=True):
return data
@cache(ttl=datetime.timedelta(hours=1))
@AsyncCache(ttl=datetime.timedelta(hours=1))
async def get_chara_detail_data(user_id, uid, use_cache=True):
server_id = "cn_qd01" if uid[0] == '5' else "cn_gf01"
json_data = {
@ -95,7 +95,7 @@ async def get_chara_detail_data(user_id, uid, use_cache=True):
return data
@cache(ttl=datetime.timedelta(hours=1))
@AsyncCache(ttl=datetime.timedelta(hours=1))
async def get_chara_skill_data(uid, chara_id, use_cache=True):
server_id = "cn_qd01" if uid[0] == '5' else "cn_gf01"
url = 'https://api-takumi.mihoyo.com/event/e20200928calculate/v1/sync/avatar/detail'
@ -114,7 +114,7 @@ async def get_chara_skill_data(uid, chara_id, use_cache=True):
return data
@cache(ttl=datetime.timedelta(hours=1))
@AsyncCache(ttl=datetime.timedelta(hours=1))
async def get_monthinfo_data(uid, month, use_cache=True):
server_id = "cn_qd01" if uid[0] == '5' else "cn_gf01"
url = 'https://hk4e-api.mihoyo.com/event/ys_ledger/monthInfo'

View File

@ -2,7 +2,6 @@ import os
import re
import time
from ssl import SSLCertVerificationError
from nonebot import on_endswith, on_command, on_regex
from nonebot.adapters.onebot.v11 import MessageSegment, MessageEvent
@ -10,6 +9,7 @@ from nonebot.params import RegexDict
from utils.character_alias import get_id_by_alias
from utils.decorator import exception_handler
from utils.message_util import MessageBuild
from .abyss_rate_draw import draw_rate_rank, draw_teams_rate
from .blue import get_blue_pic
@ -45,12 +45,7 @@ async def genshin_guide(event: MessageEvent):
realname = get_id_by_alias(name)
if name in ['风主', '岩主', '雷主'] or realname:
name = realname[1][0] if name not in ['风主', '岩主', '雷主'] else name
try:
await guide.finish(
MessageSegment.image(file=f'https://static.cherishmoon.fun/LittlePaimon/XFGuide/{name}.jpg'))
except SSLCertVerificationError:
await guide.finish(
MessageSegment.image(file=f'http://static.cherishmoon.fun/LittlePaimon/XFGuide/{name}.jpg'))
await guide.finish(await MessageBuild.StaticImage(url=f'LittlePaimon/XFGuide/{name}.jpg'))
else:
await guide.finish(f'没有找到{name}的攻略', at_sender=True)
@ -62,12 +57,7 @@ async def genshin_material(event: MessageEvent):
realname = get_id_by_alias(name)
if name in ['夜兰', '久岐忍'] or realname:
name = realname[1][0] if realname else name
try:
await material.finish(
MessageSegment.image(file=f'https://static.cherishmoon.fun/LittlePaimon/RoleMaterials/{name}材料.jpg'))
except SSLCertVerificationError:
await material.finish(
MessageSegment.image(file=f'http://static.cherishmoon.fun/LittlePaimon/RoleMaterials/{name}材料.jpg'))
await material.finish(await MessageBuild.StaticImage(f'LittlePaimon/RoleMaterials/{name}材料.jpg'))
else:
await material.finish(f'没有找到{name}的材料', at_sender=True)
@ -92,13 +82,7 @@ async def genshinAttribute2(event: MessageEvent):
realname = get_id_by_alias(name)
if name in ['风主', '岩主', '雷主'] or realname:
name = realname[1][0] if name not in ['风主', '岩主', '雷主'] else name
try:
await attribute2.finish(
MessageSegment.image(file=f'https://static.cherishmoon.fun/LittlePaimon/blue/{name}.jpg'))
except SSLCertVerificationError:
await attribute2.finish(
MessageSegment.image(file=f'http://static.cherishmoon.fun/LittlePaimon/blue/{name}.jpg'))
await attribute2.finish(await MessageBuild.StaticImage(url=f'LittlePaimon/blue/{name}.jpg'))
else:
await attribute2.finish(f'没有找到{name}的收益曲线', at_sender=True)
@ -127,15 +111,12 @@ async def daily_material_handle(event: MessageEvent):
if week == "0":
await daily_material.finish('周日所有材料都可以刷哦!', at_sender=True)
elif week in ['1', '4']:
url = 'https://static.cherishmoon.fun/LittlePaimon/DailyMaterials/周一周四.jpg'
url = 'LittlePaimon/DailyMaterials/周一周四.jpg'
elif week in ['2', '5']:
url = 'https://static.cherishmoon.fun/LittlePaimon/DailyMaterials/周二周五.jpg'
url = 'LittlePaimon/DailyMaterials/周二周五.jpg'
else:
url = 'https://static.cherishmoon.fun/LittlePaimon/DailyMaterials/周三周六.jpg'
try:
await daily_material.finish(MessageSegment.image(file=url))
except SSLCertVerificationError:
await daily_material.finish(MessageSegment.image(file=url.replace('https', 'http')))
url = 'LittlePaimon/DailyMaterials/周三周六.jpg'
await daily_material.finish(await MessageBuild.StaticImage(url=url))
@abyss_rate.handle()
@ -156,9 +137,4 @@ async def abyss_team_handler(event: MessageEvent, reGroup=RegexDict()):
@exception_handler()
async def weapon_guide_handler(event: MessageEvent):
name: str = event.message.extract_plain_text().replace('武器攻略', '').strip()
try:
await weapon_guide.finish(
MessageSegment.image(file=f'https://static.cherishmoon.fun/LittlePaimon/WeaponGuild/{name}.png'))
except SSLCertVerificationError:
await weapon_guide.finish(
MessageSegment.image(file=f'http://static.cherishmoon.fun/LittlePaimon/WeaponGuild/{name}.png'))
await weapon_guide.finish(await MessageBuild.StaticImage(url=f'LittlePaimon/WeaponGuild/{name}.png'))

View File

@ -1,4 +1,3 @@
from utils import aiorequests
from utils.message_util import MessageBuild
blue = {
@ -60,6 +59,5 @@ blue = {
async def get_blue_pic(name):
for c in blue.items():
if c[0] == name:
img = await aiorequests.get_img(url=f'https://static.cherishmoon.fun/LittlePaimon/blue/{c[1][0]}.jpg', crop=(0, int(c[1][1][0]), 1080, int(c[1][1][1])))
return MessageBuild.Image(img)
return await MessageBuild.StaticImage(url=f'LittlePaimon/blue/{c[1][0]}.jpg', crop=(0, int(c[1][1][0]), 1080, int(c[1][1][1])))
return None

View File

@ -30,6 +30,36 @@ def auto_withdraw(seconds: int = -1):
# 缓存装饰器 ttl为过期时间 参数use_cache决定是否使用缓存默认为True
def cache(ttl=datetime.timedelta(hours=1)):
def wrap(func):
cache_data = {}
@functools.wraps(func)
def wrapped(*args, **kw):
nonlocal cache_data
bound = inspect.signature(func).bind(*args, **kw)
bound.apply_defaults()
ins_key = '|'.join(['%s_%s' % (k, v) for k, v in bound.arguments.items()])
default_data = {"time": None, "value": None}
data = cache_data.get(ins_key, default_data)
now = datetime.datetime.now()
if 'use_cache' not in kw:
kw['use_cache'] = True
if not kw['use_cache'] or not data['time'] or now - data['time'] > ttl:
try:
data['value'] = func(*args, **kw)
data['time'] = now
cache_data[ins_key] = data
except Exception as e:
raise e
return data['value']
return wrapped
return wrap
# 缓存装饰异步版
def AsyncCache(ttl=datetime.timedelta(hours=1)):
def wrap(func):
cache_data = {}

View File

@ -1,15 +1,21 @@
from pathlib import Path
from PIL import Image
from typing import Union, Optional, Tuple
import json
import requests
from pathlib import Path
from typing import Union, Optional, Tuple
from ssl import SSLCertVerificationError
from PIL import Image
from .decorator import cache
@cache()
def load_image(
path: Union[Path, str],
*,
size: Optional[Union[Tuple[int, int], float]] = None,
crop: Optional[Tuple[int, int, int, int]] = None,
mode: Optional[str] = 'RGB'
mode: Optional[str] = None,
use_cache: bool = True
):
img = Image.open(path)
if size:
@ -19,7 +25,8 @@ def load_image(
img = img.resize(size, Image.ANTIALIAS)
if crop:
img = img.crop(crop)
img = img.convert(mode)
if mode:
img = img.convert(mode)
return img
@ -34,6 +41,14 @@ def load_json(file: str = None, path: Union[Path, str] = None, encoding: str = '
return json.load(path.open('r', encoding=encoding))
def load_json_from_url(url: str):
try:
resp = requests.get(url)
except SSLCertVerificationError:
resp = requests.get(url.replace('https', 'http'))
return resp.json()
def save_json(data, file: str = None, path: Union[Path, str] = None, encoding: str = 'utf-8'):
if file and not path:
path = Path() / 'data' / 'LittlePaimon' / file

View File

@ -33,6 +33,30 @@ class MessageBuild:
img_b64 = 'base64://' + base64.b64encode(bio.getvalue()).decode()
return MessageSegment.image(img_b64)
@classmethod
async def StaticImage(cls,
url: str,
size: Optional[Tuple[int, int]] = None,
crop: Optional[Tuple[int, int, int, int]] = None,
quality: Optional[int] = 100,
mode: Optional[str] = 'RGB'
):
path = Path() / 'data' / url
if not path.exists():
path.parent.mkdir(parents=True, exist_ok=True)
img = await aiorequests.get_img(url='https://static.cherishmoon.fun/' + url, save_path=path)
else:
img = Image.open(path)
if size:
img = img.resize(size)
if crop:
img = img.crop(crop)
bio = BytesIO()
img = img.convert(mode)
img.save(bio, format='JPEG' if mode == 'RGB' else 'PNG', quality=quality)
img_b64 = 'base64://' + base64.b64encode(bio.getvalue()).decode()
return MessageSegment.image(img_b64)
@classmethod
def Text(cls, text: str) -> MessageSegment:
# TODO 过滤负面文本
@ -43,6 +67,16 @@ class MessageBuild:
# TODO 网络语音
return MessageSegment.record(path)
@classmethod
async def StaticRecord(cls, url: str) -> MessageSegment:
path = Path() / 'data' / url
if not path.exists():
path.parent.mkdir(parents=True, exist_ok=True)
resp = await aiorequests.get(url='https://static.cherishmoon.fun/' + url)
content = resp.content
path.write_bytes(content)
return MessageSegment.record(file=path)
async def get_at_target(msg):
for msg_seg in msg: