Add HTML rendering for /material

This commit is contained in:
LittleMengBot 2023-04-04 22:02:14 +08:00 committed by GitHub
parent 115532b698
commit 5f33c5fc3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 769 additions and 73 deletions

View File

@ -3,7 +3,7 @@ from typing import List
from core.base_service import BaseService from core.base_service import BaseService
from core.dependence.redisdb import RedisDB from core.dependence.redisdb import RedisDB
__all__ = ["GameCache", "GameCacheForStrategy", "GameCacheForMaterial"] __all__ = ["GameCache", "GameCacheForStrategy"]
class GameCache: class GameCache:
@ -27,7 +27,3 @@ class GameCache:
class GameCacheForStrategy(BaseService.Component, GameCache): class GameCacheForStrategy(BaseService.Component, GameCache):
qname = "game:strategy" qname = "game:strategy"
class GameCacheForMaterial(BaseService.Component, GameCache):
qname = "game:material"

View File

@ -1,10 +1,10 @@
from typing import List, Optional from typing import List, Optional
from core.base_service import BaseService from core.base_service import BaseService
from core.services.game.cache import GameCacheForMaterial, GameCacheForStrategy from core.services.game.cache import GameCacheForStrategy
from modules.apihelper.client.components.hyperion import Hyperion from modules.apihelper.client.components.hyperion import Hyperion
__all__ = ("GameMaterialService", "GameStrategyService") __all__ = "GameStrategyService"
class GameStrategyService(BaseService): class GameStrategyService(BaseService):
@ -50,52 +50,3 @@ class GameStrategyService(BaseService):
artwork_info = await self._hyperion.get_post_info(2, post_id) artwork_info = await self._hyperion.get_post_info(2, post_id)
await self._cache.set_url_list(character_name, artwork_info.image_urls) await self._cache.set_url_list(character_name, artwork_info.image_urls)
return artwork_info.image_urls[0] return artwork_info.image_urls[0]
class GameMaterialService(BaseService):
def __init__(self, cache: GameCacheForMaterial, collections: Optional[List[int]] = None):
self._cache = cache
self._hyperion = Hyperion()
self._collections = [428421, 1362644] if collections is None else collections
self._special = ["雷电将军", "珊瑚宫心海", "菲谢尔", "托马", "八重神子", "九条裟罗", "辛焱", "神里绫华"]
async def _get_material_from_hyperion(self, collection_id: int, character_name: str) -> int:
post_id: int = -1
post_full_in_collection = await self._hyperion.get_post_full_in_collection(collection_id)
for post_data in post_full_in_collection["posts"]:
topics = post_data["topics"]
for topic in topics:
if character_name == topic["name"]:
post_id = int(post_data["post"]["post_id"])
break
if post_id != -1:
break
subject = post_data["post"]["subject"]
if character_name in subject:
post_id = int(post_data["post"]["post_id"])
if post_id != -1:
break
return post_id
async def get_material(self, character_name: str) -> str:
cache = await self._cache.get_url_list(character_name)
if len(cache) >= 1:
image_url_list = cache
else:
for collection_id in self._collections:
post_id = await self._get_material_from_hyperion(collection_id, character_name)
if post_id != -1:
break
else:
return ""
artwork_info = await self._hyperion.get_post_info(2, post_id)
image_url_list = artwork_info.image_urls
if collection_id == 1362644 or character_name in self._special:
image_url_list.pop(0)
await self._cache.set_url_list(character_name, image_url_list)
if len(image_url_list) == 0:
return ""
if len(image_url_list) == 1:
return image_url_list[0]
return image_url_list[1]

View File

@ -11,6 +11,7 @@ class Remote:
BASE_URL = f"https://raw.githubusercontent.com/{RESOURCE_DEFAULT_PATH}" BASE_URL = f"https://raw.githubusercontent.com/{RESOURCE_DEFAULT_PATH}"
CALENDAR = f"{BASE_URL}calendar.json" CALENDAR = f"{BASE_URL}calendar.json"
BIRTHDAY = f"{BASE_URL}birthday.json" BIRTHDAY = f"{BASE_URL}birthday.json"
MATERIAL = f"{BASE_URL}roles_material.json"
@staticmethod @staticmethod
async def get_remote_calendar() -> Dict[str, Dict]: async def get_remote_calendar() -> Dict[str, Dict]:
@ -35,3 +36,15 @@ class Remote:
return {} return {}
except HTTPError: except HTTPError:
return {} return {}
@staticmethod
async def get_remote_material() -> Dict[str, List[str]]:
"""获取云端角色材料"""
try:
async with AsyncClient() as client:
req = await client.get(Remote.MATERIAL)
if req.status_code == 200:
return req.json()
return {}
except HTTPError:
return {}

