From 388cdf1848be5bc2018bf6ee12054bc22783d133 Mon Sep 17 00:00:00 2001 From: Xhichn Date: Mon, 13 Mar 2023 11:41:18 +0800 Subject: [PATCH] Support sync from hoyolab my characters --- .../AvatarInfo/AvatarInfoDbOperation.cs | 88 ++++++++++++------- .../Takumi/GameRecord/GameRecordClientOs.cs | 59 ++++++++++++- 2 files changed, 114 insertions(+), 33 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbOperation.cs index 68b036a9..0a47f975 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbOperation.cs @@ -90,48 +90,72 @@ internal sealed class AvatarInfoDbOperation .ToList(); EnsureItemsAvatarIdDistinct(ref dbInfos, uid); - GameRecordClient gameRecordClient = Ioc.Default.GetRequiredService(); - Response playerInfoResponse = await gameRecordClient - .GetPlayerInfoAsync(userAndUid, token) - .ConfigureAwait(false); + Response playerInfoResponse; + Response charactersResponse; + + if (userAndUid.Uid.Region == "cn_gf01" || userAndUid.Uid.Region == "cn_qd01") + { + GameRecordClient gameRecordClient = Ioc.Default.GetRequiredService(); + playerInfoResponse = await gameRecordClient + .GetPlayerInfoAsync(userAndUid, token) + .ConfigureAwait(false); + + if (!playerInfoResponse.IsOk()) + { + return GetDbAvatarInfos(uid); + } + + charactersResponse = await gameRecordClient + .GetCharactersAsync(userAndUid, playerInfoResponse.Data, token) + .ConfigureAwait(false); + } + else + { + GameRecordClientOs gameRecordClientOs = Ioc.Default.GetRequiredService(); + playerInfoResponse = await gameRecordClientOs + .GetPlayerInfoAsync(userAndUid, token) + .ConfigureAwait(false); + + if (!playerInfoResponse.IsOk()) + { + return GetDbAvatarInfos(uid); + } + + charactersResponse = await gameRecordClientOs + .GetCharactersAsync(userAndUid, playerInfoResponse.Data, token) + .ConfigureAwait(false); + } token.ThrowIfCancellationRequested(); - if (playerInfoResponse.IsOk()) + if (charactersResponse.IsOk()) { - Response charactersResponse = await gameRecordClient - .GetCharactersAsync(userAndUid, playerInfoResponse.Data, token) - .ConfigureAwait(false); + List characters = charactersResponse.Data.Avatars; - if (charactersResponse.IsOk()) + GameRecordCharacterAvatarInfoComposer composer = Ioc.Default.GetRequiredService(); + + foreach (RecordCharacter character in characters) { - List characters = charactersResponse.Data.Avatars; - - GameRecordCharacterAvatarInfoComposer composer = Ioc.Default.GetRequiredService(); - - foreach (RecordCharacter character in characters) + if (AvatarIds.IsPlayer(character.Id)) { - if (AvatarIds.IsPlayer(character.Id)) - { - continue; - } + continue; + } - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - ModelAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == character.Id); + ModelAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == character.Id); - if (entity == null) - { - EnkaAvatarInfo avatarInfo = new() { AvatarId = character.Id }; - avatarInfo = await composer.ComposeAsync(avatarInfo, character).ConfigureAwait(false); - entity = ModelAvatarInfo.Create(uid, avatarInfo); - appDbContext.AvatarInfos.AddAndSave(entity); - } - else - { - entity.Info = await composer.ComposeAsync(entity.Info, character).ConfigureAwait(false); - appDbContext.AvatarInfos.UpdateAndSave(entity); - } + if (entity == null) + { + EnkaAvatarInfo avatarInfo = new() { AvatarId = character.Id }; + avatarInfo = await composer.ComposeAsync(avatarInfo, character).ConfigureAwait(false); + entity = ModelAvatarInfo.Create(uid, avatarInfo); + appDbContext.AvatarInfos.AddAndSave(entity); + } + else + { + entity.Info = await composer.ComposeAsync(entity.Info, character).ConfigureAwait(false); + appDbContext.AvatarInfos.UpdateAndSave(entity); } } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClientOs.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClientOs.cs index 375461af..80bfddcf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClientOs.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClientOs.cs @@ -36,6 +36,24 @@ internal sealed class GameRecordClientOs this.logger = logger; } + /// + /// 获取玩家基础信息 + /// + /// 用户与角色 + /// 取消令牌 + /// 玩家的基础信息 + [ApiInformation(Cookie = CookieType.Ltoken, Salt = SaltType.OS)] + public async Task> GetPlayerInfoAsync(UserAndUid userAndUid, CancellationToken token = default) + { + Response? resp = await httpClient + .SetUser(userAndUid.User, CookieType.Cookie) + .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.OS, false) + .TryCatchGetFromJsonAsync>(ApiOsEndpoints.GameRecordIndex(userAndUid.Uid), options, logger, token) + .ConfigureAwait(false); + + return Response.Response.DefaultIfNull(resp); + } + /// /// 获取玩家深渊信息 /// @@ -46,7 +64,6 @@ internal sealed class GameRecordClientOs [ApiInformation(Cookie = CookieType.Cookie, Salt = SaltType.OS)] public async Task> GetSpiralAbyssAsync(UserAndUid userAndUid, SpiralAbyssSchedule schedule, CancellationToken token = default) { - System.Net.Http.Headers.HttpRequestHeaders headers = httpClient.DefaultRequestHeaders; Response? resp = await httpClient .SetUser(userAndUid.User, CookieType.Cookie) .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.OS, false) @@ -55,4 +72,44 @@ internal sealed class GameRecordClientOs return Response.Response.DefaultIfNull(resp); } + + /// + /// 获取玩家角色详细信息 + /// + /// 用户与角色 + /// 玩家的基础信息 + /// 取消令牌 + /// 角色列表 + [ApiInformation(Cookie = CookieType.Ltoken, Salt = SaltType.X4)] + public async Task> GetCharactersAsync(UserAndUid userAndUid, PlayerInfo playerInfo, CancellationToken token = default) + { + CharacterData data = new(userAndUid.Uid, playerInfo.Avatars.Select(x => x.Id)); + + Response? resp = await httpClient + .SetUser(userAndUid.User, CookieType.Cookie) + .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.OS, false) + .TryCatchPostAsJsonAsync>(ApiOsEndpoints.GameRecordCharacter, data, options, logger, token) + .ConfigureAwait(false); + + return Response.Response.DefaultIfNull(resp); + } + + private class CharacterData + { + public CharacterData(PlayerUid uid, IEnumerable characterIds) + { + CharacterIds = characterIds; + Uid = uid.Value; + Server = uid.Region; + } + + [JsonPropertyName("character_ids")] + public IEnumerable CharacterIds { get; } + + [JsonPropertyName("role_id")] + public string Uid { get; } + + [JsonPropertyName("server")] + public string Server { get; } + } }