diff --git a/LittlePaimon/manager/bot_manager/handler.py b/LittlePaimon/manager/bot_manager/handler.py index cfd3964..c04cd6c 100644 --- a/LittlePaimon/manager/bot_manager/handler.py +++ b/LittlePaimon/manager/bot_manager/handler.py @@ -1,3 +1,4 @@ +import datetime from pathlib import Path import git from nonebot.utils import run_sync @@ -25,7 +26,8 @@ async def check_update(): return f'当前已是最新版本:{__version__}' result = '检查到更新,日志如下:\n' for i, commit in enumerate(remote_commit, start=1): - result += f'{i}.{commit["commit"]["committer"]["date"].replace("T", " ").replace("Z", "")}\n' + commit['commit']['message'].replace(':bug:', '🐛').replace( + time_str = (datetime.datetime.strptime(commit['commit']['committer']['date'], '%Y-%m-%dT%H:%M:%SZ') + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') + result += f'{i}.{time_str}\n' + commit['commit']['message'].replace(':bug:', '🐛').replace( ':sparkles:', '✨').replace(':memo:', '📝') + '\n' return result diff --git a/LittlePaimon/plugins/Paimon_Wiki/__init__.py b/LittlePaimon/plugins/Paimon_Wiki/__init__.py index 378fe38..ed72570 100644 --- a/LittlePaimon/plugins/Paimon_Wiki/__init__.py +++ b/LittlePaimon/plugins/Paimon_Wiki/__init__.py @@ -16,6 +16,7 @@ from LittlePaimon.utils.message import MessageBuild from LittlePaimon.database.models import PlayerAlias from LittlePaimon.config import RESOURCE_BASE_PATH from .draw_map import init_map, draw_map, get_full_map +from .draw_daily_material import draw_material # from .abyss_rate_draw import draw_rate_rank, draw_teams_rate @@ -86,31 +87,28 @@ generate_map = on_command('生成地图', priority=1, block=True, permission=SUP @daily_material.handle() async def _(event: MessageEvent, regex_dict: dict = RegexDict()): + await daily_material.send('开始获取每日材料,请稍候...') if regex_dict['day'] in ['今日', '今天', '现在']: day = time.strftime("%w") elif regex_dict['day'] in ['明日', '明天']: day = str(int(time.strftime("%w")) + 1) elif regex_dict['day'] in ['后日', '后天']: day = str(int(time.strftime("%w")) + 2) - elif regex_dict['day'] in ['周一', '周四']: - day = '1' - elif regex_dict['day'] in ['周二', '周五']: - day = '2' - elif regex_dict['day'] in ['周三', '周六']: - day = '3' - else: - day = '0' - if day == "0": + elif regex_dict['day'] == '周日': + await daily_material.finish('周日所有材料都可以刷哦!', at_sender=True) + elif regex_dict['day'].startswith('周'): + await daily_material.finish(await draw_material(regex_dict['day'])) + if day == '0': await daily_material.finish('周日所有材料都可以刷哦!', at_sender=True) - elif day in ['1', '4']: - await daily_material.finish( - MessageSegment.image(file='https://static.cherishmoon.fun/LittlePaimon/DailyMaterials/周一周四.jpg')) - elif day in ['2', '5']: - await daily_material.finish( - MessageSegment.image(file='https://static.cherishmoon.fun/LittlePaimon/DailyMaterials/周二周五.jpg')) else: - await daily_material.finish( - MessageSegment.image(file='https://static.cherishmoon.fun/LittlePaimon/DailyMaterials/周三周六.jpg')) + await daily_material.finish(await draw_material({ + '1': '周一', + '2': '周二', + '3': '周三', + '4': '周四', + '5': '周五', + '6': '周六', + }[day]), at_sender=True) @material_map.handle() @@ -164,7 +162,9 @@ async def _(event: MessageEvent, map_: str = Arg('map'), names=Arg('names')): if isinstance(names, Message): names = names.extract_plain_text().split(' ') if not freq_limiter.check(f'材料地图_{event.group_id if isinstance(event, GroupMessageEvent) else event.user_id}'): - await material_map_full.finish(f'材料地图查询冷却中,剩余{freq_limiter.left(f"材料地图_{event.group_id if isinstance(event, GroupMessageEvent) else event.user_id}")}秒', at_sender=True) + await material_map_full.finish( + f'材料地图查询冷却中,剩余{freq_limiter.left(f"材料地图_{event.group_id if isinstance(event, GroupMessageEvent) else event.user_id}")}秒', + at_sender=True) freq_limiter.start(f'材料地图_{event.group_id if isinstance(event, GroupMessageEvent) else event.user_id}', 15) if len(names) > 3: names = names[:3] diff --git a/LittlePaimon/plugins/Paimon_Wiki/draw_daily_material.py b/LittlePaimon/plugins/Paimon_Wiki/draw_daily_material.py new file mode 100644 index 0000000..8c7c783 --- /dev/null +++ b/LittlePaimon/plugins/Paimon_Wiki/draw_daily_material.py @@ -0,0 +1,116 @@ +import math +from pathlib import Path +from LittlePaimon.config import RESOURCE_BASE_PATH +from LittlePaimon.utils import aiorequests, scheduler +from LittlePaimon.utils.files import save_json, load_json, load_image +from LittlePaimon.utils.image import PMImage, font_manager as fm +from LittlePaimon.utils.message import MessageBuild + +week_cn = { + 'monday': '周一', + 'tuesday': '周二', + 'wednesday': '周三', + 'thursday': '周四', + 'friday': '周五', + 'saturday': '周六', +} + +MATERIAL_URL = 'https://api.ambr.top/v2/chs/material' +CHARACTER_URL = 'https://api.ambr.top/v2/chs/avatar' +WEAPON_URL = 'https://api.ambr.top/v2/chs/weapon' +DAILY_URL = 'https://api.ambr.top/v2/chs/dailyDungeon' +UPGRADE_URL = 'https://api.ambr.top/v2/static/upgrade' + + +async def get_daily_material(): + daily_info = { + '天赋': {}, + '武器': {} + } + daily_data = (await aiorequests.get(DAILY_URL)).json()['data'] + material_data = (await aiorequests.get(MATERIAL_URL)).json()['data'] + upgrade_data = (await aiorequests.get(UPGRADE_URL)).json()['data'] + for week in daily_data: + if week == 'sunday': + continue + daily_info['天赋'][week_cn[week]], daily_info['武器'][week_cn[week]] = {}, {} + domain_data = daily_data[week] + domain_data_sort = sorted(domain_data, key=lambda x: domain_data[x]['city']) + for domain_key in domain_data_sort: + item_type = 'avatar' if domain_data[domain_key]['name'].startswith('精通秘境') else 'weapon' + material = material_data['items'][str(domain_data[domain_key]['reward'][-1])] + used = [upgrade_data[item_type][id] for id in upgrade_data[item_type] if + str(material['id']) in upgrade_data[item_type][id]['items'] and 'Player' not in + upgrade_data[item_type][id]['icon']] + daily_info['天赋' if item_type == 'avatar' else '武器'][week_cn[week]][ + f'{material["name"]}-{material["icon"]}'] = [f'{u["rank"]}{u["icon"]}' for u in used] + save_json(daily_info, Path() / 'data' / 'LittlePaimon' / 'daily_material.json') + + +async def draw_material(week: str = '周一'): + if not (Path() / 'data' / 'LittlePaimon' / 'daily_material.json').exists(): + await get_daily_material() + if week in {'周一', '周四'}: + week_str = '周一/周四' + elif week in {'周二', '周五'}: + week_str = '周二/周五' + else: + week_str = '周三/周六' + daily_info = load_json(Path() / 'data' / 'LittlePaimon' / 'daily_material.json') + avatar = daily_info['天赋'][week] + weapon = daily_info['武器'][week] + total_height = max(70 * len(avatar) + sum(math.ceil(len(items) / 5) * 140 for items in avatar.values()), + 70 * len(weapon) + sum(math.ceil(len(items) / 5) * 140 for items in weapon.values())) + 165 + img = PMImage(RESOURCE_BASE_PATH / 'general' / 'bg.png') + await img.stretch((50, img.width - 50), 1520, 'width') + await img.stretch((50, img.height - 50), total_height - 100, 'height') + frame = await load_image(RESOURCE_BASE_PATH / 'general' / 'frame.png') + await img.paste(frame, (190, 62)) + await img.paste(frame, (1000, 62)) + await img.text(f'{week_str}角色天赋材料', 223, 69, fm.get('SourceHanSerifCN-Bold.otf', 35), 'black') + await img.text(f'{week_str}武器突破材料', 1033, 69, fm.get('SourceHanSerifCN-Bold.otf', 35), 'black') + star_bg = { + '3': await load_image(RESOURCE_BASE_PATH / 'icon' / 'star3.png', size=(110, 110)), + '4': await load_image(RESOURCE_BASE_PATH / 'icon' / 'star4.png', size=(110, 110)), + '5': await load_image(RESOURCE_BASE_PATH / 'icon' / 'star5.png', size=(110, 110)) + } + now_height = 165 + for name, items in avatar.items(): + name, icon = name.split('-') + await img.paste(await load_image(RESOURCE_BASE_PATH / 'icon' / 'star5.png', size=(60, 60)), (90, now_height)) + await img.paste(await load_image(RESOURCE_BASE_PATH / 'material' / f'{icon}.png', size=(60, 60)), + (90, now_height)) + await img.text(name, 165, now_height + 5, fm.get('SourceHanSerifCN-Bold.otf', 30), 'black') + now_height += 70 + items.sort(key=lambda x: int(x[0]), reverse=True) + for i in range(len(items)): + star = items[i][0] + icon = items[i][1:] + await img.paste(star_bg[star], (90 + 128 * (i % 5), now_height + 125 * int(i / 5))) + await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(110, 110)), + (90 + 128 * (i % 5), now_height + 125 * int(i / 5))) + now_height += math.ceil(len(items) / 5) * 125 + 15 + now_height = 165 + for name, items in weapon.items(): + name, icon = name.split('-') + await img.paste(await load_image(RESOURCE_BASE_PATH / 'icon' / 'star5.png', size=(60, 60)), (908, now_height)) + await img.paste(await load_image(RESOURCE_BASE_PATH / 'material' / f'{icon}.png', size=(60, 60)), + (908, now_height)) + await img.text(name, 983, now_height + 5, fm.get('SourceHanSerifCN-Bold.otf', 30), 'black') + now_height += 70 + items.sort(key=lambda x: int(x[0]), reverse=True) + for i in range(len(items)): + star = items[i][0] + icon = items[i][1:] + await img.paste(star_bg[star], (908 + 128 * (i % 5), now_height + 125 * int(i / 5))) + await img.paste(await load_image(RESOURCE_BASE_PATH / 'weapon' / f'{icon}.png', size=(110, 110)), + (908 + 128 * (i % 5), now_height + 125 * int(i / 5))) + now_height += math.ceil(len(items) / 5) * 125 + 15 + await img.text('CREATED BY LITTLEPAIMON', (0, img.width), img.height - 83, + fm.get('bahnschrift_bold', 44, 'Bold'), '#3c3c3c', align='center') + + return MessageBuild.Image(img, mode='RGB', quality=80) + +@scheduler.scheduled_job('cron', hour=7, misfire_grace_time=10) +async def update_daily_material(): + await get_daily_material() \ No newline at end of file diff --git a/LittlePaimon/utils/files.py b/LittlePaimon/utils/files.py index db9fb57..142d50d 100644 --- a/LittlePaimon/utils/files.py +++ b/LittlePaimon/utils/files.py @@ -39,13 +39,7 @@ async def load_image( if path.exists(): img = Image.open(path) elif path.name.startswith(('UI_', 'Skill_')): - try: - img = await aiorequests.get_img(f'https://enka.network/ui/{path.name}', headers=headers, save_path=path, follow_redirects=True) - except Exception: - try: - img = await aiorequests.get_img(f'https://file.minigg.icu/genshin/ui/{path.name}', headers=headers, save_path=path, follow_redirects=True) - except Exception as e: - raise FileNotFoundError(f'{path} not found') from e + img = await aiorequests.download_icon(path.name, headers=headers, save_path=path, follow_redirects=True) else: raise FileNotFoundError(f'{path} not found') cache_image[str(path)] = img diff --git a/LittlePaimon/utils/requests.py b/LittlePaimon/utils/requests.py index 93b7808..18fa2b4 100644 --- a/LittlePaimon/utils/requests.py +++ b/LittlePaimon/utils/requests.py @@ -1,3 +1,4 @@ +import contextlib from io import BytesIO from pathlib import Path from ssl import SSLCertVerificationError @@ -145,3 +146,24 @@ class aiorequests: colour='green'): f.write(chunk) f.close() + + @staticmethod + async def download_icon(name: str, + headers: Optional[Dict[str, str]] = None, + save_path: Optional[Union[str, Path]] = None, + **kwargs): + """ + 下载icon + :param name: url + :param headers: 请求头 + :param save_path: 保存路径 + """ + urls = [ + f'https://file.minigg.icu/genshin/ui/{name}', + f'https://api.ambr.top/assets/UI/{name}', + f'https://enka.network/ui/{name}' + ] + for url in urls: + with contextlib.suppress(Exception): + return await aiorequests.get_img(url=url, headers=headers, save_path=save_path, **kwargs) + raise FileNotFoundError(f'{name}下载失败,请检查网络')