diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Annotation/HttpClient/HttpClientConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Annotation/HttpClient/HttpClientConfiguration.cs
index 76609c09..337bf1fd 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Annotation/HttpClient/HttpClientConfiguration.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Annotation/HttpClient/HttpClientConfiguration.cs
@@ -25,7 +25,7 @@ internal enum HttpClientConfiguration
XRpc2,
///
- /// 国际服Hoyolab请求配置
+ /// Hoyolab app
///
XRpc3,
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs
index 9eca4792..c4fd585d 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs
@@ -68,10 +68,26 @@ internal static partial class IocHttpClientConfiguration
///
/// 对于需要添加动态密钥的客户端使用此配置
- /// 国际服 API 测试
+ /// Hoyolab app
///
/// 配置后的客户端
private static void XRpc3Configuration(HttpClient client)
+ {
+ client.Timeout = Timeout.InfiniteTimeSpan;
+ client.DefaultRequestHeaders.UserAgent.ParseAdd(HoyolabOptions.UserAgentOversea);
+ client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
+ client.DefaultRequestHeaders.Add("x-rpc-app_version", HoyolabOptions.XrpcVersionOversea);
+ client.DefaultRequestHeaders.Add("x-rpc-client_type", "5");
+ client.DefaultRequestHeaders.Add("x-rpc-language", "zh-cn");
+ client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);
+ }
+
+ ///
+ /// 对于需要添加动态密钥的客户端使用此配置
+ /// Hoyolab web
+ ///
+ /// 配置后的客户端
+ private static void XRpc4Configuration(HttpClient client)
{
client.Timeout = Timeout.InfiniteTimeSpan;
client.DefaultRequestHeaders.UserAgent.ParseAdd(HoyolabOptions.UserAgentOversea);
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/ApiOsEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/ApiOsEndpoints.cs
index 329972e1..2bf522e0 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/ApiOsEndpoints.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/ApiOsEndpoints.cs
@@ -87,7 +87,7 @@ internal static class ApiOsEndpoints
#endregion
- #region ApiOsTaKumiApi
+ #region ApiOsTakumiBindingApi
///
/// 用户游戏角色
@@ -105,6 +105,12 @@ internal static class ApiOsEndpoints
return $"{ApiAccountOsBindingApi}/getUserGameRolesByLtoken?game_biz=hk4e_global®ion={region}";
}
+ ///
+ /// Game Authkey
+ ///
+ public const string BindingGenAuthKey = $"{ApiAccountOsBindingApi}/genAuthKey";
+
+
#endregion
#region BbsApiOsApi
@@ -119,6 +125,11 @@ internal static class ApiOsEndpoints
return $"{BbsApiOs}/community/painter/wapi/user/full";
}
+ ///
+ /// 用户详细信息
+ ///
+ public const string UserFullInfo = $"{BbsApiOs}/community/user/wapi/getUserFullInfo?gid=2";
+
///
/// 国际服角色基本信息
///
@@ -126,13 +137,13 @@ internal static class ApiOsEndpoints
/// 角色基本信息字符串
public static string GameRecordRoleBasicInfo(in PlayerUid uid)
{
- return $"{BbsApiOsGameRecordApi}/roleBasicInfo?role_id={uid.Value}&server={uid.Region}";
+ return $"{BbsApiOsGameRecordAppApi}/roleBasicInfo?role_id={uid.Value}&server={uid.Region}";
}
///
/// 国际服角色信息
///
- public const string GameRecordCharacter = $"{BbsApiOsGameRecordApi}/character";
+ public const string GameRecordCharacter = $"{BbsApiOsGameRecordAppApi}/character";
///
/// 国际服游戏记录实时便笺
@@ -141,7 +152,7 @@ internal static class ApiOsEndpoints
/// 游戏记录实时便笺字符串
public static string GameRecordDailyNote(in PlayerUid uid)
{
- return $"{BbsApiOsGameRecordApi}/dailyNote?server={uid.Region}&role_id={uid.Value}";
+ return $"{BbsApiOsGameRecordAppApi}/dailyNote?server={uid.Region}&role_id={uid.Value}";
}
///
@@ -151,7 +162,7 @@ internal static class ApiOsEndpoints
/// 游戏记录主页字符串
public static string GameRecordIndex(in PlayerUid uid)
{
- return $"{BbsApiOsGameRecordApi}/index?server={uid.Region}&role_id={uid.Value}";
+ return $"{BbsApiOsGameRecordAppApi}/index?server={uid.Region}&role_id={uid.Value}";
}
///
@@ -162,7 +173,7 @@ internal static class ApiOsEndpoints
/// 深渊信息字符串
public static string GameRecordSpiralAbyss(Hoyolab.Takumi.GameRecord.SpiralAbyssSchedule scheduleType, in PlayerUid uid)
{
- return $"{BbsApiOsGameRecordApi}/spiralAbyss?schedule_type={(int)scheduleType}&role_id={uid.Value}&server={uid.Region}";
+ return $"{BbsApiOsGameRecordAppApi}/spiralAbyss?server={uid.Region}&role_id={uid.Value}&schedule_type={(int)scheduleType}";
}
#endregion
@@ -247,12 +258,12 @@ internal static class ApiOsEndpoints
private const string ApiOsTakumi = "https://api-os-takumi.hoyoverse.com";
private const string ApiOsTakumiBindingApi = $"{ApiOsTakumi}/binding/api";
- private const string ApiAccountOs = "https://api-account-os.hoyolab.com";
+ private const string ApiAccountOs = "https://api-account-os.hoyoverse.com";
private const string ApiAccountOsBindingApi = $"{ApiAccountOs}/binding/api";
private const string ApiAccountOsAuthApi = $"{ApiAccountOs}/account/auth/api";
- private const string BbsApiOs = "https://bbs-api-os.hoyolab.com";
- private const string BbsApiOsGameRecordApi = $"{BbsApiOs}/game_record/genshin/api";
+ private const string BbsApiOs = "https://bbs-api-os.hoyoverse.com";
+ private const string BbsApiOsGameRecordAppApi = $"{BbsApiOs}/game_record/app/genshin/api";
private const string Hk4eApiOs = "https://hk4e-api-os.hoyoverse.com";
private const string Hk4eApiOsGachaInfoApi = $"{Hk4eApiOs}/event/gacha_info/api";
@@ -260,7 +271,7 @@ internal static class ApiOsEndpoints
private const string SdkOsStatic = "https://sdk-os-static.mihoyo.com";
private const string SdkOsStaticLauncherApi = $"{SdkOsStatic}/hk4e_global/mdk/launcher/api";
- private const string SgPublicApi = "https://sg-public-api.hoyolab.com";
+ private const string SgPublicApi = "https://sg-public-api.hoyoverse.com";
private const string WebApiOs = "https://webapi-os.account.hoyoverse.com";
private const string WebApiOsAccountApi = $"{WebApiOs}/Api";
@@ -275,5 +286,10 @@ internal static class ApiOsEndpoints
///
public const string ActHoyolabReferer = "https://act.hoyolab.com/";
+ ///
+ /// App hoyolab referer
+ ///
+ public const string AppHoyolabReferer = "https://app.hoyolab.com/";
+
#endregion
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs
index 366d0f12..1d0a768c 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs
@@ -47,22 +47,4 @@ internal sealed partial class UserClient : IUserClient
return Response.Response.DefaultIfNull(resp);
}
-
- ///
- /// 获取当前用户详细信息,使用 LToken
- ///
- /// 用户
- /// 取消令牌
- /// 详细信息
- [ApiInformation(Cookie = CookieType.LToken, Salt = SaltType.OSK2)]
- public async Task> GetOsUserFullInfoAsync(Model.Entity.User user, CancellationToken token = default)
- {
- Response? resp = await httpClient
- .SetUser(user, CookieType.LToken)
- .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.OSK2, false)
- .TryCatchGetFromJsonAsync>(ApiOsEndpoints.UserFullInfoQuery(user.Aid!), options, logger, token)
- .ConfigureAwait(false);
-
- return Response.Response.DefaultIfNull(resp);
- }
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/SaltType.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/SaltType.cs
index ab1f0a8e..af6f2931 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/SaltType.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/SaltType.cs
@@ -14,6 +14,11 @@ internal enum SaltType
///
None,
+ ///
+ /// PROD
+ ///
+ PROD,
+
///
/// X4
///
@@ -24,11 +29,6 @@ internal enum SaltType
///
X6,
- ///
- /// PROD
- ///
- PROD,
-
///
/// K2
///
@@ -40,7 +40,22 @@ internal enum SaltType
LK2,
///
- /// Hoyolab K2
+ /// OSK2
///
OSK2,
+
+ ///
+ /// OSLK
+ ///
+ OSLK2,
+
+ ///
+ /// OSX4
+ ///
+ OSX4,
+
+ ///
+ /// OSX6
+ ///
+ OSX6,
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs
index 58847511..94073738 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabOptions.cs
@@ -41,19 +41,23 @@ internal sealed class HoyolabOptions : IOptions
///
/// Hoyolab Rpc 版本
///
- public const string XrpcVersionOversea = "2.30.0";
+ public const string XrpcVersionOversea = "2.31.0";
// https://github.com/UIGF-org/Hoyolab.Salt
private static readonly ImmutableDictionary SaltsInner = new Dictionary()
{
+ // Chinese
[SaltType.K2] = "A4lPYtN0KGRVwE5M5Fm0DqQiC5VVMVM3",
[SaltType.LK2] = "kkFiNdhyHqZ1VnDRHnU1podIvO4eiHcs",
[SaltType.X4] = "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs",
[SaltType.X6] = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
[SaltType.PROD] = "JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS",
- // This SALT is not reliable
- [SaltType.OSK2] = "6cqshh5dhw73bzxn20oexa9k516chk7s",
+ // Oversea
+ [SaltType.OSK2] = "599uqkwc0dlqu3h6epzjzfhgyyrd44ae",
+ [SaltType.OSLK2] = "rk4xg2hakoi26nljpr099fv9fck1ah10",
+ [SaltType.OSX4] = "h4c1d6ywfq5bsbnbhm1bzq7bxzzv6srt",
+ [SaltType.OSX6] = "okr4obncj8bw5a65hbnn5oo6ixjc3l9w",
}.ToImmutableDictionary();
private static string? deviceId;
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClientOversea.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClientOversea.cs
index 731174c8..1ca0e0d5 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClientOversea.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClientOversea.cs
@@ -37,12 +37,12 @@ internal sealed partial class GameRecordClientOversea : IGameRecordClient
/// 用户与角色
/// 取消令牌
/// 实时便笺
- [ApiInformation(Cookie = CookieType.Cookie, Salt = SaltType.OSK2)]
+ [ApiInformation(Cookie = CookieType.Cookie, Salt = SaltType.OSX4)]
public async Task> GetDailyNoteAsync(UserAndUid userAndUid, CancellationToken token = default)
{
Response? resp = await httpClient
.SetUser(userAndUid.User, CookieType.Cookie)
- .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.OSK2, false)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.OSX4, false)
.TryCatchGetFromJsonAsync>(ApiOsEndpoints.GameRecordDailyNote(userAndUid.Uid.Value), options, logger, token)
.ConfigureAwait(false);
@@ -55,12 +55,12 @@ internal sealed partial class GameRecordClientOversea : IGameRecordClient
/// 用户与角色
/// 取消令牌
/// 玩家的基础信息
- [ApiInformation(Cookie = CookieType.LToken, Salt = SaltType.OSK2)]
+ [ApiInformation(Cookie = CookieType.LToken, Salt = SaltType.OSX4)]
public async Task> GetPlayerInfoAsync(UserAndUid userAndUid, CancellationToken token = default)
{
Response? resp = await httpClient
.SetUser(userAndUid.User, CookieType.Cookie)
- .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.OSK2, false)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.OSX4, false)
.TryCatchGetFromJsonAsync>(ApiOsEndpoints.GameRecordIndex(userAndUid.Uid), options, logger, token)
.ConfigureAwait(false);
@@ -74,12 +74,12 @@ internal sealed partial class GameRecordClientOversea : IGameRecordClient
/// 1:当期,2:上期
/// 取消令牌
/// 深渊信息
- [ApiInformation(Cookie = CookieType.Cookie, Salt = SaltType.OSK2)]
+ [ApiInformation(Cookie = CookieType.Cookie, Salt = SaltType.OSX4)]
public async Task> GetSpiralAbyssAsync(UserAndUid userAndUid, SpiralAbyssSchedule schedule, CancellationToken token = default)
{
Response? resp = await httpClient
.SetUser(userAndUid.User, CookieType.Cookie)
- .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.OSK2, false)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.OSX4, false)
.TryCatchGetFromJsonAsync>(ApiOsEndpoints.GameRecordSpiralAbyss(schedule, userAndUid.Uid), options, logger, token)
.ConfigureAwait(false);
@@ -93,14 +93,14 @@ internal sealed partial class GameRecordClientOversea : IGameRecordClient
/// 玩家的基础信息
/// 取消令牌
/// 角色列表
- [ApiInformation(Cookie = CookieType.LToken, Salt = SaltType.OSK2)]
+ [ApiInformation(Cookie = CookieType.LToken, Salt = SaltType.OSX4)]
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.OSK2, false)
+ .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.OSX4, false)
.TryCatchPostAsJsonAsync>(ApiOsEndpoints.GameRecordCharacter, data, options, logger, token)
.ConfigureAwait(false);