diff --git a/core/template/services.py b/core/template/services.py index 37584b09..9dc3bbde 100644 --- a/core/template/services.py +++ b/core/template/services.py @@ -1,6 +1,6 @@ import os import time -from typing import Optional, Dict +from typing import Dict, Optional from jinja2 import Environment, PackageLoader, Template from playwright.async_api import ViewportSize @@ -65,7 +65,7 @@ class TemplateService: viewport: ViewportSize = None, full_page: bool = True, evaluate: Optional[str] = None, - query_selector: str = None, + query_selector: str = None ) -> bytes: """模板渲染成图片 :param template_path: 模板目录 diff --git a/metadata/genshin.py b/metadata/genshin.py index 01552b0b..ef1cac81 100644 --- a/metadata/genshin.py +++ b/metadata/genshin.py @@ -19,6 +19,7 @@ __all__ = [ "ARTIFACT_DATA", "NAMECARD_DATA", "honey_id_to_game_id", + "game_id_to_role_id", "Data", ] @@ -91,3 +92,10 @@ NAMECARD_DATA: dict[str, dict[str, int | str]] = Data("namecard") @functools.lru_cache() def honey_id_to_game_id(honey_id: str, item_type: str) -> str | None: return next((key for key, value in HONEY_DATA[item_type].items() if value[0] == honey_id), None) + + +@functools.lru_cache +def game_id_to_role_id(gid: str) -> int | None: + return next( + (int(key.split("-")[0]) for key, value in AVATAR_DATA.items() if value["icon"].split("_")[-1] == gid), None + ) diff --git a/metadata/shortname.py b/metadata/shortname.py index 14094657..432cd2d2 100644 --- a/metadata/shortname.py +++ b/metadata/shortname.py @@ -217,6 +217,7 @@ roles = { 10000051: ["优菈", "Eula", "eula", "优拉", "尤拉", "尤菈", "浪花骑士", "记仇", "劳伦斯"], 10000052: [ "雷电将军", + "Shougun", "Raiden Shogun", "Raiden", "raiden", diff --git a/plugins/genshin/abyss.py b/plugins/genshin/abyss.py index 3963ab55..24514595 100644 --- a/plugins/genshin/abyss.py +++ b/plugins/genshin/abyss.py @@ -1,9 +1,17 @@ -from typing import Dict, Optional +"""深渊数据查询""" +import asyncio +import re +from datetime import datetime +from functools import lru_cache, partial +from typing import List, Match, Optional, Tuple +import ujson as json +from arkowrapper import ArkoWrapper from genshin import Client -from telegram import Update -from telegram.constants import ChatAction -from telegram.ext import CallbackContext, CommandHandler, MessageHandler, filters +from pytz import timezone +from telegram import InlineKeyboardButton, InlineKeyboardMarkup, InputMediaPhoto, Update +from telegram.constants import ChatAction, ParseMode +from telegram.ext import CallbackContext, filters from core.base.assets import AssetsService from core.baseplugin import BasePlugin @@ -13,23 +21,51 @@ from core.plugin import Plugin, handler from core.template import TemplateService from core.user import UserService from core.user.error import UserNotFoundError +from metadata.genshin import game_id_to_role_id from utils.decorators.error import error_callable from utils.decorators.restricts import restricts -from utils.helpers import get_genshin_client, get_public_genshin_client +from utils.helpers import async_re_sub, get_genshin_client, get_public_genshin_client from utils.log import logger +TZ = timezone("Asia/Shanghai") +cmd_pattern = r"^/abyss\s*((?:\d+)|(?:all))?\s*(pre)?" +msg_pattern = r"^深渊数据((?:查询)|(?:总览))(上期)?\D?(\d*)?.*?$" + +regex_01 = r"['\"]icon['\"]:\s*['\"](.*?)['\"]" +regex_02 = r"['\"]side_icon['\"]:\s*['\"](.*?)['\"]" + + +async def replace_01(match: Match, assets_service: AssetsService) -> str: + aid = game_id_to_role_id(re.findall(r"UI_AvatarIcon_(.*?).png", match.group(1))[0]) + return (await assets_service.avatar(aid).icon()).as_uri() + + +async def replace_02(match: Match, assets_service: AssetsService) -> str: + aid = game_id_to_role_id(re.findall(r"UI_AvatarIcon_Side_(.*?).png", match.group(1))[0]) + return (await assets_service.avatar(aid).side()).as_uri() + + +@lru_cache +def get_args(text: str) -> Tuple[int, bool, bool]: + if text.startswith("/"): + result = re.match(cmd_pattern, text).groups() + try: + floor = int(result[0] or 0) + except ValueError: + floor = 0 + return floor, result[0] == "all", bool(result[1]) + else: + result = re.match(msg_pattern, text).groups() + return int(result[2] or 0), result[0] == "总览", result[1] == "上期" + class AbyssUnlocked(Exception): """根本没动""" - pass - class NoMostKills(Exception): """挑战了但是数据没刷新""" - pass - class Abyss(Plugin, BasePlugin): """深渊数据查询""" @@ -46,95 +82,245 @@ class Abyss(Plugin, BasePlugin): self.user_service = user_service self.assets_service = assets_service - @staticmethod - def _get_role_star_bg(value: int): - if value == 4: - return "./background/roleStarBg4.png" - elif value == 5: - return "./background/roleStarBg5.png" - else: - raise ValueError("错误的数据") - - async def _get_abyss_data(self, client: Client, uid: Optional[int] = None) -> Dict: - if uid is None: - _uid = client.uid - await client.get_record_cards() - else: - _uid = uid - spiral_abyss_info = await client.get_spiral_abyss(_uid) - if not spiral_abyss_info.unlocked: - raise AbyssUnlocked - ranks = spiral_abyss_info.ranks - if len(spiral_abyss_info.ranks.most_kills) == 0: - raise NoMostKills - abyss_data = { - "uid": _uid, - "max_floor": spiral_abyss_info.max_floor, - "total_battles": spiral_abyss_info.total_battles, - "total_stars": spiral_abyss_info.total_stars, - "most_played_list": [], - "most_kills": { - "icon": await self.assets_service.avatar(ranks.most_kills[0].id).side(), - "value": ranks.most_kills[0].value, - }, - "strongest_strike": { - "icon": await self.assets_service.avatar(ranks.strongest_strike[0].id).side(), - "value": ranks.strongest_strike[0].value, - }, - "most_damage_taken": { - "icon": await self.assets_service.avatar(ranks.most_damage_taken[0].id).side(), - "value": ranks.most_damage_taken[0].value, - }, - "most_bursts_used": { - "icon": await self.assets_service.avatar(ranks.most_bursts_used[0].id).side(), - "value": ranks.most_bursts_used[0].value, - }, - "most_skills_used": { - "icon": await self.assets_service.avatar(ranks.most_skills_used[0].id).side(), - "value": ranks.most_skills_used[0].value, - }, - } - # most_kills - most_played_list = ranks.most_played - for most_played in most_played_list: - temp = { - "icon": await self.assets_service.avatar(most_played.id).icon(), - "value": most_played.value, - "background": self._get_role_star_bg(most_played.rarity), - } - abyss_data["most_played_list"].append(temp) - return abyss_data - - @handler(CommandHandler, command="abyss", block=False) - @handler(MessageHandler, filters=filters.Regex("^深渊数据查询(.*)"), block=False) + @handler.command("abyss", block=False) + @handler.message(filters.Regex(msg_pattern), block=False) @restricts() @error_callable async def command_start(self, update: Update, context: CallbackContext) -> None: user = update.effective_user message = update.effective_message - logger.info(f"用户 {user.full_name}[{user.id}] 查深渊挑战命令请求") - await message.reply_chat_action(ChatAction.TYPING) - try: - try: - client = await get_genshin_client(user.id) - abyss_data = await self._get_abyss_data(client) - except CookiesNotFoundError: - client, uid = await get_public_genshin_client(user.id) - abyss_data = await self._get_abyss_data(client, uid) - except UserNotFoundError: - reply_message = await message.reply_text("未查询到账号信息,请先私聊派蒙绑定账号") + + # 若查询帮助 + if (message.text.startswith("/") and "help" in message.text) or "帮助" in message.text: + await message.reply_text( + "深渊挑战数据功能使用帮助(中括号表示可选参数)\n\n" + "指令格式:\n/abyss + [层数/all] + [pre]\n(pre表示上期)\n\n" + "文本格式:\n深渊数据 + 查询/总览 + [上期] + [层数] \n\n" + "例如以下指令都正确:\n" + "/abyss\n/abyss 12 pre\n/abyss all pre\n" + "深渊数据查询\n深渊数据查询上期第12层\n深渊数据总览上期", + parse_mode=ParseMode.HTML, + ) + logger.info(f"用户 {user.full_name}[{user.id}] 查询[bold]深渊挑战数据[/bold]帮助", extra={"markup": True}) + return + + # 解析参数 + floor, total, previous = get_args(message.text) + + if floor > 12 or floor < 0: + reply_msg = await message.reply_text("深渊层数输入错误,请重新输入") if filters.ChatType.GROUPS.filter(message): - self._add_delete_message_job(context, reply_message.chat_id, reply_message.message_id, 10) + self._add_delete_message_job(context, reply_msg.chat_id, reply_msg.message_id, 10) self._add_delete_message_job(context, message.chat_id, message.message_id, 10) return - except TooManyRequestPublicCookies: - await message.reply_text("用户查询次数过多 请稍后重试") - return - except (AbyssUnlocked, NoMostKills): - await message.reply_text("本次深渊旅行者还没挑战呢,咕咕咕~~~") - return - await message.reply_chat_action(ChatAction.UPLOAD_PHOTO) - png_data = await self.template_service.render( - "genshin/abyss", "abyss.html", abyss_data, {"width": 865, "height": 504}, full_page=False + elif 0 < floor < 9: + previous = False + + logger.info( + f"用户 {user.full_name}[{user.id}] [bold]深渊挑战数据[/bold]请求: " + f"floor={floor} total={total} previous={previous}", + extra={"markup": True}, ) - await message.reply_photo(png_data, filename=f"abyss_{user.id}.png", allow_sending_without_reply=True) + + try: + client = await get_genshin_client(user.id) + await client.get_record_cards() + uid = client.uid + except UserNotFoundError: # 若未找到账号 + if filters.ChatType.GROUPS.filter(message): + buttons = [[InlineKeyboardButton("点我私聊", url=f"https://t.me/{context.bot.username}?start=set_cookies")]] + reply_msg = await message.reply_text( + "未查询到您所绑定的账号信息,请先私聊派蒙绑定账号", reply_markup=InlineKeyboardMarkup(buttons) + ) + self._add_delete_message_job(context, reply_msg.chat_id, reply_msg.message_id, 30) + + self._add_delete_message_job(context, message.chat_id, message.message_id, 30) + else: + await message.reply_text("未查询到您所绑定的账号信息,请先私聊派蒙绑定账号") + return + except CookiesNotFoundError: # 若未找到cookie + client, uid = await get_public_genshin_client(user.id) + except TooManyRequestPublicCookies: + reply_msg = await message.reply_text( + "查询次数太多,请您稍后重试", + ) + if filters.ChatType.GROUPS.filter(message): + self._add_delete_message_job(context, reply_msg.chat_id, reply_msg.message_id, 10) + self._add_delete_message_job(context, message.chat_id, message.message_id, 10) + return + + async def reply_message(content: str) -> None: + _user = await client.get_genshin_user(uid) + _reply_msg = await message.reply_text( + f"旅行者 {_user.info.nickname}({uid}) {content}", parse_mode=ParseMode.HTML + ) + if filters.ChatType.GROUPS.filter(message): + self._add_delete_message_job(context, _reply_msg.chat_id, _reply_msg.message_id, 10) + self._add_delete_message_job(context, message.chat_id, message.message_id, 10) + + if total: + reply_msg = await message.reply_text("派蒙需要时间整理深渊数据,还请耐心等待哦~") + if filters.ChatType.GROUPS.filter(message): + self._add_delete_message_job(context, reply_msg.chat_id, reply_msg.message_id, 10) + self._add_delete_message_job(context, message.chat_id, message.message_id, 10) + + await message.reply_chat_action(ChatAction.TYPING) + + try: + images = await self.get_rendered_pic(client, uid, floor, total, previous) + except AbyssUnlocked: # 若深渊未解锁 + return await reply_message("还未解锁深渊哦~") + except NoMostKills: # 若深渊还未挑战 + return await reply_message("还没有挑战本次深渊呢,咕咕咕~") + except IndexError: # 若深渊为挑战此层 + return await reply_message("还没有挑战本层呢,咕咕咕~") + if images is None: + return await reply_message(f"还没有第 {floor} 层的挑战数据") + + await message.reply_chat_action(ChatAction.UPLOAD_PHOTO) + + for group in ArkoWrapper(images).map(InputMediaPhoto).group(10): # 每 10 张图片分一个组 + await message.reply_media_group(list(group), allow_sending_without_reply=True) + + logger.info(f"用户 {user.full_name}[{user.id}] [bold]深渊挑战数据[/bold]: 成功发送图片", extra={"markup": True}) + + async def get_rendered_pic( + self, client: Client, uid: int, floor: int, total: bool, previous: bool + ) -> Optional[List[bytes]]: + """ + 获取渲染后的图片 + + Args: + client (Client): 获取 genshin 数据的 client + uid (int): 需要查询的 uid + floor (int): 层数 + total (bool): 是否为总览 + previous (bool): 是否为上期 + + Returns: + bytes格式的图片 + """ + + def json_encoder(value): + if isinstance(value, datetime): + return value.astimezone(TZ).strftime("%Y-%m-%d %H:%M:%S") + return value + + abyss_data = await client.get_spiral_abyss(uid, previous=previous, lang="zh-cn") + if not abyss_data.unlocked: + raise AbyssUnlocked() + if not abyss_data.ranks.most_kills: + raise NoMostKills() + end_time = abyss_data.end_time.astimezone(TZ) + time = end_time.strftime("%Y年%m月") + "上" if end_time.day <= 16 else "下" + "期" + stars = [i.stars for i in filter(lambda x: x.floor > 8, abyss_data.floors)] + total_stars = f"{sum(stars)} ({'-'.join(map(str, stars))})" + + render_data = {} + result = await async_re_sub( + regex_01, + partial(replace_01, assets_service=self.assets_service), + abyss_data.json(encoder=json_encoder), + ) + result = await async_re_sub(regex_02, partial(replace_02, assets_service=self.assets_service), result) + + render_data["time"] = time + render_data["stars"] = total_stars + render_data["uid"] = uid + render_data["floor_colors"] = { + 1: "#374952", + 2: "#374952", + 3: "#55464B", + 4: "#55464B", + 5: "#55464B", + 6: "#1D2A5D", + 7: "#1D2A5D", + 8: "#1D2A5D", + 9: "#292B58", + 10: "#382024", + 11: "#252550", + 12: "#1D2A4A", + } + if total: + avatars = await client.get_genshin_characters(uid, lang="zh-cn") + render_data["avatar_data"] = {i.id: i.constellation for i in avatars} + data = json.loads(result) + render_data["data"] = data + + render_result = [] + + async def overview_task(): + render_result.append( + [ + -1, + await self.template_service.render( + "genshin/abyss", "overview.html", render_data, viewport={"width": 750, "height": 580} + ), + ] + ) + + async def floor_task(floor_index: int): + floor_d = data["floors"][floor_index] + render_result.append( + [ + floor_d["floor"], + await self.template_service.render( + "genshin/abyss", + "floor.html", + { + **render_data, + "floor": floor_d, + "total_stars": f"{floor_d['stars']}/{floor_d['max_stars']}", + }, + viewport={"width": 690, "height": 500}, + full_page=True, + ), + ] + ) + + task_list = [asyncio.create_task(overview_task())] + for i, f in enumerate(data["floors"]): + if f["floor"] >= 9: + task_list.append(asyncio.create_task(floor_task(i))) + await asyncio.gather(*task_list) + + return list(map(lambda x: x[1], sorted(render_result, key=lambda x: x[0]))) + elif floor < 1: + render_data["data"] = json.loads(result) + return [ + await self.template_service.render( + "genshin/abyss", + "overview.html", + render_data, + viewport={"width": 750, "height": 580}, + ) + ] + else: + num_dic = { + "0": "", + "1": "一", + "2": "二", + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "7": "七", + "8": "八", + "9": "九", + } + if num := num_dic.get(str(floor)): + render_data["floor-num"] = num + else: + render_data["floor-num"] = f"十{num_dic.get(str(floor % 10))}" + floors = json.loads(result)["floors"] + if (floor_data := list(filter(lambda x: x["floor"] == floor, floors))) is None: + return None + avatars = await client.get_genshin_characters(uid, lang="zh-cn") + render_data["avatar_data"] = {i.id: i.constellation for i in avatars} + render_data["floor"] = floor_data[0] + render_data["total_stars"] = f"{floor_data[0]['stars']}/{floor_data[0]['max_stars']}" + return [ + await self.template_service.render( + "genshin/abyss", "floor.html", render_data, viewport={"width": 690, "height": 500}, full_page=True + ) + ] diff --git a/resources/genshin/daily_material/bg/rarity/full/1.png b/resources/background/rarity/full/1.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/full/1.png rename to resources/background/rarity/full/1.png diff --git a/resources/genshin/daily_material/bg/rarity/full/2.png b/resources/background/rarity/full/2.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/full/2.png rename to resources/background/rarity/full/2.png diff --git a/resources/genshin/daily_material/bg/rarity/full/3.png b/resources/background/rarity/full/3.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/full/3.png rename to resources/background/rarity/full/3.png diff --git a/resources/genshin/daily_material/bg/rarity/full/4.png b/resources/background/rarity/full/4.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/full/4.png rename to resources/background/rarity/full/4.png diff --git a/resources/genshin/daily_material/bg/rarity/full/5.png b/resources/background/rarity/full/5.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/full/5.png rename to resources/background/rarity/full/5.png diff --git a/resources/genshin/daily_material/bg/rarity/half/1.png b/resources/background/rarity/half/1.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/half/1.png rename to resources/background/rarity/half/1.png diff --git a/resources/genshin/daily_material/bg/rarity/half/2.png b/resources/background/rarity/half/2.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/half/2.png rename to resources/background/rarity/half/2.png diff --git a/resources/genshin/daily_material/bg/rarity/half/3.png b/resources/background/rarity/half/3.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/half/3.png rename to resources/background/rarity/half/3.png diff --git a/resources/genshin/daily_material/bg/rarity/half/4.png b/resources/background/rarity/half/4.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/half/4.png rename to resources/background/rarity/half/4.png diff --git a/resources/genshin/daily_material/bg/rarity/half/5.png b/resources/background/rarity/half/5.png similarity index 100% rename from resources/genshin/daily_material/bg/rarity/half/5.png rename to resources/background/rarity/half/5.png diff --git a/resources/genshin/daily_material/bg/rarity/star.webp b/resources/background/rarity/star.webp similarity index 100% rename from resources/genshin/daily_material/bg/rarity/star.webp rename to resources/background/rarity/star.webp diff --git a/resources/fonts/HYWenHei-35W.ttf b/resources/fonts/HYWenHei-35W.ttf new file mode 100644 index 00000000..64d5ac66 Binary files /dev/null and b/resources/fonts/HYWenHei-35W.ttf differ diff --git a/resources/fonts/HYWenHei-45W.ttf b/resources/fonts/HYWenHei-45W.ttf new file mode 100644 index 00000000..75ee78a6 Binary files /dev/null and b/resources/fonts/HYWenHei-45W.ttf differ diff --git a/resources/fonts/HYWenHei-55W.ttf b/resources/fonts/HYWenHei-55W.ttf new file mode 100644 index 00000000..92040355 Binary files /dev/null and b/resources/fonts/HYWenHei-55W.ttf differ diff --git a/resources/fonts/HYWenHei-65W.ttf b/resources/fonts/HYWenHei-65W.ttf new file mode 100644 index 00000000..e3cfe72c Binary files /dev/null and b/resources/fonts/HYWenHei-65W.ttf differ diff --git a/resources/fonts/HYWenHei-75W.ttf b/resources/fonts/HYWenHei-75W.ttf new file mode 100644 index 00000000..4bef1cad Binary files /dev/null and b/resources/fonts/HYWenHei-75W.ttf differ diff --git a/resources/fonts/汉仪文黑-85W.ttf b/resources/fonts/HYWenHei-85W.ttf similarity index 100% rename from resources/fonts/汉仪文黑-85W.ttf rename to resources/fonts/HYWenHei-85W.ttf diff --git a/resources/genshin/abyss/abyss.html b/resources/genshin/abyss/abyss.html deleted file mode 100644 index f1ad4b02..00000000 --- a/resources/genshin/abyss/abyss.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - abyss - - - - - -
-
深境螺旋
-
-
UID {{ uid }}
-
最深抵达 {{ max_floor }}
-
战斗次数 {{ total_battles }}
-
获得星级 {{ total_stars }}
-
-
-
出战次数
-
- {% for most_played in most_played_list %} -
-
-
-
{{ most_played.value }}次
-
- {% endfor %} -
-
-
-
-
战斗数据榜
-
-
-
-
-
最多击破数:{{ most_kills.value }}
- -
-
-
最强一击:{{ strongest_strike.value }}
- -
-
-
-
-
承受最多伤害:{{ most_damage_taken.value }}
- -
-
-
元素爆发数:{{ most_bursts_used.value }}
- -
-
-
-
-
元素战技释放次数:{{ most_skills_used.value }}
- -
-
-
-
-
-
-
- - \ No newline at end of file diff --git a/resources/genshin/abyss/background/abyss.png b/resources/genshin/abyss/background/abyss.png new file mode 100644 index 00000000..9cbc0215 Binary files /dev/null and b/resources/genshin/abyss/background/abyss.png differ diff --git a/resources/genshin/abyss/background/banner 01.png b/resources/genshin/abyss/background/banner 01.png new file mode 100644 index 00000000..d6d1ae92 Binary files /dev/null and b/resources/genshin/abyss/background/banner 01.png differ diff --git a/resources/genshin/abyss/background/banner 02.png b/resources/genshin/abyss/background/banner 02.png new file mode 100644 index 00000000..f948a1fa Binary files /dev/null and b/resources/genshin/abyss/background/banner 02.png differ diff --git a/resources/genshin/abyss/background/floor1.png b/resources/genshin/abyss/background/floor1.png new file mode 100644 index 00000000..5ec57368 Binary files /dev/null and b/resources/genshin/abyss/background/floor1.png differ diff --git a/resources/genshin/abyss/background/floor10.png b/resources/genshin/abyss/background/floor10.png new file mode 100644 index 00000000..18a364ff Binary files /dev/null and b/resources/genshin/abyss/background/floor10.png differ diff --git a/resources/genshin/abyss/background/floor11.png b/resources/genshin/abyss/background/floor11.png new file mode 100644 index 00000000..df319f61 Binary files /dev/null and b/resources/genshin/abyss/background/floor11.png differ diff --git a/resources/genshin/abyss/background/floor12.png b/resources/genshin/abyss/background/floor12.png new file mode 100644 index 00000000..775233d4 Binary files /dev/null and b/resources/genshin/abyss/background/floor12.png differ diff --git a/resources/genshin/abyss/background/floor2.png b/resources/genshin/abyss/background/floor2.png new file mode 100644 index 00000000..5ec57368 Binary files /dev/null and b/resources/genshin/abyss/background/floor2.png differ diff --git a/resources/genshin/abyss/background/floor3.png b/resources/genshin/abyss/background/floor3.png new file mode 100644 index 00000000..0c8c546d Binary files /dev/null and b/resources/genshin/abyss/background/floor3.png differ diff --git a/resources/genshin/abyss/background/floor4.png b/resources/genshin/abyss/background/floor4.png new file mode 100644 index 00000000..0c8c546d Binary files /dev/null and b/resources/genshin/abyss/background/floor4.png differ diff --git a/resources/genshin/abyss/background/floor5.png b/resources/genshin/abyss/background/floor5.png new file mode 100644 index 00000000..0c8c546d Binary files /dev/null and b/resources/genshin/abyss/background/floor5.png differ diff --git a/resources/genshin/abyss/background/floor6.png b/resources/genshin/abyss/background/floor6.png new file mode 100644 index 00000000..290aab49 Binary files /dev/null and b/resources/genshin/abyss/background/floor6.png differ diff --git a/resources/genshin/abyss/background/floor7.png b/resources/genshin/abyss/background/floor7.png new file mode 100644 index 00000000..290aab49 Binary files /dev/null and b/resources/genshin/abyss/background/floor7.png differ diff --git a/resources/genshin/abyss/background/floor8.png b/resources/genshin/abyss/background/floor8.png new file mode 100644 index 00000000..290aab49 Binary files /dev/null and b/resources/genshin/abyss/background/floor8.png differ diff --git a/resources/genshin/abyss/background/floor9.png b/resources/genshin/abyss/background/floor9.png new file mode 100644 index 00000000..d22f314c Binary files /dev/null and b/resources/genshin/abyss/background/floor9.png differ diff --git a/resources/genshin/abyss/background/four-star.png b/resources/genshin/abyss/background/four-star.png new file mode 100644 index 00000000..d2297b5d Binary files /dev/null and b/resources/genshin/abyss/background/four-star.png differ diff --git a/resources/genshin/abyss/background/star.png b/resources/genshin/abyss/background/star.png new file mode 100644 index 00000000..fb5901cf Binary files /dev/null and b/resources/genshin/abyss/background/star.png differ diff --git a/resources/genshin/abyss/example.html b/resources/genshin/abyss/example.html index d8742e39..6b8a3e6e 100644 --- a/resources/genshin/abyss/example.html +++ b/resources/genshin/abyss/example.html @@ -2,115 +2,518 @@ - abyss - - + abyss-example + + -
-
深境螺旋
-
-
UID 1414514
-
最深抵达 12-3
-
战斗次数 12
-
获得星级 36
-
-
-
出战次数
-
-
-
-
-
12次
+
+
+
挑战回顾
+
+
+
UID: 100206192
+
+ 36 (9-9-9-9) +
-
-
-
-
12次
-
-
-
-
-
12次
-
-
-
-
-
12次
+
+
时间: 2022年10月上
+
最深抵达: 12-3
-
-
-
-
战斗数据榜
+
+
出战次数
+
+
+
+ 神里绫华 +
+
15次
+
+ +
+
+ 神里绫华 +
+
15次
+
+ +
+
+ 神里绫华 +
+
15次
+
+ +
+
+ 神里绫华 +
+
15次
+
+
-
-
-
最多击破数:21
- +
战斗数据
+
+
+
战斗次数: 12
+
+ 最多击破:999 + 神里绫华 +
-
-
最强一击:21
- +
+
+ 最强一击: 999,999 + 神里绫华 +
+
+ 最多承伤: 114,514 + 神里绫华 +
-
-
-
-
承受最多伤害:21
- +
+
+ 元素爆发: 26 + 神里绫华 +
+
+ 元素战技: 48 + 神里绫华 +
+
+
+
+
+
+
+
+
+
+
深境螺旋第一层
+
+
+ 9/9 +
+
+
+
+
+
+ 第 1 间 2022-10-01 10:02:05 +
+
+
+
+
+
+
+
+
+
+
6命
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
5命
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
4命
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
3命
+
+
+ 神里绫华 +
+
Lv.90
+
+
上半
+
+
+
+
2命
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
1命
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
+ 神里绫华 +
+
Lv.90
+
+
下半
+
+
+
+
+
+
+
+ 第 2 间 2022-10-01 10:02:05 +
+
+
+
+
+
+
+
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
上半
+
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
下半
+
+
+
+
+
+
+
+ 第 3 间 2022-10-01 10:02:05 +
+
+
+
+
+
+
+
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
4命
+
+ 神里绫华 +
+
Lv.90
+
+
+
2命
+
+ 神里绫华 +
+
Lv.90
+
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
+
+
+
+
+
+
+
1
+
+ 深境螺旋第一层 +
+
+ 9/9 +
+
+
+
+
+
+ 第 1 间 2022-10-01 10:02:05 +
+
+
+
+
+
+
+
+
+
+
6命
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
5命
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
4命
+
+ 神里绫华 +
+
Lv.90
+
+
+
3命
+
+ 神里绫华 +
+
Lv.90
+
+
上半
+
+
+
+
2命
+
+ 神里绫华 +
+
Lv.90
+
+
+
1命
+
+ 神里绫华 +
+
Lv.90
+
+
+
+ 神里绫华 +
+
Lv.90
+
+
+
+ 神里绫华 +
+
Lv.90
+
+
下半
+
+
+
+
+
+
+
+ 第 2 间 2022-10-01 10:02:05 +
+
+
+
+
+
+
+
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
上半
+
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
下半
+
+
+
+
+
+
+
+ 第 3 间 2022-10-01 10:02:05 +
+
+
+
+
+
+
+
+
+
+
6命
+
+ 神里绫华 +
+
Lv.90
+
+
+
4命
+
+ 神里绫华 +
+
Lv.90
+
+
+
2命
+
+ 神里绫华 +
+
Lv.90
+
+
+
+ 神里绫华 +
+
Lv.90
+
+
-
-
元素爆发数:21
- -
-
-
-
-
元素战技释放次数:21
- -
-
-
\ No newline at end of file diff --git a/resources/genshin/abyss/floor.html b/resources/genshin/abyss/floor.html new file mode 100644 index 00000000..4e824b56 --- /dev/null +++ b/resources/genshin/abyss/floor.html @@ -0,0 +1,97 @@ + + + + + floor + + + + + +
+
+
+
+
+
+
+
UID: {{ uid }}
+
深境螺旋第 {{ floor.floor }} 层
+
+
+
+ {{ total_stars }} +
+
+ {% for chamber in floor.chambers %} +
+
+
+
+ 第 {{ loop.index }} 间 {{ chamber.battles[0].timestamp }} +
+
+ {% for n in range(chamber.stars) %} +
+ {% endfor %} + {% for n in range(chamber.max_stars - chamber.stars) %} +
+ {% endfor %} +
+
+
+ {% for battle in chamber.battles %} +
+ {% for character in battle.characters %} +
+ {% if avatar_data[character.id] > 0 %} + {% set constellation = avatar_data[character.id] %} + {% set bg = ['blue','blue', 'green','green', 'red', 'red'][constellation - 1] %} +
+ {{ constellation }} 命 +
+ {% endif %} +
+ +
+
Lv.{{ character.level }}
+
+ {% endfor %} + {% if loop.length > 1 %} +
{{ ['上', '下'][loop.index0] }}半
+ {% endif %} +
+ {% endfor %} +
+
+ {% endfor %} +
+
+
+ + \ No newline at end of file diff --git a/resources/genshin/abyss/overview.html b/resources/genshin/abyss/overview.html new file mode 100644 index 00000000..6b64bb14 --- /dev/null +++ b/resources/genshin/abyss/overview.html @@ -0,0 +1,89 @@ + + + + + overview + + + + + +
+
+
挑战回顾
+
+
+
UID: {{ uid }}
+
+ {{ stars }} +
+
+
+
时间: {{ time }}
+
最深抵达: {{ data.max_floor }}
+
+
+
+
出战次数
+
+ {% for avatar in data.ranks.most_played %} +
+
+ +
+
{{ avatar.value }} 次
+
+ {% if loop.index != 4 %} + + {% endif %} + {% endfor %} +
+
+
+
战斗数据
+
+
+
战斗次数: {{ data.total_battles }}
+
+ 最多击破:{{ data.ranks.most_kills[0].value }} + +
+
+
+
+ 最强一击: {{ data.ranks.strongest_strike[0].value }} + +
+
+ 最多承伤: {{ data.ranks.most_damage_taken[0].value }} + +
+
+
+
+ 元素爆发: {{ data.ranks.most_bursts_used[0].value }} + +
+
+ 元素战技: {{ data.ranks.most_skills_used[0].value }} + +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/resources/genshin/abyss/style.css b/resources/genshin/abyss/style.css new file mode 100644 index 00000000..6e5fa6b5 --- /dev/null +++ b/resources/genshin/abyss/style.css @@ -0,0 +1,346 @@ +:root { + --white: rgb(246 248 249); + --bg-color: rgb(233 229 220); + --h-color: rgb(203 189 162); + --red: rgb(255 86 33/ 80%); + --blue: rgb(98 168 233/ 80%); + --green: rgb(67 185 124/ 80%); +} + +body { + margin: 0; + padding: 10px; +} + +.hr { + width: 100%; + height: 3px; + background-color: rgb(246 248 249 / 50%); +} + +.container { + width: 750px; + position: relative; + filter: drop-shadow(2px 2px 5px rgb(0 0 0 /70%)); +} + +.title { + text-align: center; + font-size: 27px; + font-weight: bold; + color: var(--h-color); +} + +.caption { + margin: 10px 0; + color: var(--h-color); + font-size: 20px; +} + +/* 概览 */ + +.overview { + height: 540px; + padding: 20px 40px; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + background-image: linear-gradient(to top, rgb(0 0 0 / 10%), rgb(0 0 0 / 10%)), url("./background/lookback-bg.png"); + background-attachment: local; + border-radius: 15px; + overflow: hidden; +} + +.summarize { + font-size: 20px; + width: calc(100% - 90px); + height: calc(100px - 20px); + margin: 20px 0; + padding: 10px 0 10px 80px; + border-radius: 5px; + border: 2px solid rgb(118 121 120 / 80%); + outline: 4px solid rgb(74, 82, 101); + background-color: rgb(74 82 101 / 60%); + background-image: url("./background/banner 01.png"), url("./background/banner 02.png"); + background-repeat: no-repeat, no-repeat; + background-position: right, left; + background-size: auto 100%, auto 100%; + backdrop-filter: blur(5px); +} + +.summarize > div { + width: 100%; + height: 50%; + color: var(--white); + display: flex; + align-items: center; +} + +.summarize > div > div { + flex: 1; +} + +.star { + display: inline-flex; + align-items: center; + position: relative; +} + +.star::before { + content: ""; + width: 40px; + height: 40px; + background-size: cover; + background-image: url("./background/star.png"); +} + +.star > span { + margin-left: 10px; +} + +.most-played { + width: 100%; + margin: 30px 0; +} + +.characters { + width: calc(100% - 60px); + padding: 0 30px; + display: flex; + justify-content: center; + align-items: center; +} + +.character { + width: 100px; + height: 125px; + margin: 0 20px; + background-color: rgb(233 229 220); + overflow: hidden; + border-radius: 10px; + position: relative; +} + +.icon { + width: 100%; + height: 100px; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + overflow: hidden; + border-radius: 0 0 20px 0; + display: flex; + flex-direction: column; + flex-wrap: wrap; + align-items: center; + justify-content: space-around; +} + +.icon > img { + width: inherit; + height: inherit; +} + +.character > .caption { + font-size: 18px; + margin: 4px 0 0; + padding: 0; + height: min-content; + text-align: center; + color: black; +} + +.four-star { + width: 15px; + height: 15px; + position: relative; +} + +.four-star::after { + content: ''; + position: absolute; + top: 0; + left: 0; + z-index: 1; + width: inherit; + height: inherit; + background-position: center; + background-image: url("./background/four-star.png"); + background-blend-mode: lighten; + background-size: contain; +} + +.ranks { + width: calc(100% + 80px); + transform: translateX(-40px); + color: var(--white); + position: relative; + display: flex; + flex-flow: column; + flex-wrap: wrap; +} + +.ranks > div { + font-size: 18px; + width: 100%; + height: 43px; + display: flex; + align-items: center; +} + +.rank { + flex: 1; + position: relative; + display: flex; + margin-left: 80px; + margin-right: 60px; +} + +.ranks > div > .rank:first-child { + margin-right: 10px; +} + +.rank > img { + width: 50px; + position: absolute; + right: 0; + bottom: -5px; +} + +/* 层数 */ + +.floors { + margin-top: 20px; +} + +.floor { + margin: 20px 0; + padding: 0 30px; + width: calc(100% - 60px); + border-radius: 20px; + overflow: hidden; + outline: rgb(233 229 220 / 30%) solid 3px; + outline-offset: -7px; + background-position: top center; + background-repeat: no-repeat; + background-size: contain; +} + +.head { + width: 100%; + height: 160px; + display: flex; +} + +.floor-name { + font-size: 28px; + display: flex; + align-items: center; + font-weight: bold; + color: var(--white); +} + +.floor-name > div:not(.floor-num) { + margin-left: 20px; + text-shadow: 1px 1px 5px rgb(0 0 0/50%); +} + +.floor-num { + color: black; + width: 100px; + height: 100px; + background-image: url("./background/abyss.png"); + background-size: contain; + filter: drop-shadow(0 0 5px rgb(0 0 0/80%)) grayscale(10%); + position: relative; +} + +.head > .star { + margin-left: auto; + float: right; + color: var(--white); + font-size: 25px; + text-shadow: 1px 1px 5px rgb(0 0 0/50%); +} + +.head > .star::before { + width: 50px; + height: 50px; +} + +.chamber { + margin: 10px 0; + display: flex; + flex-flow: column; +} + +.chamber-info { + height: 70px; + display: flex; + align-items: center; + color: var(--white); + font-size: 22px; +} + +.stars { + margin-left: auto; +} + +.dim-star::before { + filter: brightness(50%); +} + +.battle { + margin: 10px 0 20px 0; + display: flex; + justify-content: center; + align-items: center; +} + +.battle > .character { + flex: 2; + max-width: 120px; + height: 145px; +} + +.battle > .battle-info { + flex: 1; + color: var(--white); + font-size: 22px; + font-weight: bold; +} + +.battle > .character > div:first-child:not(.icon, .element) { + position: absolute; + top: 0; + right: 0; + padding: 5px; + min-width: 27px; + text-align: center; + border-radius: 0 0 0 10px; + filter: drop-shadow(1px 1px 5px rgb(0 0 0/50%)); + font-weight: 500; + color: var(--white); +} + +.battle > .character > .element { + position: absolute; + top: 3px; + left: 3px; + width: 30px; + height: 30px; + background-size: contain; + background-position: center; + background-repeat: no-repeat; +} + +.battle > .character > .icon { + width: 100%; + height: fit-content; + border-radius: 0 0 28px 0; +} + +.battle > .character > .caption { + font-size: 20px; + margin-top: 2px; +} diff --git a/resources/genshin/daily_material/character.html b/resources/genshin/daily_material/character.html index 98d25618..2df4295c 100644 --- a/resources/genshin/daily_material/character.html +++ b/resources/genshin/daily_material/character.html @@ -31,12 +31,12 @@ {% for material in area.materials %}
+ style="background-image: url(../../background/rarity/half/{{ material.rarity }}.png)"> {{ material.name }}
{% for _ in range(material.rarity) %} - star + star {% endfor %}
@@ -53,7 +53,7 @@ {% endif %} >
+ style="background-image: url(../../background/rarity/full/{{ item.rarity }}.png)"> {% if item.level != none %}
Lv.{{ item.level }}
{% endif %} diff --git a/resources/genshin/daily_material/example.html b/resources/genshin/daily_material/example.html index e03b1156..9a36269e 100644 --- a/resources/genshin/daily_material/example.html +++ b/resources/genshin/daily_material/example.html @@ -27,52 +27,52 @@
-
+
- star - star + star + star
-
+
- star - star - star + star + star + star
-
+
- star - star - star - star + star + star + star + star
-
+
- star - star - star - star - star + star + star + star + star + star
-
+
Lv.90
6命
八重神子 @@ -82,7 +82,7 @@
-
+
Lv.90
6命
神里绫华 @@ -92,7 +92,7 @@
-
+
Lv.90
6命
神里绫华 @@ -102,7 +102,7 @@
-
+
Lv.90
神里绫华
@@ -111,7 +111,7 @@
-
+
神里绫华
@@ -119,7 +119,7 @@
-
+
神里绫华
@@ -139,52 +139,52 @@
-
+
- star - star + star + star
-
+
- star - star - star + star + star + star
-
+
- star - star - star - star + star + star + star + star
-
+
- star - star - star - star - star + star + star + star + star + star
-
+
Lv.90
6命
神里绫华 @@ -194,7 +194,7 @@
-
+
Lv.90
6命
神里绫华 @@ -204,7 +204,7 @@
-
+
Lv.90
6命
神里绫华 @@ -214,7 +214,7 @@
-
+
Lv.90
神里绫华
@@ -223,7 +223,7 @@
-
+
神里绫华
@@ -231,7 +231,7 @@
-
+
神里绫华
@@ -255,45 +255,45 @@
-
+
- star - star + star + star
-
+
- star - star - star + star + star + star
-
+
- star - star - star - star + star + star + star + star
-
+
- star - star - star - star - star + star + star + star + star + star
@@ -303,7 +303,7 @@
申鹤
-
+
Lv.90
精炼5
天空之刃 @@ -316,7 +316,7 @@
神里绫华
-
+
Lv.90
精炼5
天空之刃 @@ -329,7 +329,7 @@
神里绫华
-
+
Lv.90
精炼5
天空之刃 @@ -342,7 +342,7 @@
神里绫华
-
+
Lv.90
精炼5
天空之刃 @@ -352,7 +352,7 @@
-
+
天空之刃
@@ -360,7 +360,7 @@
-
+
天空之刃
diff --git a/resources/genshin/daily_material/style.css b/resources/genshin/daily_material/style.css index 63c9c693..91a64047 100644 --- a/resources/genshin/daily_material/style.css +++ b/resources/genshin/daily_material/style.css @@ -1,13 +1,13 @@ @font-face { font-family: 'HYWH'; - src: url('../../fonts/汉仪文黑-85W.ttf') format('truetype'); + src: url('../../fonts/HYWenHei-85W.ttf') format('truetype'); } :root { - --bg-color: #ebe5d9; - --font-color: #514e49; - --color-1: #d6ba92; - --shadow: #726c65; + --bg-color: #EBE5D9; + --font-color: #514E49; + --color-1: #D6BA92; + --shadow: #726C65; } @@ -190,7 +190,7 @@ body { display: flex; justify-content: center; align-items: center; - filter: drop-shadow(1px 1px 2px #6c6c6c); + filter: drop-shadow(1px 1px 2px #6C6C6C); } .material-star > img { diff --git a/resources/genshin/daily_material/weapon.html b/resources/genshin/daily_material/weapon.html index 0d81c82e..0c19d2a1 100644 --- a/resources/genshin/daily_material/weapon.html +++ b/resources/genshin/daily_material/weapon.html @@ -31,12 +31,12 @@ {% for material in area.materials %}
+ style="background-image: url(../../background/rarity/half/{{ material.rarity }}.png)"> {{ material.name }}
{% for _ in range(material.rarity) %} - star + star {% endfor %}
@@ -58,7 +58,7 @@
{% endif %}
+ style="background-image: url(../../background/rarity/full/{{ item.rarity }}.png)"> {% if item.level != none %}
Lv.{{ item.level }}
{% endif %} diff --git a/resources/genshin/gacha_count/example.html b/resources/genshin/gacha_count/example.html index 983e6798..9fddf2cb 100644 --- a/resources/genshin/gacha_count/example.html +++ b/resources/genshin/gacha_count/example.html @@ -4,7 +4,7 @@ - + diff --git a/resources/genshin/gacha_count/gacha_count.css b/resources/genshin/gacha_count/gacha_count.css index 191d032d..4d1e2a5e 100644 --- a/resources/genshin/gacha_count/gacha_count.css +++ b/resources/genshin/gacha_count/gacha_count.css @@ -7,7 +7,7 @@ @font-face { font-family: "HYWenHei-55W"; - src: url("./../../fonts/汉仪文黑-85W.ttf"); + src: url("../../fonts/HYWenHei-85W.ttf"); font-weight: normal; font-style: normal; } @@ -22,7 +22,7 @@ body { font-size: 16px; width: 530px; - color: #1e1f20; + color: #1E1F20; transform: scale(1.5); transform-origin: 0 0; } @@ -30,7 +30,7 @@ body { .container { width: 530px; padding: 20px 15px 10px 15px; - background-color: #f5f6fb; + background-color: #F5F6FB; } .head_box { @@ -72,7 +72,7 @@ body { margin-top: 20px; margin-bottom: 20px; padding: 10px 5px 5px 5px; - background: #fff; + background: #FFF; box-shadow: 0 5px 10px 0 rgb(0 0 0 / 15%); position: relative; } @@ -111,7 +111,7 @@ body { box-shadow: 0 2px 6px 0 rgb(132 93 90 / 30%); height: 70px; width: 70px; - background: #e9e5dc; + background: #E9E5DC; position: relative; } @@ -132,7 +132,7 @@ body { z-index: 9; font-size: 18px; text-align: center; - color: #fff; + color: #FFF; border-radius: 3px; padding: 1px 5px; background: rgb(0 0 0 / 50%); @@ -144,15 +144,15 @@ body { } .label_302 { - background-color: #e69449; + background-color: #E69449; } .label_200 { - background-color: #757cc8; + background-color: #757CC8; } .label { - color: #fff; + color: #FFF; border-radius: 10px; font-size: 16px; padding: 2px 7px; @@ -177,38 +177,38 @@ body { } .list_box .item .life1 { - background-color: #62a8ea; + background-color: #62A8EA; } .list_box .item .life2 { - background-color: #62a8ea; + background-color: #62A8EA; } .list_box .item .life3 { - background-color: #45b97c; + background-color: #45B97C; } .list_box .item .life4 { - background-color: #45b97c; + background-color: #45B97C; } .list_box .item .life5 { - background-color: #ff5722; + background-color: #FF5722; } .list_box .item .life6 { - background-color: #ff5722; + background-color: #FF5722; } .logo { font-size: 14px; font-family: "tttgbnumber", serif; text-align: center; - color: #7994a7; + color: #7994A7; } .hasMore { font-size: 12px; margin: -6px 0 10px 6px; - color: #7f858a; + color: #7F858A; } diff --git a/resources/genshin/gacha_count/gacha_count.html b/resources/genshin/gacha_count/gacha_count.html index 0a834ebb..02e28da0 100644 --- a/resources/genshin/gacha_count/gacha_count.html +++ b/resources/genshin/gacha_count/gacha_count.html @@ -4,7 +4,7 @@ - + @@ -20,34 +20,34 @@
-
ID: {{uid}}
-

抽卡统计-{{typeName}}

+
ID: {{ uid }}
+

抽卡统计-{{ typeName }}

{% for val in pool %} -
-
-
-

「{{val.name}}」

- {{val.count}}抽 +
+
+
+

「{{ val.name }}」

+ {{ val.count }}抽 +
+ {% if typeName != "常驻祈愿" %} + {{ val.start }} - {{ val.end }} + {% endif %}
- {% if typeName != "常驻祈愿" %} - {{val.start}} - {{val.end}} - {% endif %} -
-
- {% for v in val.list %} -
-
- {{v.count}} - +
+ {% for v in val.list %} +
+
+ {{ v.count }} + +
+ {% endfor %}
- {% endfor %}
-
{% endfor %} {% if hasMore %} -
*完整数据请私聊查看
+
*完整数据请私聊查看
{% endif %}
diff --git a/resources/img/element/Anemo.png b/resources/img/element/Anemo.png new file mode 100644 index 00000000..dc8f802d Binary files /dev/null and b/resources/img/element/Anemo.png differ diff --git a/resources/img/element/Cyro.png b/resources/img/element/Cyro.png new file mode 100644 index 00000000..4f913dba Binary files /dev/null and b/resources/img/element/Cyro.png differ diff --git a/resources/img/element/Dendro.png b/resources/img/element/Dendro.png new file mode 100644 index 00000000..2dcd04b9 Binary files /dev/null and b/resources/img/element/Dendro.png differ diff --git a/resources/img/element/Electro.png b/resources/img/element/Electro.png new file mode 100644 index 00000000..9a31a2ed Binary files /dev/null and b/resources/img/element/Electro.png differ diff --git a/resources/img/element/Geo.png b/resources/img/element/Geo.png new file mode 100644 index 00000000..674e8086 Binary files /dev/null and b/resources/img/element/Geo.png differ diff --git a/resources/img/element/Hydro.png b/resources/img/element/Hydro.png new file mode 100644 index 00000000..2c1b3dc2 Binary files /dev/null and b/resources/img/element/Hydro.png differ diff --git a/resources/img/element/Pyro.png b/resources/img/element/Pyro.png new file mode 100644 index 00000000..82868f9e Binary files /dev/null and b/resources/img/element/Pyro.png differ diff --git a/resources/styles/public.css b/resources/styles/public.css index 5c068e9e..97b0731a 100644 --- a/resources/styles/public.css +++ b/resources/styles/public.css @@ -6,12 +6,54 @@ } @font-face { - font-family: "hywh"; - src: url("../fonts/汉仪文黑-85W.ttf"); + font-family: "HYWH"; + src: url("../fonts/HYWenHei-35W.ttf") format("truetype"); + font-weight: 200; + font-style: normal; +} + +@font-face { + font-family: "HYWH"; + src: url("../fonts/HYWenHei-45W.ttf") format("truetype"); + font-weight: 300; + font-style: normal; +} + +@font-face { + font-family: "HYWH"; + src: url("../fonts/HYWenHei-55W.ttf") format("truetype"); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: "HYWH"; + src: url("../fonts/HYWenHei-65W.ttf") format("truetype"); + font-weight: 500; + font-style: normal; +} + +@font-face { + font-family: "HYWH"; + src: url("../fonts/HYWenHei-75W.ttf") format("truetype"); + font-weight: 600; + font-style: normal; +} + +@font-face { + font-family: "HYWH"; + src: url("../fonts/HYWenHei-85W.ttf") format("truetype"); + font-weight: 700; + font-style: normal; +} + +@font-face { + font-family: "Number"; + src: url("../fonts/tttgbnumber.ttf") format("truetype"); font-weight: normal; font-style: normal; } body { - font-family: "hywh", "seguiemj", emoji, system-ui; + font-family: "Number", "HYWH", "seguiemj", emoji, serif, system-ui; } diff --git a/utils/helpers.py b/utils/helpers.py index ae8d04c2..c0fbc4fd 100644 --- a/utils/helpers.py +++ b/utils/helpers.py @@ -1,9 +1,13 @@ +from __future__ import annotations + import hashlib import os +import re from asyncio import create_subprocess_shell from asyncio.subprocess import PIPE +from inspect import iscoroutinefunction from pathlib import Path -from typing import Optional, Tuple, TypeVar, Union, cast +from typing import Awaitable, Callable, Match, Optional, Pattern, Tuple, TypeVar, Union, cast import aiofiles import genshin @@ -80,10 +84,7 @@ async def url_to_file(url: str, return_path: bool = False) -> str: await f.write(data.content) logger.debug(f"url_to_file 获取url[{url}] 并下载到 file_dir[{file_dir}]") - if return_path: - return file_dir - - return Path(file_dir).as_uri() + return file_dir if return_path else Path(file_dir).as_uri() async def get_genshin_client(user_id: int, region: Optional[RegionEnum] = None, need_cookie: bool = True) -> Client: @@ -133,9 +134,7 @@ async def get_public_genshin_client(user_id: int) -> Tuple[Client, Optional[int] def region_server(uid: Union[int, str]) -> RegionEnum: - if isinstance(uid, int): - region = REGION_MAP.get(str(uid)[0]) - elif isinstance(uid, str): + if isinstance(uid, (int, str)): region = REGION_MAP.get(str(uid)[0]) else: raise TypeError("UID variable type error") @@ -161,3 +160,50 @@ async def execute(command, pass_error=True): except UnicodeDecodeError: result = str(stdout.decode("gbk").strip()) return result + + +async def async_re_sub( + pattern: str | Pattern, + repl: str | Callable[[Match], str] | Callable[[Match], Awaitable[str]], + string: str, + count: int = 0, + flags: int = 0, +) -> str: + """ + 一个支持 repl 参数为 async 函数的 re.sub + Args: + pattern (str | Pattern): 正则对象 + repl (str | Callable[[Match], str] | Callable[[Match], Awaitable[str]]): 替换后的文本或函数 + string (str): 目标文本 + count (int): 要替换的最大次数 + flags (int): 标志常量 + + Returns: + 返回经替换后的字符串 + """ + result = "" + temp = string + if count != 0: + for _ in range(count): + match = re.search(pattern, temp, flags=flags) + replaced = None + if iscoroutinefunction(repl): + # noinspection PyUnresolvedReferences,PyCallingNonCallable + replaced = await repl(match) + elif callable(repl): + # noinspection PyCallingNonCallable + replaced = repl(match) + result += temp[: match.span(1)[0]] + (replaced or repl) + temp = temp[match.span(1)[1] :] + else: + while match := re.search(pattern, temp, flags=flags): + replaced = None + if iscoroutinefunction(repl): + # noinspection PyUnresolvedReferences,PyCallingNonCallable + replaced = await repl(match) + elif callable(repl): + # noinspection PyCallingNonCallable + replaced = repl(match) + result += temp[: match.span(1)[0]] + (replaced or repl) + temp = temp[match.span(1)[1] :] + return result + temp diff --git a/utils/log/_logger.py b/utils/log/_logger.py index e2aaf958..2781b66f 100644 --- a/utils/log/_logger.py +++ b/utils/log/_logger.py @@ -77,7 +77,14 @@ log_console = Console(color_system=color_system, theme=Theme(DEFAULT_STYLE), wid class Traceback(BaseTraceback): def __init__(self, *args, **kwargs): - kwargs.update({"show_locals": True, "max_frames": config.logger.traceback_max_frames}) + kwargs.update( + { + "show_locals": True, + "max_frames": config.logger.traceback_max_frames, + "locals_max_length": 3, + "locals_max_string": 80, + } + ) super(Traceback, self).__init__(*args, **kwargs) self.theme = PygmentsSyntaxTheme(MonokaiProStyle)