Skip to content

Commit

Permalink
feat: head icons
Browse files Browse the repository at this point in the history
  • Loading branch information
omg-xtao committed Mar 28, 2024
1 parent 08e6923 commit 21eb9a9
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 6 deletions.
7 changes: 4 additions & 3 deletions fix_data.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import asyncio

from res_func.avatar import fix_avatar_config, fetch_text_map
from res_func.avatar import fix_avatar_config
from res_func.light_cone import fix_light_cone_config
from res_func.relic import fetch_relic_config
from res_func.relic_res import fix_set_image
from res_func.yatta.avatar import get_all_avatars
from res_func.head_icon import get_head_icons


async def main():
text_map_data = await fetch_text_map()
await fix_avatar_config(text_map_data)
await fix_avatar_config()
await fix_light_cone_config()
await fetch_relic_config()
await fix_set_image()
await get_all_avatars()
await get_head_icons()


if __name__ == "__main__":
Expand Down
41 changes: 41 additions & 0 deletions models/head_icon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from typing import List, Optional

from pydantic import BaseModel


class HeadIcon(BaseModel):
id: int
name: str
desc: str
bg_desc: str
avatar_id: Optional[int] = None
icons: List[str]

@property
def icon(self) -> str:
for icon in self.icons:
if icon:
return icon


# 原始数据

class ForHash(BaseModel):
Hash: str


class ItemPlayerCard(BaseModel):
ID: int
ItemSubType: str
ItemName: ForHash
ItemDesc: ForHash
ItemBGDesc: ForHash


class PlayerIcon(BaseModel):
ID: int
ImagePath: str


class AvatarPlayerIcon(PlayerIcon):
AvatarID: int
13 changes: 10 additions & 3 deletions res_func/avatar.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ async def fetch_text_map() -> Dict[str, str]:
return await get_base_data(text_map)


async def fetch_config(text_map_data: Dict[str, str]) -> List[AvatarConfig]:
async def fetch_config() -> List[AvatarConfig]:
text_map_data = await get_base_data(text_map)
data = await get_base_data(avatar_config)
datas = []
for i in data.values():
Expand Down Expand Up @@ -65,6 +66,12 @@ async def dump_icons(path: Path, datas: List[AvatarIcon]):
await f.write(ujson.dumps(data, indent=4, ensure_ascii=False))


async def load_icons(path: Path) -> List[AvatarIcon]:
async with aiofiles.open(path, "r", encoding="utf-8") as f:
data = await f.read()
return [AvatarIcon(**i) for i in ujson.loads(data)]


async def fetch_station_ktz(tasks, datas, player_avatars: List[Tag]):
data_map = {"开拓者·毁灭": (8001, 8002), "开拓者·存护": (8003, 8004)}
idx = 0
Expand Down Expand Up @@ -105,8 +112,8 @@ async def fix_avatar_config_ktz():
all_avatars_map[i].name = key


async def fix_avatar_config(text_map_data: Dict[str, str]):
configs = await fetch_config(text_map_data)
async def fix_avatar_config():
configs = await fetch_config()
configs_map: Dict[str, AvatarConfig] = {config.name: config for config in configs}
print(f"读取到原始数据:{list(configs_map.keys())}")
data_path = Path("data")
Expand Down
117 changes: 117 additions & 0 deletions res_func/head_icon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
from pathlib import Path
from typing import List, Dict

import aiofiles
import ujson
from bs4 import BeautifulSoup

from models.head_icon import HeadIcon, ItemPlayerCard, PlayerIcon, AvatarPlayerIcon

from .avatar import load_icons
from .base_data import get_base_data
from .client import client
from .url import avatar_player_icon_url, player_icon_url, item_player_card_url, text_map, icons_url, base_enka_url

data_path = Path("data")


async def get_text_map() -> dict[str, str]:
return await get_base_data(text_map)


async def get_avatar_player_icon() -> List[AvatarPlayerIcon]:
data = await get_base_data(avatar_player_icon_url)
datas = []
for i in data.values():
datas.append(AvatarPlayerIcon(**i))
return datas


async def get_player_icon() -> List[PlayerIcon]:
data = await get_base_data(player_icon_url)
datas = []
for i in data.values():
datas.append(PlayerIcon(**i))
return datas


async def get_item_player_card() -> List[ItemPlayerCard]:
data = await get_base_data(item_player_card_url)
datas = []
for i in data.values():
datas.append(ItemPlayerCard(**i))
return datas