View File

@ -0,0 +1,28 @@
from typing import List
class TalentMaterials:
def __init__(self, amount: List[int]):
self.amount = amount
def cal_materials(self) -> List[int]:
"""
:return: [摩拉天赋书x3怪物素材x3皇冠周本素材]
"""
cost = [0, 0, 0, 0, 0, 0, 0, 0, 0]
cost_list = [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[12500, 3, 0, 0, 6, 0, 0, 0, 0],
[17500, 0, 2, 0, 0, 3, 0, 0, 0],
[25000, 0, 4, 0, 0, 4, 0, 0, 0],
[30000, 0, 6, 0, 0, 6, 0, 0, 0],
[37500, 0, 9, 0, 0, 9, 0, 0, 0],
[120000, 0, 0, 4, 0, 0, 4, 0, 1],
[260000, 0, 0, 6, 0, 0, 6, 0, 1],
[450000, 0, 0, 12, 0, 0, 9, 0, 2],
[700000, 0, 0, 16, 0, 0, 12, 1, 2],
]
for i in self.amount:
for level in range(1, i):
cost = list(map(lambda x: x[0] + x[1], zip(cost, cost_list[level])))
return cost

View File

@ -1,10 +1,17 @@
import re
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.constants import ChatAction, ParseMode from telegram.constants import ChatAction
from telegram.ext import CallbackContext, CommandHandler, MessageHandler, filters from telegram.ext import CallbackContext, CommandHandler, MessageHandler, filters
from core.dependence.assets import AssetsService
from core.plugin import Plugin, handler from core.plugin import Plugin, handler
from core.services.game.services import GameMaterialService from core.services.template.services import TemplateService
from metadata.genshin import MATERIAL_DATA
from metadata.shortname import roleToName from metadata.shortname import roleToName
from modules.apihelper.client.components.remote import Remote
from modules.material.talent import TalentMaterials
from modules.wiki.character import Character
from utils.log import logger from utils.log import logger
__all__ = ("MaterialPlugin",) __all__ = ("MaterialPlugin",)
@ -15,8 +22,184 @@ class MaterialPlugin(Plugin):
KEYBOARD = [[InlineKeyboardButton(text="查看角色培养素材列表并查询", switch_inline_query_current_chat="查看角色培养素材列表并查询")]] KEYBOARD = [[InlineKeyboardButton(text="查看角色培养素材列表并查询", switch_inline_query_current_chat="查看角色培养素材列表并查询")]]
def __init__(self, game_material_service: GameMaterialService = None): def __init__(
self.game_material_service = game_material_service self,
template_service: TemplateService,
assets_service: AssetsService,
):
self.roles_material = {}
self.assets_service = assets_service
self.template_service = template_service
async def initialize(self):
await self._refresh()
async def _refresh(self):
self.roles_material = await Remote.get_remote_material()
async def _parse_material(self, data: dict, character_name: str, talent_level: str) -> dict:
data = data["data"]
if character_name not in data.keys():
return {}
character = self.assets_service.avatar(character_name)
level_up_material = self.assets_service.material(data[character_name]["level_up_materials"])
ascension_material = self.assets_service.material(data[character_name]["ascension_materials"])
local_material = self.assets_service.material(data[character_name]["materials"][0])
enemy_material = self.assets_service.material(data[character_name]["materials"][1])
level_up_materials = [
{
"num": 46,
"rarity": MATERIAL_DATA[str(level_up_material.id)]["rank"],
"icon": (await level_up_material.icon()).as_uri(),
"name": data[character_name]["level_up_materials"],
},
{
"num": 419,
"rarity": 4,
"icon": (await self.assets_service.material(104003).icon()).as_uri(),
"name": "大英雄的经验",
},
{
"num": 1,
"rarity": 2,
"icon": (await ascension_material.icon()).as_uri(),
"name": MATERIAL_DATA[str(ascension_material.id)]["name"],
},
{
"num": 9,
"rarity": 3,
"icon": (await self.assets_service.material(ascension_material.id - 1).icon()).as_uri(),
"name": MATERIAL_DATA[str(ascension_material.id - 1)]["name"],
},
{
"num": 9,
"rarity": 4,
"icon": (await self.assets_service.material(str(ascension_material.id - 2)).icon()).as_uri(),
"name": MATERIAL_DATA[str(ascension_material.id - 2)]["name"],
},
{
"num": 6,
"rarity": 5,
"icon": (await self.assets_service.material(ascension_material.id - 3).icon()).as_uri(),
"name": MATERIAL_DATA[str(ascension_material.id - 3)]["name"],
},
{
"num": 168,
"rarity": MATERIAL_DATA[str(local_material.id)]["rank"],
"icon": (await local_material.icon()).as_uri(),
"name": MATERIAL_DATA[str(local_material.id)]["name"],
},
{
"num": 18,
"rarity": MATERIAL_DATA[str(enemy_material.id)]["rank"],
"icon": (await self.assets_service.material(enemy_material.id).icon()).as_uri(),
"name": MATERIAL_DATA[str(enemy_material.id)]["name"],
},
{
"num": 30,
"rarity": MATERIAL_DATA[str(enemy_material.id + 1)]["rank"],
"icon": (await self.assets_service.material(enemy_material.id + 1).icon()).as_uri(),
"name": MATERIAL_DATA[str(enemy_material.id + 1)]["name"],
},
{
"num": 36,
"rarity": MATERIAL_DATA[str(enemy_material.id + 2)]["rank"],
"icon": (await self.assets_service.material(str(enemy_material.id + 2)).icon()).as_uri(),
"name": MATERIAL_DATA[str(enemy_material.id + 2)]["name"],
},
]
talent_book = self.assets_service.material(f"{data[character_name]['talent'][0]}」的教导")
weekly_talent_material = self.assets_service.material(data[character_name]["talent"][1])
talent_materials = [
{
"num": 9,
"rarity": MATERIAL_DATA[str(talent_book.id)]["rank"],
"icon": (await self.assets_service.material(talent_book.id).icon()).as_uri(),
"name": MATERIAL_DATA[str(talent_book.id)]["name"],
},
{
"num": 63,
"rarity": MATERIAL_DATA[str(talent_book.id + 1)]["rank"],
"icon": (await self.assets_service.material(talent_book.id + 1).icon()).as_uri(),
"name": MATERIAL_DATA[str(talent_book.id + 1)]["name"],
},
{
"num": 114,
"rarity": MATERIAL_DATA[str(talent_book.id + 2)]["rank"],
"icon": (await self.assets_service.material(str(talent_book.id + 2)).icon()).as_uri(),
"name": MATERIAL_DATA[str(talent_book.id + 2)]["name"],
},
{
"num": 18,
"rarity": MATERIAL_DATA[str(enemy_material.id)]["rank"],
"icon": (await self.assets_service.material(enemy_material.id).icon()).as_uri(),
"name": MATERIAL_DATA[str(enemy_material.id)]["name"],
},
{
"num": 66,
"rarity": MATERIAL_DATA[str(enemy_material.id + 1)]["rank"],
"icon": (await self.assets_service.material(enemy_material.id + 1).icon()).as_uri(),
"name": MATERIAL_DATA[str(enemy_material.id + 1)]["name"],
},
{
"num": 93,
"rarity": MATERIAL_DATA[str(enemy_material.id + 2)]["rank"],
"icon": (await self.assets_service.material(str(enemy_material.id + 2)).icon()).as_uri(),
"name": MATERIAL_DATA[str(enemy_material.id + 2)]["name"],
},
{
"num": 3,
"rarity": 5,
"icon": (await self.assets_service.material(104319).icon()).as_uri(),
"name": "智识之冕",
},
{
"num": 18,
"rarity": MATERIAL_DATA[str(weekly_talent_material.id)]["rank"],
"icon": (await self.assets_service.material(weekly_talent_material.id).icon()).as_uri(),
"name": MATERIAL_DATA[str(weekly_talent_material.id)]["name"],
},
]
return {
"bot_username": self.application.bot.username,
"character": {
"element": character.enka.element.name,
"image": character.enka.images.banner.url,
"name": character_name,
"association": (await Character.get_by_name(character_name)).association.name,
},
"level_up_materials": level_up_materials,
"talent_materials": talent_materials,
"talent_level": talent_level,
"talent_amount": TalentMaterials(list(map(int, talent_level.split("/")))).cal_materials(),
}
async def render(self, character_name: str, talent_amount: str):
if not self.roles_material:
await self._refresh()
data = await self._parse_material(self.roles_material, character_name, talent_amount)
if not data:
return
return await self.template_service.render(
"genshin/material/roles_material.html",
data,
{"width": 960, "height": 1460},
full_page=True,
ttl=7 * 24 * 60 * 60,
)
@staticmethod
def _is_valid(string: str):
"""
判断字符串是否符合`8/9/10`的格式并保证每个数字都在[110]
"""
return bool(
re.match(r"^\d+/\d+/\d+$", string)
and all(1 <= int(num) <= 10 for num in string.split("/"))
and string != "1/1/1"
and string != "10/10/10"
)
@handler(CommandHandler, command="material", block=False) @handler(CommandHandler, command="material", block=False)
@handler(MessageHandler, filters=filters.Regex("^角色培养素材查询(.*)"), block=False) @handler(MessageHandler, filters=filters.Regex("^角色培养素材查询(.*)"), block=False)
@ -26,6 +209,9 @@ class MaterialPlugin(Plugin):
args = self.get_args(context) args = self.get_args(context)
if len(args) >= 1: if len(args) >= 1:
character_name = args[0] character_name = args[0]
material_count = "8/8/8"
if len(args) >= 2 and self._is_valid(args[1]):
material_count = args[1]
else: else:
reply_message = await message.reply_text( reply_message = await message.reply_text(
"请回复你要查询的培养素材的角色名", reply_markup=InlineKeyboardMarkup(self.KEYBOARD) "请回复你要查询的培养素材的角色名", reply_markup=InlineKeyboardMarkup(self.KEYBOARD)
@ -35,8 +221,10 @@ class MaterialPlugin(Plugin):
self.add_delete_message_job(reply_message) self.add_delete_message_job(reply_message)
return return
character_name = roleToName(character_name) character_name = roleToName(character_name)
url = await self.game_material_service.get_material(character_name) logger.info("用户 %s[%s] 查询角色培养素材命令请求 || 参数 %s", user.full_name, user.id, character_name)
if not url: await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
result = await self.render(character_name, material_count)
if not result:
reply_message = await message.reply_text( reply_message = await message.reply_text(
f"没有找到 {character_name} 的培养素材", reply_markup=InlineKeyboardMarkup(self.KEYBOARD) f"没有找到 {character_name} 的培养素材", reply_markup=InlineKeyboardMarkup(self.KEYBOARD)
) )
@ -44,14 +232,4 @@ class MaterialPlugin(Plugin):
self.add_delete_message_job(message) self.add_delete_message_job(message)
self.add_delete_message_job(reply_message) self.add_delete_message_job(reply_message)
return return
logger.info("用户 %s[%s] 查询角色培养素材命令请求 || 参数 %s", user.full_name, user.id, character_name) await result.reply_photo(message)
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
file_path = await self.download_resource(url, return_path=True)
caption = "From 米游社 " f"查看 [原图]({url})"
await message.reply_photo(
photo=open(file_path, "rb"),
caption=caption,
filename=f"{character_name}.png",
allow_sending_without_reply=True,
parse_mode=ParseMode.MARKDOWN_V2,
)

Binary file not shown.

View File

@ -0,0 +1,363 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8"/>
<title>Title</title>
<script src="../../js/tailwindcss-3.1.8.js"></script>
<link href="../../styles/public.css" rel="stylesheet" type="text/css"/>
<style>
@font-face {
font-family: siyuan;
src: url(../../fonts/SourceHanSerifCN-Heavy.woff) format("woff");
font-style: normal;
}
.text-shadow {
text-shadow: 0 0.08em 0.1em #000, 0 0.1em 0.3em rgba(0, 0, 0, 0.4);
}
.num {
color: white;
text-shadow: black 2px 0 0, black 0 2px 0, black -2px 0 0, black 0 -2px 0;
}
.title-fieldset {
border: none;
border-top: 2px solid;
}
.title-fieldset .inner {
margin: 0 auto;
}
</style>
</head>
<body>
<div class="bg-no-repeat bg-cover overflow-hidden" style="background-image: url('../player_card/img/bg-anemo.jpg')">
<div class="relative round-l-3xl">
<div
class="absolute w-full h-full -left-1/4 -bottom-32 opacity-80 bg-no-repeat bg-center"
style="background-image: url('https://enka.network/ui/UI_Gacha_AvatarImg_Wanderer.png'); background-size: auto 100%; transform: scale(3); "
></div>
<div class="relative">
<div class="flex-1">
<div class="text-7xl text-right text-neutral-200 text-shadow p-10 tracking-wide"
style="font-family: siyuan,serif">
<div class="mb-2 leading-relaxed">
流浪者
</div>
<div class="flex justify-end">
<div class="text-4xl">角色培养素材一览</div>
</div>
</div>
</div>
</div>
</div>
<div class="relative bg-amber-50 text-center text-yellow-900 p-5 m-4 rounded-3xl text-3xl bg-no-repeat bg-center"
style="background-image: url('img/sumeru.webp'); background-size: auto 65%;">
<div class="font-shadow">
<div class="">★等级突破★</div>
<div class="text-left m-10">
<span style="border-left: 8px solid;">&nbsp;</span>
<span>&nbsp;角色90级升级材料</span>
<div class="text-right -mt-1.5" style="float: right">
<span>摩拉消耗</span>
<span class="text-4xl">x2,092,530</span>
</div>
</div>
</div>
<div class="grid grid-cols-5 font-shadow ml-14" style="justify-content: left;">
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
</div>
<div class="relative text-2xl mt-5 font-shadow">
<div class="text-2xl text-gray-700" style="font-family: HYWH,serif">
<span>突破至81级其它材料数量不变&nbsp;摩拉&nbsp;x</span>
<span class="text-3xl">1,444,540&nbsp;&nbsp;</span>
<span>大英雄的经验</span>
<span class="text-3xl">x257<br></span>
</div>
</div>
<fieldset class="title-fieldset bg-yellow-900 mt-6">
<legend class="inner"></legend>
</fieldset>
<div class="font-shadow">
<div class="mt-4">★天赋升级★</div>
<div class="text-left m-10">
<span style="border-left: 8px solid;">&nbsp;</span>
<span>&nbsp;满级天赋升级材料</span>
<div class="text-right -mt-1.5" style="float: right">
<span>摩拉消耗</span>
<span class="text-4xl">x4,957,500</span>
</div>
</div>
</div>
<div class="grid grid-cols-5 font-shadow ml-14" style="justify-content: left;">
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">20</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/5.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('../../assets/material/100021/icon.png'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">Philosophies of Resistance</div>
</div>
</div>
</div>
<div class="relative text-center text-gray-700 text-2xl mt-5 font-shadow" style="font-family: HYWH,serif">
<div style="display: flex;justify-content: center;align-content: center">
<table class="table-auto" style="font-family: HYWH,serif">
<caption>将角色天赋升至8/8/8时所需材料</caption>
<tr>
<th></th>
</tr>
<tr>
<td class="px-6 py-1">「诤言」的教导 x9</td>
<td class="px-6 py-1">「诤言」的指引 x63</td>
<td class="px-6 py-1">「诤言」的哲学 x30</td>
</tr>
<tr>
<td class="px-6 py-1">蕈兽孢子 x18</td>
<td class="px-6 py-1">荧光孢粉 x66</td>
<td class="px-6 py-1">孢囊晶尘 x30</td>
</tr>
<tr>
<td class="px-6 py-1">万劫之真意 x6</td>
<td class="px-6 py-1">摩拉 x1,507,500</td>
</tr>
</table>
</div>
</div>
</div>
<div class="text-xl text-center my-5 num">
Created by @{{ bot_username }}
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

View File

@ -0,0 +1,167 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8"/>
<title>Title</title>
<script src="../../js/tailwindcss-3.1.8.js"></script>
<link href="../../styles/public.css" rel="stylesheet" type="text/css"/>
<style>
@font-face {
font-family: siyuan;
src: url(../../fonts/SourceHanSerifCN-Heavy.woff) format("woff");
font-style: normal;
}
.text-shadow {
text-shadow: 0 0.08em 0.1em #000, 0 0.1em 0.3em rgba(0, 0, 0, 0.4);
}
.num {
color: white;
text-shadow: black 2px 0 0, black 0 2px 0, black -2px 0 0, black 0 -2px 0;
}
.title-fieldset {
border: none;
border-top: 2px solid;
}
.title-fieldset .inner {
margin: 0 auto;
}
</style>
</head>
<body>
<div class="bg-no-repeat bg-cover overflow-hidden" style="background-image: url('../player_card/img/bg-{{ character.element | lower }}.jpg')">
<div class="relative round-l-3xl">
<div
class="absolute w-full h-full -left-1/4 -bottom-32 opacity-80 bg-no-repeat bg-center"
style="background-image: url('{{ character.image }}'); background-size: auto 100%; transform: scale(3); "
></div>
<div class="relative">
<div class="flex-1">
<div class="text-7xl text-right text-neutral-200 text-shadow p-10 tracking-wide"
style="font-family: siyuan,serif">
<div class="mb-2 leading-relaxed">
{{ character.name }}
</div>
<div class="flex justify-end">
<div class="text-4xl">角色培养素材一览</div>
</div>
</div>
</div>
</div>
</div>
<div class="relative bg-amber-50 text-center text-yellow-900 p-5 m-4 rounded-3xl text-3xl bg-no-repeat bg-center"
style="background-image: url('img/{{ character.association | lower}}.webp'); background-size: auto 65%;">
<div class="font-shadow">
<div class="">★等级突破★</div>
<div class="text-left m-10">
<span style="border-left: 8px solid;">&nbsp;</span>
<span>&nbsp;角色90级升级材料</span>
<div class="text-right -mt-1.5" style="float: right">
<span>摩拉消耗</span>
<span class="text-4xl">x2,092,530</span>
</div>
</div>
</div>
<div class="grid grid-cols-5 font-shadow ml-14" style="justify-content: left;">
{% for material in level_up_materials %}
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">{{ material.num }}</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/{{ material.rarity }}.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('{{ material.icon }}'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">{{ material.name }}</div>
</div>
</div>
{% endfor %}
</div>
<div class="relative text-2xl mt-5 font-shadow">
<div class="text-2xl text-gray-700" style="font-family: HYWH,serif">
<span>突破至81级其它材料数量不变&nbsp;摩拉&nbsp;x</span>
<span class="text-3xl">1,444,540&nbsp;&nbsp;</span>
<span>大英雄的经验</span>
<span class="text-3xl">x257<br></span>
</div>
</div>
<fieldset class="title-fieldset bg-yellow-900 mt-6">
<legend class="inner"></legend>
</fieldset>
<div class="font-shadow">
<div class="mt-4">★天赋升级★</div>
<div class="text-left m-10">
<span style="border-left: 8px solid;">&nbsp;</span>
<span>&nbsp;满级天赋升级材料</span>
<div class="text-right -mt-1.5" style="float: right">
<span>摩拉消耗</span>
<span class="text-4xl">x4,957,500</span>
</div>
</div>
</div>
<div class="grid grid-cols-5 font-shadow ml-14" style="justify-content: left;">
{% for material in talent_materials %}
<div class="text-center w-28">
<div class="w-28 h-28">
<div class="text-right text-2xl mr-1 num">{{ material.num }}</div>
<div class="rounded-lg shadow-lg bg-contain bg-no-repeat"
style="background-image: url('../../background/rarity/half/{{ material.rarity }}.png')">
<div class="w-28 h-28 -my-8"
style="background-image: url('{{ material.icon }}'); background-size: auto 100%;"></div>
</div>
</div>
<div class="text-2xl">
<div style="word-wrap:break-word;">{{ material.name }}</div>
</div>
</div>
{% endfor %}
</div>
<div class="relative text-center text-gray-700 text-2xl mt-5 font-shadow" style="font-family: HYWH,serif">
<div style="display: flex;justify-content: center;align-content: center">
<table class="table-auto" style="font-family: HYWH,serif">
<caption>将角色天赋升至{{ talent_level }}时所需材料:</caption>
<tr><th></th></tr>
<tr>
{% for i in range(1, 4) %}
{% if talent_amount[i] > 0 %}
<td class="px-6 py-1">{{ talent_materials[i - 1].name }} x{{ talent_amount[i] }}</td>
{% endif %}
{% endfor %}
</tr>
<tr>
{% for i in range(4, 7) %}
{% if talent_amount[i] > 0 %}
<td class="px-6 py-1">{{ talent_materials[i - 1].name }} x{{ talent_amount[i] }}</td>
{% endif %}
{% endfor %}
</tr>
<tr>
{% for i in range(7, 9) %}
{% if talent_amount[i] > 0 %}
<td class="px-6 py-1">{{ talent_materials[i - 1].name }} x{{ talent_amount[i] }}</td>
{% endif %}
{% endfor %}
{% if talent_amount[0] > 0 %}
<td class="px-6 py-1">摩拉 x{{ talent_amount[0] }}</td>
{% endif %}
</tr>
</table>
</div>
</div>
</div>
<div class="text-xl text-center my-5 num">
Created by @{{ bot_username }}
</div>
</div>
</body>
</html>