From 36a7cc1f5c43f4075b41536e8142da1b3558a958 Mon Sep 17 00:00:00 2001 From: CMHopeSunshine <277073121@qq.com> Date: Mon, 12 Jun 2023 19:29:56 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20`=E6=98=9F=E7=A9=B9=E9=93=81?= =?UTF-8?q?=E9=81=93`=E9=9D=A2=E6=9D=BF=E5=88=9D=E6=AD=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/star_rail_info/__init__.py | 87 ++++++ .../plugins/star_rail_info/data_handle.py | 59 ++++ LittlePaimon/plugins/star_rail_info/draw.py | 260 ++++++++++++++++++ LittlePaimon/plugins/star_rail_info/models.py | 240 ++++++++++++++++ LittlePaimon/utils/tool.py | 12 +- 5 files changed, 657 insertions(+), 1 deletion(-) create mode 100644 LittlePaimon/plugins/star_rail_info/__init__.py create mode 100644 LittlePaimon/plugins/star_rail_info/data_handle.py create mode 100644 LittlePaimon/plugins/star_rail_info/draw.py create mode 100644 LittlePaimon/plugins/star_rail_info/models.py diff --git a/LittlePaimon/plugins/star_rail_info/__init__.py b/LittlePaimon/plugins/star_rail_info/__init__.py new file mode 100644 index 0000000..7236971 --- /dev/null +++ b/LittlePaimon/plugins/star_rail_info/__init__.py @@ -0,0 +1,87 @@ +from nonebot import on_command +from nonebot.params import CommandArg +from nonebot.plugin import PluginMetadata +from nonebot.adapters.onebot.v11 import Message, MessageEvent + +from LittlePaimon.utils.message import MessageBuild +from .data_handle import set_uid, get_uid, update_info, get_info +from .draw import draw_character + + +__plugin_meta__ = PluginMetadata( + name='星穹铁道面板查询', + description='星穹铁道面板查询', + usage='...', + extra={ + 'author': '惜月', + 'version': '3.0', + 'priority': 6, + }, +) + +panel_cmd = on_command("星铁面板", aliases={"崩铁面板", "星穹铁道面板", "sr"}, priority=1, block=True, state={ + 'pm_name': '星穹铁道面板', + 'pm_description': '查询星穹铁道面板', + 'pm_usage': '星铁面板', + 'pm_priority': 1 +}) + + +update_cmd = on_command("更新星铁面板", aliases={"更新崩铁面板", "更新星穹铁道面板", "sr update"}, priority=1, block=True, state={ + 'pm_name': '星穹铁道面板更新', + 'pm_description': '绑定星穹面板更新', + 'pm_usage': '更新星铁面板 uid', + 'pm_priority': 2 +}) + +bind_cmd = on_command("星铁绑定", aliases={"崩铁绑定", "星穹铁道绑定", "srb", "绑定星铁", "绑定崩铁", "绑定星穹铁道"}, priority=1, block=True, state={ + 'pm_name': '星穹铁道绑定', + 'pm_description': '绑定星穹铁道uid', + 'pm_usage': '星铁绑定uid', + 'pm_priority': 3 +}) + +@panel_cmd.handle() +async def panel_cmd_handler(event: MessageEvent, args: Message = CommandArg()): + name = args.extract_plain_text().strip() + if not name: + await panel_cmd.finish("请给出要查询的角色名全称") + uid = get_uid(str(event.user_id)) + if not uid: + await panel_cmd.finish("请先使用命令[星铁绑定 uid]来绑定星穹铁道UID") + data = get_info(uid, name) + if not data: + await panel_cmd.finish("你还没有该角色的面板数据哦,请将该角色放在你的游戏主页中,使用命令[更新星铁面板]来更新") + try: + image = await draw_character(data, uid) + except Exception as e: + await panel_cmd.finish(f"绘制星穹铁道面板时出现了错误:{e}") + await panel_cmd.finish(MessageBuild.Image(image, quality=80, mode='RGB'), at_sender=True) + + + +@bind_cmd.handle() +async def bind_cmd_handler(event: MessageEvent, args: Message = CommandArg()): + uid = args.extract_plain_text().strip() + if not uid: + await bind_cmd.finish("请给出要绑定的uid") + if not (uid.isdigit() and len(uid) == 9): + await bind_cmd.finish("UID格式不对哦~") + set_uid(str(event.user_id), uid) + await bind_cmd.finish(f"成功绑定星铁UID{uid}", at_sender=True) + + +@update_cmd.handle() +async def update_cmd_handler(event: MessageEvent, args: Message = CommandArg()): + uid = args.extract_plain_text().strip() + if not uid: + uid = get_uid(str(event.user_id)) + elif not (uid.isdigit() and len(uid) == 9): + await update_cmd.finish("UID格式不对哦~") + if not uid: + await update_cmd.finish("请先绑定UID或在本命令后面加上UID") + set_uid(str(event.user_id), uid) + msg = await update_info(uid) + await update_cmd.finish(msg, at_sender=True) + + diff --git a/LittlePaimon/plugins/star_rail_info/data_handle.py b/LittlePaimon/plugins/star_rail_info/data_handle.py new file mode 100644 index 0000000..45a66b2 --- /dev/null +++ b/LittlePaimon/plugins/star_rail_info/data_handle.py @@ -0,0 +1,59 @@ +from typing import Optional +from LittlePaimon.utils.path import USER_DATA_PATH +from LittlePaimon.utils.files import load_json, save_json +from LittlePaimon.utils.requests import aiorequests + +from .models import Character + +API = "https://api.mihomo.me/sr_info_parsed/" + + +def set_uid(user_id: str, uid: str): + data = load_json(USER_DATA_PATH / "star_rail_uid.json") + data[user_id] = uid + save_json(data, USER_DATA_PATH / "star_rail_uid.json") + + +def get_uid(user_id: str) -> Optional[str]: + data = load_json(USER_DATA_PATH / "star_rail_uid.json") + return data.get(user_id) + + +async def update_info(uid: str) -> str: + try: + path = USER_DATA_PATH / "star_rail_info" / f"{uid}.json" + resp = await aiorequests.get( + API + uid, headers={"User-Agent": "LittlePaimon/3.0"}, follow_redirects=True + ) + data = resp.json() + if "player" not in data and "characters" not in data: + return "获取星穹铁道面板数据失败,请检查uid是否正确或者稍后再试" + if not path.exists(): + save_json(data, path) + else: + old_data = load_json(path) + old_data["player"] = data["player"] + # 如果旧数据和新数据都有相同ID的角色,就更新旧数据,否则就添加新数据 + for new_char in data["characters"]: + for old_char in old_data["characters"]: + if new_char["id"] == old_char["id"]: + old_char.update(new_char) + break + else: + old_data["characters"].append(new_char) + save_json(old_data, path) + new_char_name = " ".join([char["name"] for char in data["characters"]]) + return f"成功更新以下星穹铁道角色面板:\n{new_char_name}\n可以使用“星铁面板 角色名”命令查看面板" + except Exception as e: + return f"获取星穹铁道面板数据失败:{e}" + + +def get_info(uid: str, chara_name: str) -> Optional[Character]: + path = USER_DATA_PATH / "star_rail_info" / f"{uid}.json" + if not path.exists(): + return None + data = load_json(path) + for char in data["characters"]: + if char["name"] == chara_name: + return Character.parse_obj(char) + return None diff --git a/LittlePaimon/plugins/star_rail_info/draw.py b/LittlePaimon/plugins/star_rail_info/draw.py new file mode 100644 index 0000000..4439a49 --- /dev/null +++ b/LittlePaimon/plugins/star_rail_info/draw.py @@ -0,0 +1,260 @@ +import asyncio +from LittlePaimon.utils.image import PMImage, load_image +from LittlePaimon.utils.image import font_manager as fm +from LittlePaimon.utils.path import RESOURCE_BASE_PATH +from .models import Character, Relic, Element + +PATH = RESOURCE_BASE_PATH / "star_rail" + +LEVEL_COLOR = ["#404040", "#519d57", "#2f8dac", "#d16fe9", "#f5ad1e"] +ELEMENT_COLOR = { + "雷": "#d16fe9", + "冰": "#2f9de0", + "风": "#42c28c", + "火": "#e93d44", + "物理": "#8c8b8f", + "量子": "#723de8", + "虚数": "#ebca47", +} + + +async def draw_relic(relic: Relic, element: Element) -> PMImage: + # 背景 + bg = PMImage(await load_image(PATH / f"遗器-{element.name}.png")) + # 名称 + await bg.text(relic.name, 19, 12, fm.get("汉仪雅酷黑", 30), "white") + # 图标 + await bg.paste( + await load_image(PATH / "relic" / relic.icon.split("/")[-1], size=(106, 106)), + (4, 63), + ) + # 稀有度 + await bg.draw_rectangle((6, 138, 47, 160), LEVEL_COLOR[relic.rarity - 1]) + # 等级 + await bg.text( + f"+{relic.level}", + (6, 47), + (138, 160), + fm.get("bahnschrift_regular", 24), + "white", + "center", + ) + # 主属性名 + await bg.text( + relic.main_affix.name.rstrip("提高"), + 328, + 67, + fm.get("汉仪润圆", 36), + "#333333", + "right", + ) + # 主属性值 + await bg.text( + "+" + relic.main_affix.display, 328, 123, fm.get("汉仪润圆", 36), "#333333", "right" + ) + # 副属性 + for i, affix in enumerate(relic.sub_affix): + # 副属性名 + await bg.text(affix.name, 6, 178 + i * 56, fm.get("汉仪润圆", 36), "#333333") + # 副属性值 + await bg.text( + "+" + affix.display, + 328, + 178 + i * 56, + fm.get("汉仪润圆", 36), + "#333333", + "right", + ) + return bg + + +async def draw_character(chara: Character, uid: str): + # 背景 + bg = PMImage(await load_image(PATH / f"背景-{chara.element.name}.png")) + + # 等级 + await bg.text( + f"UID{uid} - Lv.{chara.level}", + 36, + 20, + fm.get("bahnschrift_regular", 36), + ELEMENT_COLOR[chara.element.name], + ) + + # 角色立绘 + pic = await load_image( + PATH / "character_portrait" / chara.portrait.split("/")[-1], + size=(1300, 1300), + crop=(338, 146, 886, 1176), + ) + await bg.paste(pic, (510, 28)) + await bg.paste(await load_image(PATH / f"立绘边框-{chara.element.name}.png"), (500, 13)) + + # 星魂图标 + circle = await load_image(PATH / "星魂圆.png") + circle_lock = await load_image(PATH / "星魂圆暗.png") + for i in range(6): + await bg.paste(circle, (524, 443 + i * 104)) + icon = PMImage( + await load_image( + PATH / "skill" / chara.rank_icons[i].split("/")[-1], size=(76, 76) + ) + ) + await bg.paste(icon, (536, 453 + i * 104)) + if i >= chara.rank: + await bg.paste(circle_lock, (524, 443 + i * 104)) + + # 星魂文字 + await bg.text( + f"星魂{chara.rank}", (388, 488), 17, fm.get("汉仪雅酷黑", 30), "white", "center" + ) + + # 角色名称 + await bg.text(chara.name, 480, (59, 154), fm.get("汉仪雅酷黑", 72), "white", "right") + + # 属性 + for i, attr in enumerate(("生命值", "攻击力", "防御力", "速度", "暴击率", "暴击伤害")): + base = next((a for a in chara.attributes if a.name == attr), None) + extra = next((a for a in chara.additions if a.name == attr), None) + if attr in ("暴击率", "暴击伤害"): + n = "0%" + total = ( + str( + round( + ((base.value if base else 0) + (extra.value if extra else 0)) + * 100, + 1, + ) + ) + + "%" + ) + else: + n = "0" + total = str( + int((base.value if base else 0) + (extra.value if extra else 0)) + ) + + await bg.text( + total, + 400, + 180 + i * 56, + fm.get("bahnschrift_regular", 36), + "#333333", + "right", + ) + await bg.text( + base.display if base else n, + 483, + 175 + i * 56, + fm.get("bahnschrift_regular", 24), + "#333333", + "right", + ) + await bg.text( + "+" + (extra.display if extra else n), + 483, + 196 + i * 56, + fm.get("bahnschrift_regular", 24), + "#5a9922", + "right", + ) + + for i, attr in enumerate( + ("效果抵抗", "效果命中", "击破特攻", "能量恢复效率", f"{chara.element.name}属性伤害提高") + ): + affix = next((a for a in chara.properties if a.name == attr), None) + + if affix is None: + value = "0%" if attr != "能量恢复效率" else "100%" + else: + value = ( + affix.display + if attr != "能量恢复效率" + else (str(round((1 + affix.value) * 100, 1)) + "%") + ) + await bg.text( + value, + 483, + 516 + i * 56, + fm.get("bahnschrift_regular", 36), + "#333333", + "right", + ) + + # 光锥图标 + await bg.paste( + await load_image( + PATH / "light_cone" / chara.light_cone.icon.split("/")[-1], size=(96, 96) + ), + (24, 802), + ) + + # 光锥稀有度 + await bg.paste( + await load_image(PATH / f"光锥{chara.light_cone.rarity}星.png"), (123, 813) + ) + + # 光锥名称 + await bg.text(chara.light_cone.name, 138, 847, fm.get("汉仪雅酷黑", 30), "#333333") + + # 光锥等级 + await bg.draw_rectangle((279, 813, 346, 841), ELEMENT_COLOR[chara.element.name]) + await bg.text( + f"lv.{chara.light_cone.level}", + (279, 346), + (813, 841), + fm.get("bahnschrift_regular", 30), + "white", + "center", + ) + + # 光锥叠影 + await bg.draw_rectangle( + (353, 813, 427, 841), LEVEL_COLOR[chara.light_cone.rank - 1] + ) + await bg.text( + f"叠影{chara.light_cone.rank}", + (353, 427), + (813, 841), + fm.get("汉仪雅酷黑", 24), + "white", + "center", + ) + + # 行迹 + for i, skill in enumerate(chara.skills[:4]): + # 图标 + await bg.paste( + await load_image(PATH / "skill" / skill.icon.split("/")[-1], size=(70, 70)), + (50 + 113 * i, 962), + ) + # 等级 + await bg.draw_rectangle( + (65 + 113 * i, 1024, 104 + 113 * i, 1056), + LEVEL_COLOR[(skill.level // 2 - 1) if skill.level < 10 else 5], + ) + await bg.text( + str(skill.level), + (65 + 113 * i, 104 + 113 * i), + 1021, + fm.get("汉仪雅酷黑", 30), + "white", + "center", + ) + + # 遗器 + await asyncio.gather( + *[ + bg.paste( + await draw_relic(relic, chara.element), + ((19 + (i % 3) * 353, (1131 if i < 3 else 1537))), + ) + for i, relic in enumerate(chara.relics) + ] + ) + + # 其他文字 + await bg.text("CREATED BY LITTLEPAIMON", 20, 1078, fm.get("汉仪雅酷黑", 30), "#252525") + await bg.text("数据源 MiHoMo", 1060, 1078, fm.get("汉仪雅酷黑", 30), "#252525", "right") + + return bg diff --git a/LittlePaimon/plugins/star_rail_info/models.py b/LittlePaimon/plugins/star_rail_info/models.py new file mode 100644 index 0000000..1df4e98 --- /dev/null +++ b/LittlePaimon/plugins/star_rail_info/models.py @@ -0,0 +1,240 @@ +from typing import List, Optional +from enum import Enum +from pydantic import BaseModel, Field + + +class Avatar(BaseModel): + id: str + name: str + icon: str + + +class ChallengeData(BaseModel): + maze_group_id: int + maze_group_index: int + pre_maze_group_index: int + +class SpaceInfo(BaseModel): + challenge_data: ChallengeData + pass_area_progress: int + light_cone_count: int + avatar_count: int + achievement_count: int + + +class Player(BaseModel): + uid: str + nickname: str + level: int + world_level: int + friend_count: int + avatar: Avatar + signature: str + is_display: bool + space_info: SpaceInfo + + +class Element(BaseModel): + id: str + name: str + color: str + icon: str + +class Path(BaseModel): + id: str + name: str + icon: str + +class SkillType(str, Enum): + Normal = "Normal" + """普攻""" + BPSkill = "BPSkill" + """战技""" + Ultra = "Ultra" + """终结技""" + Talent = "Talent" + """天赋""" + MazeNormal = "MazeNormal" + """dev_连携""" + Maze = "Maze" + """秘技""" + + +class Skill(BaseModel): + id: str + name: str + level: int + max_level: int + element: Optional[Element] + type: SkillType + type_text: str + effect: str + simple_desc: str + desc: str + icon: str + + +class SkillTree(BaseModel): + id: str + level: int + icon: str + + +class Attribute(BaseModel): + field: str + name: str + icon: str + value: float + display: str + percent: bool + +class Property(BaseModel): + type: str + field: str + name: str + icon: str + value: float + display: str + percent: bool + + +class LightCone(BaseModel): + id: str + name: str + rarity: int + rank: int + level: int + promotion: int + icon: str + preview: str + portrait: str + path: Path + attributes: List[Attribute] + properties: List[Property] + + +class RelicAffix(BaseModel): + type: str + field: str + name: str + icon: str + value: float + display: str + percent: bool + + +class Relic(BaseModel): + id: str + name: str + set_id: str + set_name: str + rarity: int + level: int + icon: str + main_affix: RelicAffix + sub_affix: List[RelicAffix] + + +class RelicSet(BaseModel): + id: str + name: str + icon: str + num: int + desc: str + properties: List[Property] + + +class Character(BaseModel): + id: str + name: str + rarity: int + rank: int + level: int + promotion: int + icon: str + preview: str + portrait: str + rank_icons: List[str] + path: Path + element: Element + skills: List[Skill] + skill_trees: List[SkillTree] + light_cone: LightCone + relics: List[Relic] + relic_sets: List[RelicSet] + attributes: List[Attribute] + additions: List[Attribute] + properties: List[Property] + + +class StarRailInfo(BaseModel): + player: Player + characters: List[Character] + + +# class SubAffix(BaseModel): +# affix_id: int = Field(alias="affixId") +# cnt: int +# step: Optional[int] + + +# class Relic(BaseModel): +# exp: Optional[int] +# type: int +# tid: int +# sub_affix_list: List[SubAffix] = Field(alias="subAffixList") +# level: int +# main_affix_id: int = Field(alias="mainAffixId") + + +# class SkillTree(BaseModel): +# point_id: int +# level: int + + +# class Equipment(BaseModel): +# level: int +# tid: int +# promotion: int +# rank: int + + +# class AvatarDetail(BaseModel): +# pos: Optional[int] +# avatar_id: int = Field(alias="avatarId") +# promotion: int +# skill_tree_list: List[SkillTree] = Field(alias="skillTreeList") +# relic_list: List = Field(alias="relicList") +# equipment: Equipment +# rank: Optional[int] +# level: int + + + +# class ChallengeInfo(BaseModel): +# schedule_max_level: int = Field(alias="scheduleMaxLevel") +# schedule_group_id: int = Field(alias="scheduleGroupId") +# none_schedule_max_level: int = Field(alias="noneScheduleMaxLevel") + + +# class RecordInfo(BaseModel): +# achievement_count: int = Field(alias="achievementCount") +# challenge_info: ChallengeInfo = Field(alias="challengeInfo") +# equipment_count: int = Field(alias="equipmentCount") +# max_rogue_challenge_score: int = Field(alias="maxRogueChallengeScore") +# avatar_count: int = Field(alias="avatarCount") + + +# class StarRailInfo(BaseModel): +# world_level: int = Field(alias="worldLevel") +# platform: str +# friend_count: int = Field(alias="friendCount") +# signature: str +# is_display_list: bool = Field(alias="isDisplayList") +# avatar_detail_list: List[AvatarDetail] = Field(alias="avatarDetailList") +# record_info: RecordInfo = Field(alias="recordInfo") +# head_icon: int = Field(alias="headIcon") +# nickname: str +# assist_avatar_detail: AvatarDetail = Field(alias="assistAvatarDetail") +# level: int +# uid: int \ No newline at end of file diff --git a/LittlePaimon/utils/tool.py b/LittlePaimon/utils/tool.py index 7534d85..8a3f078 100644 --- a/LittlePaimon/utils/tool.py +++ b/LittlePaimon/utils/tool.py @@ -105,8 +105,18 @@ async def check_resource(): (RESOURCE_BASE_PATH / '原神图标资源.zip').unlink() logger.info('资源检查', '资源下载完成') except Exception: - logger.warning('资源检查', '下载资源出错,请尝试更换github资源地址') + logger.warning('资源检查', '下载资源包出错,请尝试更换github资源地址') else: + if not (RESOURCE_BASE_PATH / 'LittlePaimon' / 'star_rail').is_dir(): + try: + await aiorequests.download( + url=f'{config.github_proxy}https://raw.githubusercontent.com/CMHopeSunshine/LittlePaimonRes/main/resources/star_rail.zip', + save_path=RESOURCE_BASE_PATH / 'star_rail.zip') + zipfile.ZipFile(RESOURCE_BASE_PATH / 'star_rail.zip').extractall(RESOURCE_BASE_PATH / 'LittlePaimon') + (RESOURCE_BASE_PATH / 'star_rail.zip').unlink() + logger.info('资源检查', '星穹铁道相关资源下载完成') + except Exception: + logger.warning('资源检查', '下载星穹铁道资源出错,请尝试更换github资源地址') try: resource_list = await aiorequests.get( f'{config.github_proxy}https://raw.githubusercontent.com/CMHopeSunshine/LittlePaimonRes/main/resources_list.json', From 5f23420e965501f28d7df3934701cc992d5a47c9 Mon Sep 17 00:00:00 2001 From: CMHopeSunshine <277073121@qq.com> Date: Mon, 12 Jun 2023 20:11:33 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20typo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LittlePaimon/utils/tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LittlePaimon/utils/tool.py b/LittlePaimon/utils/tool.py index 8a3f078..415bfdf 100644 --- a/LittlePaimon/utils/tool.py +++ b/LittlePaimon/utils/tool.py @@ -110,7 +110,7 @@ async def check_resource(): if not (RESOURCE_BASE_PATH / 'LittlePaimon' / 'star_rail').is_dir(): try: await aiorequests.download( - url=f'{config.github_proxy}https://raw.githubusercontent.com/CMHopeSunshine/LittlePaimonRes/main/resources/star_rail.zip', + url=f'{config.github_proxy}https://raw.githubusercontent.com/CMHopeSunshine/LittlePaimonRes/main/star_rail.zip', save_path=RESOURCE_BASE_PATH / 'star_rail.zip') zipfile.ZipFile(RESOURCE_BASE_PATH / 'star_rail.zip').extractall(RESOURCE_BASE_PATH / 'LittlePaimon') (RESOURCE_BASE_PATH / 'star_rail.zip').unlink() From 1497ef12e16e48486119fe5b44984bbee4c93fd2 Mon Sep 17 00:00:00 2001 From: CMHopeSunshine <277073121@qq.com> Date: Mon, 12 Jun 2023 20:17:20 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20typo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LittlePaimon/utils/tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LittlePaimon/utils/tool.py b/LittlePaimon/utils/tool.py index 415bfdf..a7eb963 100644 --- a/LittlePaimon/utils/tool.py +++ b/LittlePaimon/utils/tool.py @@ -112,7 +112,7 @@ async def check_resource(): await aiorequests.download( url=f'{config.github_proxy}https://raw.githubusercontent.com/CMHopeSunshine/LittlePaimonRes/main/star_rail.zip', save_path=RESOURCE_BASE_PATH / 'star_rail.zip') - zipfile.ZipFile(RESOURCE_BASE_PATH / 'star_rail.zip').extractall(RESOURCE_BASE_PATH / 'LittlePaimon') + zipfile.ZipFile(RESOURCE_BASE_PATH / 'star_rail.zip').extractall(RESOURCE_BASE_PATH / 'LittlePaimon' / 'star_rail') (RESOURCE_BASE_PATH / 'star_rail.zip').unlink() logger.info('资源检查', '星穹铁道相关资源下载完成') except Exception: