-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresource.py
140 lines (108 loc) · 4.95 KB
/
resource.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
from io import BytesIO
from math import ceil
from pathlib import Path
from typing import TypeVar
from pydantic import parse_obj_as
from .model import Chart, UserPost, BestdoriSongMeta, Bands, Language, ChartMeta, DifficultyInt
from .utils import get_client
difficulty_literal = ['easy', 'normal', 'hard', 'expert', 'special']
assets = Path(__file__).parent / 'assets'
cached_songs: dict[int, BestdoriSongMeta] = {} # song_id: song
cached_bands: dict[int, str] = {} # band_id: band_name
_T = TypeVar('_T')
class InGameResourceManager(object):
background = assets / 'liveBG_normal.png'
default_jacket = assets / 'default_jacket.png'
normal = assets / 'note_normal_3.png'
normal_16 = assets / 'note_normal_16_3.png'
skill = assets / 'note_skill_3.png'
long = assets / 'note_long_3.png'
connection = assets / 'note_slide_among.png'
flick = assets / 'note_flick_3.png'
flick_top = assets / 'note_flick_top.png'
flick_left = assets / 'note_flick_l_3.png'
flick_right = assets / 'note_flick_r_3.png'
flick_left_top = assets / 'note_flick_top_l.png'
flick_right_top = assets / 'note_flick_top_r.png'
class FontResourceMangaer(object):
font_arial_bd = assets / 'arialbd.ttf'
font_a_otf_shingopro_medium_2 = assets / 'A-OTF-ShinGoPro-Medium-2.otf'
async def get_chart_official(song_id: int, difficulty: DifficultyInt) -> Chart:
async with get_client() as client:
response = await client.get(f'https://bestdori.com/api/charts/{song_id}/{difficulty_literal[difficulty]}.json')
response.raise_for_status()
return parse_obj_as(Chart, response.json())
async def get_chart_user_post(post_id: int) -> UserPost:
async with get_client() as client:
response = await client.get(f'https://bestdori.com/api/post/details?id={post_id}')
response.raise_for_status()
return UserPost(**response.json())
async def get_song_jacket(url: str) -> BytesIO:
try:
async with get_client() as client:
response = await client.get(url)
response.raise_for_status()
return BytesIO(response.content)
except Exception: # noqa
with open(InGameResourceManager.default_jacket, 'rb') as f:
return BytesIO(f.read())
async def get_song_official(song_id: int) -> BestdoriSongMeta:
if song_id in cached_songs:
return cached_songs[song_id]
async with get_client() as client:
response = await client.get(f'https://bestdori.com/api/songs/{song_id}.json')
response.raise_for_status()
cached_songs.update({song_id: parse_obj_as(BestdoriSongMeta, response.json())})
return cached_songs[song_id]
def get_valid_value_from_list(value_list: list[_T]) -> _T:
return (
value_list[Language.Japanese] or
value_list[Language.ChineseSimplified] or
value_list[Language.ChineseTraditional] or
value_list[Language.English] or
value_list[Language.Korean]
)
async def get_band_official(band_id: int) -> str:
if band_id in cached_bands:
return cached_bands[band_id]
async with get_client() as client:
response = await client.get('https://bestdori.com/api/bands/all.1.json')
response.raise_for_status()
bands = parse_obj_as(Bands, response.json()).__root__
cached_bands.update({_band_id: get_valid_value_from_list(_band_name_list.bandName) for _band_id, _band_name_list in bands.items()})
return cached_bands[band_id]
def get_song_jacket_url_official(song_id: int, jacket_name: str) -> str:
jacket_pack_id = ceil(song_id / 10) * 10
if 1000 <= song_id < 10001: # 1000, 1001, 1004 is EN exclusive
server = 'en'
elif 10001 <= song_id: # 10001 is CN exclusive
server = 'cn'
else:
server = 'jp'
return (f'https://bestdori.com/'
f'assets/{server}/musicjacket/musicjacket{jacket_pack_id}_rip/'
f'assets-star-forassetbundle-startapp-musicjacket-musicjacket{jacket_pack_id}-{jacket_name}-thumb.png')
async def generate_song_meta_official(meta: BestdoriSongMeta, song_id: int, difficulty: DifficultyInt) -> ChartMeta:
return ChartMeta(
id=song_id,
title=get_valid_value_from_list(meta.musicTitle),
level=meta.difficulty[difficulty].playLevel,
difficulty=DifficultyInt(difficulty),
release=get_valid_value_from_list(meta.publishedAt),
is_official=True,
artist=await get_band_official(meta.bandId),
lyricist=get_valid_value_from_list(meta.lyricist),
composer=get_valid_value_from_list(meta.composer),
arranger=get_valid_value_from_list(meta.arranger),
)
def generate_song_meta_user_post(post: UserPost.Post, post_id: int) -> ChartMeta:
return ChartMeta(
id=post_id,
title=post.title,
level=post.level,
difficulty=DifficultyInt(post.diff),
release=post.time,
is_official=False,
artist=post.artists,
chart_designer=post.author.nickname or post.author.username,
)