1
1
from __future__ import annotations
2
2
3
3
from collections import defaultdict
4
- from typing import TYPE_CHECKING , Any
4
+ from typing import TYPE_CHECKING , Any , cast
5
5
6
6
import discord
7
7
from ambr .utils import remove_html_tags
19
19
TheaterBuff ,
20
20
)
21
21
from genshin .models import Character as GICharacter
22
+ from loguru import logger
22
23
23
24
from hoyo_buddy .bot .error_handler import get_error_embed
24
25
from hoyo_buddy .constants import GAME_CHALLENGE_TYPES , GPY_LANG_TO_LOCALE , TRAVELER_IDS
@@ -218,47 +219,74 @@ async def _fetch_data(self) -> None:
218
219
client = self .account .client
219
220
client .set_lang (self .locale )
220
221
221
- if (
222
- self .challenge_type in {ChallengeType .SPIRAL_ABYSS , ChallengeType .IMG_THEATER }
223
- and not self .characters
224
- ):
225
- self .characters = await client .get_genshin_characters (self .account .uid )
226
-
227
222
await client .get_record_cards ()
228
223
229
224
for previous in (False , True ):
230
225
if self .challenge_type is ChallengeType .SPIRAL_ABYSS :
231
- challenge = await client .get_genshin_spiral_abyss (
232
- self .account .uid , previous = previous
226
+ raw = await client .get_genshin_spiral_abyss (
227
+ self .account .uid , previous = previous , raw = True
233
228
)
234
229
elif self .challenge_type is ChallengeType .MOC :
235
- challenge = await client .get_starrail_challenge (self .account .uid , previous = previous )
230
+ raw = await client .get_starrail_challenge (
231
+ self .account .uid , previous = previous , raw = True
232
+ )
236
233
elif self .challenge_type is ChallengeType .PURE_FICTION :
237
- challenge = await client .get_starrail_pure_fiction (
238
- self .account .uid , previous = previous
234
+ raw = await client .get_starrail_pure_fiction (
235
+ self .account .uid , previous = previous , raw = True
239
236
)
240
237
elif self .challenge_type is ChallengeType .APC_SHADOW :
241
- challenge = await client .get_starrail_apc_shadow (
242
- self .account .uid , previous = previous
238
+ raw = await client .get_starrail_apc_shadow (
239
+ self .account .uid , previous = previous , raw = True
243
240
)
244
241
elif self .challenge_type is ChallengeType .IMG_THEATER :
245
- challenges = (
246
- await client .get_imaginarium_theater (self .account .uid , previous = previous )
247
- ).datas
248
- if not challenges :
242
+ raw_ = await client .get_imaginarium_theater (
243
+ self .account .uid , previous = previous , raw = True
244
+ )
245
+ datas : list [dict [str , Any ]] = raw_ .get ("data" , [])
246
+ if not datas :
249
247
raise NoChallengeDataError (ChallengeType .IMG_THEATER )
250
248
251
- challenge = max (challenges , key = lambda c : c .stats .difficulty .value )
249
+ try :
250
+ raw = max (datas , key = lambda d : d ["stat" ]["difficulty_id" ])
251
+ except KeyError :
252
+ logger .error ("Failed to get max difficulty ID from data" , datas = datas )
253
+ raw = datas [- 1 ]
252
254
elif self .challenge_type is ChallengeType .SHIYU_DEFENSE :
253
- if not self .agent_ranks :
255
+ raw = await client .get_shiyu_defense (self .account .uid , previous = previous , raw = True )
256
+ challenge = ChallengeHistory .load_data (raw , challenge_type = self .challenge_type )
257
+ challenge = cast ("ShiyuDefense" , challenge )
258
+
259
+ # Backward compatibility, ShiyuDefenseCharacter.mindscape is added in
260
+ # https://github.com/thesadru/genshin.py/commit/4e17d37f84048d2b0a478b45e374f980a7bbe3a3
261
+ is_new_ver = (
262
+ challenge .floors
263
+ and challenge .floors [0 ].node_1 .characters
264
+ and hasattr (challenge .floors [0 ].node_1 .characters [0 ], "mindscape" )
265
+ )
266
+
267
+ # No need to fetch agent ranks if the data is using new version
268
+ if challenge .has_data and not self .agent_ranks and not is_new_ver :
254
269
agents = await client .get_zzz_agents (self .account .uid )
255
270
self .agent_ranks = {agent .id : agent .rank for agent in agents }
256
- challenge = await client .get_shiyu_defense (self .account .uid , previous = previous )
257
271
elif self .challenge_type is ChallengeType .ASSAULT :
258
- challenge = await client .get_deadly_assault (self .account .uid , previous = previous )
272
+ raw = await client .get_deadly_assault (self .account .uid , previous = previous , raw = True )
259
273
else :
260
- msg = f"Invalid challenge type: { self .challenge_type } "
261
- raise ValueError (msg )
274
+ msg = f"Fetching data for { self .challenge_type !r} "
275
+ raise NotImplementedError (msg )
276
+
277
+ challenge = ChallengeHistory .load_data (raw , challenge_type = self .challenge_type )
278
+
279
+ if (
280
+ self .challenge_type in {ChallengeType .SPIRAL_ABYSS , ChallengeType .IMG_THEATER }
281
+ and not self .characters
282
+ ):
283
+ # Only fetch characters when challenge has data
284
+ try :
285
+ self .check_challenge_data (challenge )
286
+ except NoChallengeDataError :
287
+ pass
288
+ else :
289
+ self .characters = await client .get_genshin_characters (self .account .uid )
262
290
263
291
try :
264
292
season_id = self ._get_season_id (challenge , previous )
@@ -276,18 +304,20 @@ async def _fetch_data(self) -> None:
276
304
uid = self .account .uid ,
277
305
challenge_type = self .challenge_type ,
278
306
season_id = season_id ,
279
- data = challenge ,
307
+ raw = raw ,
280
308
lang = client .lang ,
281
309
)
282
310
283
311
def check_challenge_data (self , challenge : Challenge | None ) -> None :
312
+ """Check if the challenge has data and raise an error if it doesn't"""
313
+ exc = NoChallengeDataError (self .challenge_type )
284
314
if challenge is None :
285
- raise NoChallengeDataError ( self . challenge_type )
315
+ raise exc
286
316
if isinstance (challenge , SpiralAbyss ):
287
317
if not challenge .floors :
288
318
raise NoChallengeDataError (ChallengeType .SPIRAL_ABYSS )
289
319
elif not challenge .has_data :
290
- raise NoChallengeDataError ( self . challenge_type )
320
+ raise exc
291
321
292
322
def get_season (self , challenge : Challenge ) -> StarRailChallengeSeason :
293
323
if isinstance (challenge , SpiralAbyss | ImgTheaterData | ShiyuDefense | DeadlyAssault ):
0 commit comments