async def parse_station_urls() -> Dict[str, str]:
data = await client.get(icons_url)
soup = BeautifulSoup(data.text, "lxml")
a_s = soup.find_all("a", {"class": "a4041 af418 a4294"})
datas = {}
for a in a_s:
img = a.find("img")
span = a.find("span")
datas[span.get_text().strip()] = img.get("src")
return datas


async def test_enka_url(path: str) -> str:
url = f"{base_enka_url}{path}"
data = await client.head(url)
if data.status_code != 200:
return ""
return url


async def extra_head_icons(item_player_card: List[ItemPlayerCard], player_icon: List[PlayerIcon]) -> List[HeadIcon]:
player_icon_map: Dict[int, PlayerIcon] = {i.ID: i for i in player_icon}
text_map_ = await get_text_map()
station_urls = await parse_station_urls()
datas = []
for item in item_player_card:
if item.ItemSubType != "HeadIcon":
continue
id_ = item.ID
name = text_map_[item.ItemName.Hash]
desc = text_map_.get(item.ItemDesc.Hash, "")
bg_desc = text_map_.get(item.ItemBGDesc.Hash, "")
icon = player_icon_map[id_].ImagePath
station_url = station_urls.get(name, "")
enka_url = await test_enka_url(icon)
icons = [station_url, enka_url]
datas.append(HeadIcon(id=id_, name=name, desc=desc, bg_desc=bg_desc, icons=icons))
return datas


async def dump_icons(path: Path, datas: List[HeadIcon]):
data = [icon.dict() for icon in datas]
data.sort(key=lambda x: x["id"])
async with aiofiles.open(path, "w", encoding="utf-8") as f:
await f.write(ujson.dumps(data, indent=4, ensure_ascii=False))


async def avatar_head_icons(avatar_player_icon: List[AvatarPlayerIcon]):
avatar_icons = await load_icons(data_path / "avatar_icons.json")
avatar_icons_map = {i.id: i for i in avatar_icons}
datas = []
for i in avatar_player_icon:
avatar = avatar_icons_map.get(i.AvatarID)
name = avatar.name
station_url = avatar.icon_ or ""
enka_url = await test_enka_url(i.ImagePath)
icons = [station_url, enka_url]
datas.append(HeadIcon(id=i.ID, name=name, desc="", bg_desc="", avatar_id=i.AvatarID, icons=icons))
return datas


async def get_head_icons():
print("开始获取头像素材")
item_player_card = await get_item_player_card()
player_icon = await get_player_icon()
avatar_player_icon = await get_avatar_player_icon()
print("开始获取特殊头像")
datas = await extra_head_icons(item_player_card, player_icon)
print("开始获取角色头像")
datas.extend(await avatar_head_icons(avatar_player_icon))
await dump_icons(data_path / "head_icons.json", datas)
print("头像素材获取完毕")
10 changes: 10 additions & 0 deletions res_func/url.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,23 @@
relic_config = f"{base_data_url}ExcelOutput/RelicConfig.json"
relic_main_affix_config = f"{base_data_url}ExcelOutput/RelicMainAffixConfig.json"
relic_sub_affix_config = f"{base_data_url}ExcelOutput/RelicSubAffixConfig.json"
avatar_player_icon_url = f"{base_data_url}ExcelOutput/AvatarPlayerIcon.json"
player_icon_url = f"{base_data_url}ExcelOutput/PlayerIcon.json"
item_player_card_url = f"{base_data_url}ExcelOutput/ItemPlayerCard.json"


base_station_url = "https://starrailstation.com"
avatar_url = f"{base_station_url}/cn/characters"
light_cone_url = f"{base_station_url}/cn/equipment"
relic_url = f"{base_station_url}/cn/relics"
icons_url = f"{base_station_url}/cn/icons"


base_yatta_url = "https://api.yatta.top"
avatar_yatta_url = f"{base_yatta_url}/hsr/v2/cn/avatar"
avatar_skill_url = f"{base_yatta_url}/hsr/assets/UI/skill/"
light_cone_yatta_url = f"{base_yatta_url}/hsr/v2/cn/equipment"
material_yatta_url = f"{base_yatta_url}/hsr/v2/cn/item"
relic_yatta_url = f"{base_yatta_url}/hsr/v2/cn/relic"

base_enka_url = "https://enka.network/ui/hsr/"

0 comments on commit 21eb9a9

Please sign in to comment.