mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
phase 3
This commit is contained in:
@@ -4723,7 +4723,7 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Cookie 操作 的本地化字符串。
|
/// 查找类似 米游社 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ViewUserCookieOperation {
|
internal static string ViewUserCookieOperation {
|
||||||
get {
|
get {
|
||||||
|
|||||||
@@ -1639,7 +1639,7 @@
|
|||||||
<value>工具</value>
|
<value>工具</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewUserCookieOperation" xml:space="preserve">
|
<data name="ViewUserCookieOperation" xml:space="preserve">
|
||||||
<value>Cookie 操作</value>
|
<value>米游社</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewUserCookieOperationLoginMihoyoUserAction" xml:space="preserve">
|
<data name="ViewUserCookieOperationLoginMihoyoUserAction" xml:space="preserve">
|
||||||
<value>网页登录</value>
|
<value>网页登录</value>
|
||||||
|
|||||||
@@ -109,9 +109,8 @@ internal sealed class DailyNoteService : IDailyNoteService, IRecipient<UserRemov
|
|||||||
using (IServiceScope scope = scopeFactory.CreateScope())
|
using (IServiceScope scope = scopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||||
GameRecordClient gameRecordClient = scope.ServiceProvider.GetRequiredService<GameRecordClient>();
|
|
||||||
GameRecordClientOversea gameRecordClientOs = scope.ServiceProvider.GetRequiredService<GameRecordClientOversea>();
|
|
||||||
|
|
||||||
|
// TODO: Add this option to AppOptions
|
||||||
bool isSilentMode = appDbContext.Settings
|
bool isSilentMode = appDbContext.Settings
|
||||||
.SingleOrAdd(SettingEntry.DailyNoteSilentWhenPlayingGame, Core.StringLiterals.False)
|
.SingleOrAdd(SettingEntry.DailyNoteSilentWhenPlayingGame, Core.StringLiterals.False)
|
||||||
.GetBoolean();
|
.GetBoolean();
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
InputScope="Number"
|
InputScope="Number"
|
||||||
MaxLength="9"
|
MaxLength="9"
|
||||||
PlaceholderText="Please fill in your User ID here"/>
|
PlaceholderText="{shcm:ResourceString Name=ViewPageLoginHoyoverseUserHint}"/>
|
||||||
<Button
|
<Button
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Click="CookieButtonClick"
|
Click="CookieButtonClick"
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ internal sealed partial class LoginHoyoverseUserPage : Microsoft.UI.Xaml.Control
|
|||||||
if (uid.Length != 9)
|
if (uid.Length != 9)
|
||||||
{
|
{
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
infoBarService.Information($"请在页面右上方的输入框处填写你的通行证 ID!");
|
infoBarService.Information(SH.ViewPageLoginHoyoverseUserHint);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ internal sealed partial class LoginHoyoverseUserPage : Microsoft.UI.Xaml.Control
|
|||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<string, string> multiTokenMap = multiTokenResponse.Data.List.ToDictionary(n => n.Name, n => n.Token);
|
Dictionary<string, string> multiTokenMap = multiTokenResponse.Data.List.ToDictionary(n => n.Name, n => n.Token);
|
||||||
Cookie hoyoLabCookie = Cookie.Parse($"stoken={multiTokenMap["stoken"]}; stuid={uid}");
|
Cookie hoyoLabCookie = Cookie.Parse($"{Cookie.STUID}={uid};{Cookie.STOKEN}={multiTokenMap[Cookie.STOKEN]}");
|
||||||
|
|
||||||
// 处理 cookie 并添加用户
|
// 处理 cookie 并添加用户
|
||||||
(UserOptionResult result, string nickname) = await Ioc.Default
|
(UserOptionResult result, string nickname) = await Ioc.Default
|
||||||
@@ -100,16 +100,16 @@ internal sealed partial class LoginHoyoverseUserPage : Microsoft.UI.Xaml.Control
|
|||||||
vm.SelectedUser = vm.Users.Single();
|
vm.SelectedUser = vm.Users.Single();
|
||||||
}
|
}
|
||||||
|
|
||||||
infoBarService.Success($"用户 [{nickname}] 添加成功");
|
infoBarService.Success(string.Format(SH.ViewModelUserAdded, nickname));
|
||||||
break;
|
break;
|
||||||
case UserOptionResult.Incomplete:
|
case UserOptionResult.Incomplete:
|
||||||
infoBarService.Information($"此 Cookie 不完整,操作失败");
|
infoBarService.Information(SH.ViewModelUserIncomplete);
|
||||||
break;
|
break;
|
||||||
case UserOptionResult.Invalid:
|
case UserOptionResult.Invalid:
|
||||||
infoBarService.Information($"此 Cookie 无效,操作失败");
|
infoBarService.Information(SH.ViewModelUserInvalid);
|
||||||
break;
|
break;
|
||||||
case UserOptionResult.Updated:
|
case UserOptionResult.Updated:
|
||||||
infoBarService.Success($"用户 [{nickname}] 更新成功");
|
infoBarService.Success(string.Format(SH.ViewModelUserUpdated, nickname));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw Must.NeverHappen();
|
throw Must.NeverHappen();
|
||||||
|
|||||||
@@ -67,9 +67,10 @@ internal sealed partial class LoginMihoyoUserPage : Microsoft.UI.Xaml.Controls.P
|
|||||||
|
|
||||||
Dictionary<string, string> multiTokenMap = multiTokenResponse.Data.List.ToDictionary(n => n.Name, n => n.Token);
|
Dictionary<string, string> multiTokenMap = multiTokenResponse.Data.List.ToDictionary(n => n.Name, n => n.Token);
|
||||||
|
|
||||||
Cookie stokenV1 = Cookie.Parse($"stuid={loginTicketCookie["login_uid"]};stoken={multiTokenMap["stoken"]}");
|
Cookie stokenV1 = Cookie.Parse($"{Cookie.STUID}={loginTicketCookie[Cookie.LOGIN_UID]};{Cookie.STOKEN}={multiTokenMap[Cookie.STOKEN]}");
|
||||||
|
|
||||||
Response<LoginResult> loginResultResponse = await Ioc.Default
|
Response<LoginResult> loginResultResponse = await Ioc.Default
|
||||||
.GetRequiredService<PassportClient2>()
|
.GetRequiredService<PassportClient>()
|
||||||
.LoginBySTokenAsync(stokenV1, token)
|
.LoginBySTokenAsync(stokenV1, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
@@ -87,6 +88,7 @@ internal sealed partial class LoginMihoyoUserPage : Microsoft.UI.Xaml.Controls.P
|
|||||||
Ioc.Default.GetRequiredService<INavigationService>().GoBack();
|
Ioc.Default.GetRequiredService<INavigationService>().GoBack();
|
||||||
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
|
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
|
||||||
|
|
||||||
|
// TODO: Move these code somewhere else.
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case UserOptionResult.Added:
|
case UserOptionResult.Added:
|
||||||
@@ -97,16 +99,16 @@ internal sealed partial class LoginMihoyoUserPage : Microsoft.UI.Xaml.Controls.P
|
|||||||
vm.SelectedUser = vm.Users.Single();
|
vm.SelectedUser = vm.Users.Single();
|
||||||
}
|
}
|
||||||
|
|
||||||
infoBarService.Success($"用户 [{nickname}] 添加成功");
|
infoBarService.Success(string.Format(SH.ViewModelUserAdded, nickname));
|
||||||
break;
|
break;
|
||||||
case UserOptionResult.Incomplete:
|
case UserOptionResult.Incomplete:
|
||||||
infoBarService.Information($"此 Cookie 不完整,操作失败");
|
infoBarService.Information(SH.ViewModelUserIncomplete);
|
||||||
break;
|
break;
|
||||||
case UserOptionResult.Invalid:
|
case UserOptionResult.Invalid:
|
||||||
infoBarService.Information($"此 Cookie 无效,操作失败");
|
infoBarService.Information(SH.ViewModelUserInvalid);
|
||||||
break;
|
break;
|
||||||
case UserOptionResult.Updated:
|
case UserOptionResult.Updated:
|
||||||
infoBarService.Success($"用户 [{nickname}] 更新成功");
|
infoBarService.Success(string.Format(SH.ViewModelUserUpdated, nickname));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw Must.NeverHappen();
|
throw Must.NeverHappen();
|
||||||
|
|||||||
@@ -238,7 +238,7 @@
|
|||||||
Icon="{shcm:FontIcon Glyph=}"
|
Icon="{shcm:FontIcon Glyph=}"
|
||||||
Label="{shcm:ResourceString Name=ViewUserCookieOperationLoginMihoyoUserAction}"/>
|
Label="{shcm:ResourceString Name=ViewUserCookieOperationLoginMihoyoUserAction}"/>
|
||||||
<AppBarButton
|
<AppBarButton
|
||||||
Command="{Binding AddOsUserCommand}"
|
Command="{Binding AddOverseaUserCommand}"
|
||||||
Icon="{shcm:FontIcon Glyph=}"
|
Icon="{shcm:FontIcon Glyph=}"
|
||||||
Label="{shcm:ResourceString Name=ViewUserCookieOperationManualInputAction}"/>
|
Label="{shcm:ResourceString Name=ViewUserCookieOperationManualInputAction}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ internal sealed class UserViewModel : ObservableObject
|
|||||||
|
|
||||||
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
|
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
|
||||||
AddUserCommand = new AsyncRelayCommand(AddUserAsync);
|
AddUserCommand = new AsyncRelayCommand(AddUserAsync);
|
||||||
AddOsUserCommand = new AsyncRelayCommand(AddOsUserAsync);
|
AddOverseaUserCommand = new AsyncRelayCommand(AddOverseaUserAsync);
|
||||||
LoginMihoyoUserCommand = new RelayCommand(LoginMihoyoUser);
|
LoginMihoyoUserCommand = new RelayCommand(LoginMihoyoUser);
|
||||||
LoginHoyoverseUserCommand = new RelayCommand(LoginHoyoverseUser);
|
LoginHoyoverseUserCommand = new RelayCommand(LoginHoyoverseUser);
|
||||||
RemoveUserCommand = new AsyncRelayCommand<User>(RemoveUserAsync);
|
RemoveUserCommand = new AsyncRelayCommand<User>(RemoveUserAsync);
|
||||||
@@ -92,7 +92,7 @@ internal sealed class UserViewModel : ObservableObject
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加国际服用户命令
|
/// 添加国际服用户命令
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ICommand AddOsUserCommand { get; }
|
public ICommand AddOverseaUserCommand { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 登录米游社命令
|
/// 登录米游社命令
|
||||||
@@ -132,48 +132,17 @@ internal sealed class UserViewModel : ObservableObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddUserAsync()
|
private Task AddUserAsync()
|
||||||
{
|
{
|
||||||
// ContentDialog must be created by main thread.
|
return AddUserCoreAsync(false);
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
|
||||||
|
|
||||||
// Get cookie from user input
|
|
||||||
ValueResult<bool, string> result = await new UserDialog().GetInputCookieAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
// User confirms the input
|
|
||||||
if (result.IsOk)
|
|
||||||
{
|
|
||||||
Cookie cookie = Cookie.Parse(result.Value);
|
|
||||||
|
|
||||||
(UserOptionResult optionResult, string uid) = await userService.ProcessInputCookieAsync(cookie).ConfigureAwait(false);
|
|
||||||
|
|
||||||
switch (optionResult)
|
|
||||||
{
|
|
||||||
case UserOptionResult.Added:
|
|
||||||
if (Users!.Count == 1)
|
|
||||||
{
|
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
|
||||||
SelectedUser = Users.Single();
|
|
||||||
}
|
|
||||||
|
|
||||||
infoBarService.Success(string.Format(SH.ViewModelUserAdded, uid));
|
|
||||||
break;
|
|
||||||
case UserOptionResult.Incomplete:
|
|
||||||
infoBarService.Information(SH.ViewModelUserIncomplete);
|
|
||||||
break;
|
|
||||||
case UserOptionResult.Invalid:
|
|
||||||
infoBarService.Information(SH.ViewModelUserInvalid);
|
|
||||||
break;
|
|
||||||
case UserOptionResult.Updated:
|
|
||||||
infoBarService.Success(string.Format(SH.ViewModelUserUpdated, uid));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Must.NeverHappen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddOsUserAsync()
|
private Task AddOverseaUserAsync()
|
||||||
|
{
|
||||||
|
return AddUserCoreAsync(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddUserCoreAsync(bool isOversea)
|
||||||
{
|
{
|
||||||
// ContentDialog must be created by main thread.
|
// ContentDialog must be created by main thread.
|
||||||
await ThreadHelper.SwitchToMainThreadAsync();
|
await ThreadHelper.SwitchToMainThreadAsync();
|
||||||
@@ -186,7 +155,7 @@ internal sealed class UserViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
Cookie cookie = Cookie.Parse(result.Value);
|
Cookie cookie = Cookie.Parse(result.Value);
|
||||||
|
|
||||||
(UserOptionResult optionResult, string uid) = await userService.ProcessInputOsCookieAsync(cookie).ConfigureAwait(false);
|
(UserOptionResult optionResult, string uid) = await userService.ProcessInputCookieAsync(cookie, isOversea).ConfigureAwait(false);
|
||||||
|
|
||||||
switch (optionResult)
|
switch (optionResult)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ internal static class ApiOsEndpoints
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计算器结果
|
/// 计算器结果
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string CalculateOsCompute = $"{SgPublicApi}/event/calculateos/compute";
|
public const string CalculateCompute = $"{SgPublicApi}/event/calculateos/compute";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计算器同步角色详情 size 20
|
/// 计算器同步角色详情 size 20
|
||||||
@@ -208,7 +208,7 @@ internal static class ApiOsEndpoints
|
|||||||
/// <param name="avatarId">角色Id</param>
|
/// <param name="avatarId">角色Id</param>
|
||||||
/// <param name="uid">uid</param>
|
/// <param name="uid">uid</param>
|
||||||
/// <returns>角色详情</returns>
|
/// <returns>角色详情</returns>
|
||||||
public static string CalculateOsSyncAvatarDetail(AvatarId avatarId, PlayerUid uid)
|
public static string CalculateSyncAvatarDetail(AvatarId avatarId, PlayerUid uid)
|
||||||
{
|
{
|
||||||
return $"{SgPublicApi}/event/calculateos/sync/avatar/detail?avatar_id={avatarId.Value}&uid={uid.Value}®ion={uid.Region}";
|
return $"{SgPublicApi}/event/calculateos/sync/avatar/detail?avatar_id={avatarId.Value}&uid={uid.Value}®ion={uid.Region}";
|
||||||
}
|
}
|
||||||
@@ -216,7 +216,7 @@ internal static class ApiOsEndpoints
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计算器同步角色列表 size 20
|
/// 计算器同步角色列表 size 20
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string CalculateOsSyncAvatarList = $"{SgPublicApi}/event/calculateos/sync/avatar/list";
|
public const string CalculateSyncAvatarList = $"{SgPublicApi}/event/calculateos/sync/avatar/list";
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||||
using Snap.Hutao.Model.Entity;
|
using Snap.Hutao.Model.Entity;
|
||||||
using Snap.Hutao.Web.Hoyolab.Annotation;
|
using Snap.Hutao.Web.Hoyolab.Annotation;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hoyolab.Passport;
|
namespace Snap.Hutao.Web.Hoyolab.Passport;
|
||||||
|
|
||||||
@@ -13,6 +15,7 @@ namespace Snap.Hutao.Web.Hoyolab.Passport;
|
|||||||
/// 通行证客户端
|
/// 通行证客户端
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
|
[UseDynamicSecret]
|
||||||
[HttpClient(HttpClientConfiguration.Default)]
|
[HttpClient(HttpClientConfiguration.Default)]
|
||||||
internal sealed class PassportClient
|
internal sealed class PassportClient
|
||||||
{
|
{
|
||||||
@@ -34,7 +37,7 @@ internal sealed class PassportClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步验证Ltoken
|
/// 异步验证 LToken
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">用户</param>
|
/// <param name="user">用户</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
@@ -50,6 +53,28 @@ internal sealed class PassportClient
|
|||||||
return Response.Response.DefaultIfNull(response);
|
return Response.Response.DefaultIfNull(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// V1 SToken 登录
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stokenV1">v1 SToken</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>登录数据</returns>
|
||||||
|
[ApiInformation(Salt = SaltType.PROD)]
|
||||||
|
public async Task<Response<LoginResult>> LoginBySTokenAsync(Cookie stokenV1, CancellationToken token)
|
||||||
|
{
|
||||||
|
HttpResponseMessage message = await httpClient
|
||||||
|
.SetHeader("Cookie", stokenV1.ToString())
|
||||||
|
.UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.PROD, true)
|
||||||
|
.PostAsync(ApiEndpoints.AccountGetSTokenByOldToken, null, token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
Response<LoginResult>? resp = await message.Content
|
||||||
|
.ReadFromJsonAsync<Response<LoginResult>>(options, token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return Response.Response.DefaultIfNull(resp);
|
||||||
|
}
|
||||||
|
|
||||||
private class Timestamp
|
private class Timestamp
|
||||||
{
|
{
|
||||||
[JsonPropertyName("t")]
|
[JsonPropertyName("t")]
|
||||||
|
|||||||
@@ -39,28 +39,6 @@ internal sealed class PassportClient2 : IPassportClient
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsOversea => false;
|
public bool IsOversea => false;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// V1 SToken 登录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stokenV1">v1 SToken</param>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>登录数据</returns>
|
|
||||||
[ApiInformation(Salt = SaltType.PROD)]
|
|
||||||
public async Task<Response<LoginResult>> LoginBySTokenAsync(Cookie stokenV1, CancellationToken token)
|
|
||||||
{
|
|
||||||
HttpResponseMessage message = await httpClient
|
|
||||||
.SetHeader("Cookie", stokenV1.ToString())
|
|
||||||
.UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.PROD, true)
|
|
||||||
.PostAsync(ApiEndpoints.AccountGetSTokenByOldToken, null, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
Response<LoginResult>? resp = await message.Content
|
|
||||||
.ReadFromJsonAsync<Response<LoginResult>>(options, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return Response.Response.DefaultIfNull(resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取 CookieToken
|
/// 异步获取 CookieToken
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ internal sealed class PassportClientOversea : IPassportClient
|
|||||||
{
|
{
|
||||||
private readonly HttpClient httpClient;
|
private readonly HttpClient httpClient;
|
||||||
private readonly JsonSerializerOptions options;
|
private readonly JsonSerializerOptions options;
|
||||||
private readonly ILogger<PassportClient> logger;
|
private readonly ILogger<PassportClientOversea> logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的国际服通行证客户端
|
/// 构造一个新的国际服通行证客户端
|
||||||
@@ -28,7 +28,7 @@ internal sealed class PassportClientOversea : IPassportClient
|
|||||||
/// <param name="httpClient">http客户端</param>
|
/// <param name="httpClient">http客户端</param>
|
||||||
/// <param name="options">Json序列化选项</param>
|
/// <param name="options">Json序列化选项</param>
|
||||||
/// <param name="logger">日志器</param>
|
/// <param name="logger">日志器</param>
|
||||||
public PassportClientOversea(HttpClient httpClient, JsonSerializerOptions options, ILogger<PassportClient> logger)
|
public PassportClientOversea(HttpClient httpClient, JsonSerializerOptions options, ILogger<PassportClientOversea> logger)
|
||||||
{
|
{
|
||||||
this.httpClient = httpClient;
|
this.httpClient = httpClient;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ internal sealed class ResourceClient
|
|||||||
/// <returns>游戏资源</returns>
|
/// <returns>游戏资源</returns>
|
||||||
public async Task<Response<GameResource>> GetResourceAsync(LaunchScheme scheme, CancellationToken token = default)
|
public async Task<Response<GameResource>> GetResourceAsync(LaunchScheme scheme, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
string url = scheme.LauncherId == "10"
|
string url = scheme.IsOversea
|
||||||
? ApiOsEndpoints.SdkOsStaticLauncherResource(scheme)
|
? ApiOsEndpoints.SdkOsStaticLauncherResource(scheme)
|
||||||
: ApiEndpoints.SdkStaticLauncherResource(scheme);
|
: ApiEndpoints.SdkStaticLauncherResource(scheme);
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ internal sealed class BindingClient2
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步生成祈愿验证密钥
|
/// 异步生成祈愿验证密钥
|
||||||
/// 需要stoken
|
/// 需要 SToken
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">用户</param>
|
/// <param name="user">用户</param>
|
||||||
/// <param name="data">提交数据</param>
|
/// <param name="data">提交数据</param>
|
||||||
|
|||||||
@@ -43,24 +43,19 @@ internal sealed class CalculateClient
|
|||||||
[ApiInformation(Cookie = CookieType.Cookie)]
|
[ApiInformation(Cookie = CookieType.Cookie)]
|
||||||
public async Task<Response<Consumption>> ComputeAsync(Model.Entity.User user, AvatarPromotionDelta delta, CancellationToken token = default)
|
public async Task<Response<Consumption>> ComputeAsync(Model.Entity.User user, AvatarPromotionDelta delta, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
Response<Consumption>? resp;
|
string referer = user.IsOversea
|
||||||
|
? ApiOsEndpoints.ActHoyolabReferer
|
||||||
|
: ApiEndpoints.WebStaticMihoyoReferer;
|
||||||
|
|
||||||
if (user.IsOversea)
|
string url = user.IsOversea
|
||||||
{
|
? ApiOsEndpoints.CalculateCompute
|
||||||
resp = await httpClient
|
: ApiEndpoints.CalculateCompute;
|
||||||
|
|
||||||
|
Response<Consumption>? resp = await httpClient
|
||||||
.SetUser(user, CookieType.Cookie)
|
.SetUser(user, CookieType.Cookie)
|
||||||
.SetReferer(ApiOsEndpoints.ActHoyolabReferer)
|
.SetReferer(referer)
|
||||||
.TryCatchPostAsJsonAsync<AvatarPromotionDelta, Response<Consumption>>(ApiOsEndpoints.CalculateOsCompute, delta, options, logger, token)
|
.TryCatchPostAsJsonAsync<AvatarPromotionDelta, Response<Consumption>>(url, delta, options, logger, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
resp = await httpClient
|
|
||||||
.SetUser(user, CookieType.Cookie)
|
|
||||||
.SetReferer(ApiEndpoints.WebStaticMihoyoReferer)
|
|
||||||
.TryCatchPostAsJsonAsync<AvatarPromotionDelta, Response<Consumption>>(ApiEndpoints.CalculateCompute, delta, options, logger, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.Response.DefaultIfNull(resp);
|
return Response.Response.DefaultIfNull(resp);
|
||||||
}
|
}
|
||||||
@@ -80,28 +75,22 @@ internal sealed class CalculateClient
|
|||||||
Response<ListWrapper<Avatar>>? resp;
|
Response<ListWrapper<Avatar>>? resp;
|
||||||
|
|
||||||
// 根据 uid 所属服务器选择 referer 与 api
|
// 根据 uid 所属服务器选择 referer 与 api
|
||||||
string referer;
|
string referer = userAndUid.User.IsOversea
|
||||||
string endpoint;
|
? ApiOsEndpoints.ActHoyolabReferer
|
||||||
|
: ApiEndpoints.WebStaticMihoyoReferer;
|
||||||
|
string url = userAndUid.User.IsOversea
|
||||||
|
? ApiOsEndpoints.CalculateSyncAvatarList
|
||||||
|
: ApiEndpoints.CalculateSyncAvatarList;
|
||||||
|
|
||||||
if (userAndUid.User.IsOversea)
|
httpClient
|
||||||
{
|
.SetReferer(referer)
|
||||||
referer = ApiOsEndpoints.ActHoyolabReferer;
|
.SetUser(userAndUid.User, CookieType.CookieToken);
|
||||||
endpoint = ApiOsEndpoints.CalculateOsSyncAvatarList;
|
|
||||||
httpClient.SetUser(userAndUid.User, CookieType.CookieToken);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
referer = ApiEndpoints.WebStaticMihoyoReferer;
|
|
||||||
endpoint = ApiEndpoints.CalculateSyncAvatarList;
|
|
||||||
httpClient.SetUser(userAndUid.User, CookieType.CookieToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
filter.Page = currentPage++;
|
filter.Page = currentPage++;
|
||||||
resp = await httpClient
|
resp = await httpClient
|
||||||
.SetReferer(referer)
|
.TryCatchPostAsJsonAsync<SyncAvatarFilter, Response<ListWrapper<Avatar>>>(url, filter, options, logger, token)
|
||||||
.TryCatchPostAsJsonAsync<SyncAvatarFilter, Response<ListWrapper<Avatar>>>(endpoint, filter, options, logger, token)
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (resp != null && resp.IsOk())
|
if (resp != null && resp.IsOk())
|
||||||
@@ -130,21 +119,14 @@ internal sealed class CalculateClient
|
|||||||
/// <returns>角色详情</returns>
|
/// <returns>角色详情</returns>
|
||||||
public async Task<Response<AvatarDetail>> GetAvatarDetailAsync(UserAndUid userAndUid, Avatar avatar, CancellationToken token = default)
|
public async Task<Response<AvatarDetail>> GetAvatarDetailAsync(UserAndUid userAndUid, Avatar avatar, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
Response<AvatarDetail>? resp;
|
string url = userAndUid.User.IsOversea
|
||||||
if (!userAndUid.User.IsOversea)
|
? ApiOsEndpoints.CalculateSyncAvatarDetail(avatar.Id, userAndUid.Uid.Value)
|
||||||
{
|
: ApiEndpoints.CalculateSyncAvatarDetail(avatar.Id, userAndUid.Uid.Value);
|
||||||
resp = await httpClient
|
|
||||||
|
Response<AvatarDetail>? resp = await httpClient
|
||||||
.SetUser(userAndUid.User, CookieType.CookieToken)
|
.SetUser(userAndUid.User, CookieType.CookieToken)
|
||||||
.TryCatchGetFromJsonAsync<Response<AvatarDetail>>(ApiEndpoints.CalculateSyncAvatarDetail(avatar.Id, userAndUid.Uid.Value), options, logger, token)
|
.TryCatchGetFromJsonAsync<Response<AvatarDetail>>(url, options, logger, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
resp = await httpClient
|
|
||||||
.SetUser(userAndUid.User, CookieType.CookieToken)
|
|
||||||
.TryCatchGetFromJsonAsync<Response<AvatarDetail>>(ApiOsEndpoints.CalculateOsSyncAvatarDetail(avatar.Id, userAndUid.Uid.Value), options, logger, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.Response.DefaultIfNull(resp);
|
return Response.Response.DefaultIfNull(resp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,8 @@ namespace Snap.Hutao.Web.Hutao;
|
|||||||
[HttpClient(HttpClientConfiguration.Default)]
|
[HttpClient(HttpClientConfiguration.Default)]
|
||||||
internal sealed class HomaSpiralAbyssClient
|
internal sealed class HomaSpiralAbyssClient
|
||||||
{
|
{
|
||||||
|
private readonly IServiceProvider serviceProvider;
|
||||||
private readonly HttpClient httpClient;
|
private readonly HttpClient httpClient;
|
||||||
private readonly GameRecordClient gameRecordClient;
|
|
||||||
private readonly GameRecordClientOversea gameRecordClientOs;
|
|
||||||
private readonly JsonSerializerOptions options;
|
private readonly JsonSerializerOptions options;
|
||||||
private readonly ILogger<HomaSpiralAbyssClient> logger;
|
private readonly ILogger<HomaSpiralAbyssClient> logger;
|
||||||
|
|
||||||
@@ -31,16 +30,14 @@ internal sealed class HomaSpiralAbyssClient
|
|||||||
/// 构造一个新的胡桃API客户端
|
/// 构造一个新的胡桃API客户端
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="httpClient">http客户端</param>
|
/// <param name="httpClient">http客户端</param>
|
||||||
/// <param name="gameRecordClient">游戏记录客户端</param>
|
/// <param name="serviceProvider">服务提供器</param>
|
||||||
/// <param name="options">json序列化选项</param>
|
public HomaSpiralAbyssClient(HttpClient httpClient, IServiceProvider serviceProvider)
|
||||||
/// <param name="logger">日志器</param>
|
|
||||||
public HomaSpiralAbyssClient(HttpClient httpClient, GameRecordClient gameRecordClient, GameRecordClientOversea gameRecordClientOs, JsonSerializerOptions options, ILogger<HomaSpiralAbyssClient> logger)
|
|
||||||
{
|
{
|
||||||
|
options = serviceProvider.GetRequiredService<JsonSerializerOptions>();
|
||||||
|
logger = serviceProvider.GetRequiredService<ILogger<HomaSpiralAbyssClient>>();
|
||||||
|
|
||||||
|
this.serviceProvider = serviceProvider;
|
||||||
this.httpClient = httpClient;
|
this.httpClient = httpClient;
|
||||||
this.gameRecordClient = gameRecordClient;
|
|
||||||
this.gameRecordClientOs = gameRecordClientOs;
|
|
||||||
this.options = options;
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -188,55 +185,27 @@ internal sealed class HomaSpiralAbyssClient
|
|||||||
/// <returns>玩家记录</returns>
|
/// <returns>玩家记录</returns>
|
||||||
public async Task<SimpleRecord?> GetPlayerRecordAsync(UserAndUid userAndUid, CancellationToken token = default)
|
public async Task<SimpleRecord?> GetPlayerRecordAsync(UserAndUid userAndUid, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (userAndUid.User.IsOversea)
|
IGameRecordClient gameRecordClient = serviceProvider.PickRequiredService<IGameRecordClient>(userAndUid.User.IsOversea);
|
||||||
{
|
|
||||||
// for oversea server
|
Response<PlayerInfo> playerInfoResponse = await gameRecordClient
|
||||||
Response<PlayerInfo> playerInfoResponse = await gameRecordClientOs
|
|
||||||
.GetPlayerInfoAsync(userAndUid, token)
|
.GetPlayerInfoAsync(userAndUid, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (playerInfoResponse.IsOk())
|
if (playerInfoResponse.IsOk())
|
||||||
{
|
|
||||||
Response<CharacterWrapper> charactersResponse = await gameRecordClientOs
|
|
||||||
.GetCharactersAsync(userAndUid, playerInfoResponse.Data, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (charactersResponse.IsOk())
|
|
||||||
{
|
|
||||||
Response<SpiralAbyss> spiralAbyssResponse = await gameRecordClientOs
|
|
||||||
.GetSpiralAbyssAsync(userAndUid, SpiralAbyssSchedule.Current, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (spiralAbyssResponse.IsOk())
|
|
||||||
{
|
|
||||||
return new(userAndUid.Uid.Value, charactersResponse.Data.Avatars, spiralAbyssResponse.Data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// for cn server
|
Response<CharacterWrapper> charactersResponse = await gameRecordClient
|
||||||
Response<PlayerInfo> playerInfoResponse = await gameRecordClient
|
.GetCharactersAsync(userAndUid, playerInfoResponse.Data, token)
|
||||||
.GetPlayerInfoAsync(userAndUid, token)
|
.ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (playerInfoResponse.IsOk())
|
if (charactersResponse.IsOk())
|
||||||
{
|
{
|
||||||
Response<CharacterWrapper> charactersResponse = await gameRecordClient
|
Response<SpiralAbyss> spiralAbyssResponse = await gameRecordClient
|
||||||
.GetCharactersAsync(userAndUid, playerInfoResponse.Data, token)
|
.GetSpiralAbyssAsync(userAndUid, SpiralAbyssSchedule.Current, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (charactersResponse.IsOk())
|
if (spiralAbyssResponse.IsOk())
|
||||||
{
|
{
|
||||||
Response<SpiralAbyss> spiralAbyssResponse = await gameRecordClient
|
return new(userAndUid.Uid.Value, charactersResponse.Data.Avatars, spiralAbyssResponse.Data);
|
||||||
.GetSpiralAbyssAsync(userAndUid, SpiralAbyssSchedule.Current, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (spiralAbyssResponse.IsOk())
|
|
||||||
{
|
|
||||||
return new(userAndUid.Uid.Value, charactersResponse.Data.Avatars, spiralAbyssResponse.Data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user