mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Device needs rework
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<!-- https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font -->
|
||||
<x:String x:Key="FontIconContentAdd"></x:String>
|
||||
<x:String x:Key="FontIconContentSetting"></x:String>
|
||||
<x:String x:Key="FontIconContentRefresh"></x:String>
|
||||
@@ -12,10 +13,10 @@
|
||||
<x:String x:Key="FontIconContentBulletedList"></x:String>
|
||||
<x:String x:Key="FontIconContentCheckList"></x:String>
|
||||
<x:String x:Key="FontIconContentWebsite"></x:String>
|
||||
<x:String x:Key="FontIconContentQRCode"></x:String>
|
||||
<x:String x:Key="FontIconContentHomeGroup"></x:String>
|
||||
<x:String x:Key="FontIconContentAsteriskBadge12"></x:String>
|
||||
<x:String x:Key="FontIconContentZipFolder"></x:String>
|
||||
<x:String x:Key="FontIconContentGridView"></x:String>
|
||||
<x:String x:Key="FontIconContentGiftboxOpen"></x:String>
|
||||
<x:String x:Key="FontIconContentQrCode"></x:String>
|
||||
</ResourceDictionary>
|
||||
@@ -7,7 +7,7 @@ namespace Snap.Hutao.Extension;
|
||||
|
||||
internal static partial class EnumerableExtension
|
||||
{
|
||||
public static bool TryGetValue(this NameValueCollection collection, string name, [NotNullWhen(true)] out string? value)
|
||||
public static bool TryGetSingleValue(this NameValueCollection collection, string name, [NotNullWhen(true)] out string? value)
|
||||
{
|
||||
if (collection.AllKeys.Contains(name))
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace Snap.Hutao.Factory.QrCode;
|
||||
|
||||
internal interface IQrCodeFactory
|
||||
internal interface IQRCodeFactory
|
||||
{
|
||||
byte[] CreateQrCodeByteArray(string source);
|
||||
}
|
||||
byte[] Create(string source);
|
||||
}
|
||||
@@ -6,10 +6,10 @@ using QRCoder;
|
||||
namespace Snap.Hutao.Factory.QrCode;
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Singleton, typeof(IQrCodeFactory))]
|
||||
internal class QrCodeFactory : IQrCodeFactory
|
||||
[Injection(InjectAs.Singleton, typeof(IQRCodeFactory))]
|
||||
internal class QRCodeFactory : IQRCodeFactory
|
||||
{
|
||||
public byte[] CreateQrCodeByteArray(string source)
|
||||
public byte[] Create(string source)
|
||||
{
|
||||
using (QRCodeGenerator generator = new())
|
||||
{
|
||||
@@ -1265,7 +1265,7 @@
|
||||
<data name="ViewDialogLaunchGamePackageConvertTitle" xml:space="preserve">
|
||||
<value>正在转换客户端</value>
|
||||
</data>
|
||||
<data name="ViewDialogQrCodeTitle" xml:space="preserve">
|
||||
<data name="ViewDialogQRCodeTitle" xml:space="preserve">
|
||||
<value>使用米游社扫描二维码</value>
|
||||
</data>
|
||||
<data name="ViewDialogSettingDeleteUserDataContent" xml:space="preserve">
|
||||
@@ -2621,7 +2621,7 @@
|
||||
<data name="ViewUserCookieOperationLoginMihoyoUserAction" xml:space="preserve">
|
||||
<value>网页登录</value>
|
||||
</data>
|
||||
<data name="ViewUserCookieOperationLoginQrCodeAction" xml:space="preserve">
|
||||
<data name="ViewUserCookieOperationLoginQRCodeAction" xml:space="preserve">
|
||||
<value>扫码登录</value>
|
||||
</data>
|
||||
<data name="ViewUserCookieOperationManualInputAction" xml:space="preserve">
|
||||
|
||||
@@ -30,7 +30,7 @@ internal sealed partial class GachaLogQueryManualInputProvider : IGachaLogQueryP
|
||||
{
|
||||
NameValueCollection query = HttpUtility.ParseQueryString(queryString);
|
||||
|
||||
if (query.TryGetValue("auth_appid", out string? appId) && appId is "webview_gacha")
|
||||
if (query.TryGetSingleValue("auth_appid", out string? appId) && appId is "webview_gacha")
|
||||
{
|
||||
string? queryLanguageCode = query["lang"];
|
||||
if (metadataOptions.LanguageCodeFitsCurrentLocale(queryLanguageCode))
|
||||
|
||||
@@ -173,8 +173,8 @@
|
||||
<None Remove="View\Dialog\HutaoPassportUnregisterDialog.xaml" />
|
||||
<None Remove="View\Dialog\LaunchGameAccountNameDialog.xaml" />
|
||||
<None Remove="View\Dialog\LaunchGamePackageConvertDialog.xaml" />
|
||||
<None Remove="View\Dialog\QrCodeDialog.xaml" />
|
||||
<None Remove="View\Dialog\UserDialog.xaml" />
|
||||
<None Remove="View\Dialog\UserQRCodeDialog.xaml" />
|
||||
<None Remove="View\Guide\GuideView.xaml" />
|
||||
<None Remove="View\InfoBarView.xaml" />
|
||||
<None Remove="View\MainView.xaml" />
|
||||
@@ -332,7 +332,7 @@
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\QrCodeDialog.xaml">
|
||||
<Page Update="View\Dialog\UserQRCodeDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using Snap.Hutao.Factory.QrCode;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
|
||||
using Snap.Hutao.Web.Hoyolab.Passport;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
/// <summary>
|
||||
/// 扫描二维码对话框
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed partial class QrCodeDialog : ContentDialog
|
||||
{
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly PassportClient2 passportClient2;
|
||||
private readonly IQrCodeFactory qrCodeFactory;
|
||||
|
||||
private UidGameToken? account;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的扫描二维码对话框
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
public QrCodeDialog(IServiceProvider serviceProvider)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
passportClient2 = serviceProvider.GetRequiredService<PassportClient2>();
|
||||
qrCodeFactory = serviceProvider.GetRequiredService<IQrCodeFactory>();
|
||||
|
||||
FetchQrCodeAsync().SafeForget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取登录的用户
|
||||
/// </summary>
|
||||
/// <returns>QrCodeAccount</returns>
|
||||
[SuppressMessage("", "SH007")]
|
||||
public async ValueTask<ValueResult<bool, UidGameToken>> GetAccountAsync()
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
return new(account is not null, account!);
|
||||
}
|
||||
|
||||
private async ValueTask FetchQrCodeAsync()
|
||||
{
|
||||
Response<GameLoginRequestResult> fetch = await passportClient2.PostQrCodeFetchAsync().ConfigureAwait(false);
|
||||
if (fetch.IsOk())
|
||||
{
|
||||
string url = Regex.Unescape(fetch.Data.Url);
|
||||
string ticket = url.ToUri().Query.Split('&').Last().Split('=').Last();
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
BitmapImage bitmap = new();
|
||||
await bitmap.SetSourceAsync(new MemoryStream(qrCodeFactory.CreateQrCodeByteArray(url)).AsRandomAccessStream());
|
||||
|
||||
ImageView.Source = bitmap;
|
||||
if (bitmap is BitmapSource { PixelHeight: > 0, PixelWidth: > 0 })
|
||||
{
|
||||
VisualStateManager.GoToState(this, "Loaded", true);
|
||||
}
|
||||
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
await CheckStatusAsync(ticket).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask CheckStatusAsync(string ticket)
|
||||
{
|
||||
using (PeriodicTimer timer = new(TimeSpan.FromSeconds(3)))
|
||||
{
|
||||
while (await timer.WaitForNextTickAsync().ConfigureAwait(false))
|
||||
{
|
||||
Response<GameLoginResult> query = await passportClient2.PostQrCodeQueryAsync(ticket).ConfigureAwait(false);
|
||||
if (query.IsOk(false))
|
||||
{
|
||||
switch (query.Data.Stat)
|
||||
{
|
||||
case GameLoginResultStatus.Init:
|
||||
case GameLoginResultStatus.Scanned:
|
||||
break; // @switch
|
||||
case GameLoginResultStatus.Confirmed:
|
||||
if (query.Data.Payload.Proto == GameLoginResultPayload.ACCOUNT)
|
||||
{
|
||||
account = JsonSerializer.Deserialize<UidGameToken>(query.Data.Payload.Raw);
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Hide();
|
||||
return; // Stop timer
|
||||
}
|
||||
|
||||
break; // @switch
|
||||
}
|
||||
}
|
||||
else if (query.ReturnCode == (int)KnownReturnCode.QrCodeExpired)
|
||||
{
|
||||
FetchQrCodeAsync().SafeForget();
|
||||
break; // @while
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.View.Dialog.QrCodeDialog"
|
||||
x:Class="Snap.Hutao.View.Dialog.UserQRCodeDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
Title="{shcm:ResourceString Name=ViewDialogQrCodeTitle}"
|
||||
Title="{shcm:ResourceString Name=ViewDialogQRCodeTitle}"
|
||||
CloseButtonCommand="{x:Bind CancelCommand}"
|
||||
CloseButtonText="{shcm:ResourceString Name=ContentDialogCancelCloseButtonText}"
|
||||
DefaultButton="Close"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
@@ -13,8 +14,8 @@
|
||||
|
||||
<StackPanel>
|
||||
<Image
|
||||
x:Name="ImageView"
|
||||
Width="200"
|
||||
Height="200" />
|
||||
Width="320"
|
||||
Height="320"
|
||||
Source="{x:Bind QRCodeSource}"/>
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
156
src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml.cs
Normal file
156
src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using Snap.Hutao.Factory.QrCode;
|
||||
using Snap.Hutao.Web.Hoyolab.Passport;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
[DependencyProperty("QRCodeSource", typeof(ImageSource))]
|
||||
internal sealed partial class UserQRCodeDialog : ContentDialog, IDisposable
|
||||
{
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly PassportClient2 passportClient2;
|
||||
private readonly IQRCodeFactory qrCodeFactory;
|
||||
|
||||
private readonly CancellationTokenSource userManualCancellationTokenSource = new();
|
||||
private bool disposed;
|
||||
|
||||
public UserQRCodeDialog(IServiceProvider serviceProvider)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
passportClient2 = serviceProvider.GetRequiredService<PassportClient2>();
|
||||
qrCodeFactory = serviceProvider.GetRequiredService<IQRCodeFactory>();
|
||||
}
|
||||
|
||||
~UserQRCodeDialog()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
userManualCancellationTokenSource.Dispose();
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public async ValueTask<ValueResult<bool, UidGameToken>> GetUidGameTokenAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return await GetUidGameTokenCoreAsync().ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
userManualCancellationTokenSource.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Command("CancelCommand")]
|
||||
private void Cancel()
|
||||
{
|
||||
userManualCancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
private async ValueTask<ValueResult<bool, UidGameToken>> GetUidGameTokenCoreAsync()
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
await ShowAsync();
|
||||
|
||||
while (!userManualCancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
CancellationToken token = userManualCancellationTokenSource.Token;
|
||||
string ticket = await FetchQRCodeAndSetImageAsync(token).ConfigureAwait(false);
|
||||
UidGameToken? uidGameToken = await WaitQueryQRCodeConfirmAsync(ticket, token).ConfigureAwait(false);
|
||||
|
||||
if (uidGameToken is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Hide();
|
||||
return new(true, uidGameToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new(false, default!);
|
||||
}
|
||||
|
||||
private async ValueTask<string> FetchQRCodeAndSetImageAsync(CancellationToken token)
|
||||
{
|
||||
Response<UrlWrapper> fetchResponse = await passportClient2.QRCodeFetchAsync(token).ConfigureAwait(false);
|
||||
if (!fetchResponse.IsOk())
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string url = fetchResponse.Data.Url;
|
||||
string ticket = GetTicketFromUrl(fetchResponse.Data.Url);
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
BitmapImage bitmap = new();
|
||||
await bitmap.SetSourceAsync(new MemoryStream(qrCodeFactory.Create(url)).AsRandomAccessStream());
|
||||
QRCodeSource = bitmap;
|
||||
|
||||
return ticket;
|
||||
|
||||
static string GetTicketFromUrl(in ReadOnlySpan<char> urlSpan)
|
||||
{
|
||||
ReadOnlySpan<char> querySpan = urlSpan[urlSpan.IndexOf('?')..];
|
||||
NameValueCollection queryCollection = HttpUtility.ParseQueryString(querySpan.ToString());
|
||||
if (queryCollection.TryGetSingleValue("ticket", out string? ticket))
|
||||
{
|
||||
return ticket;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<UidGameToken?> WaitQueryQRCodeConfirmAsync(string ticket, CancellationToken token)
|
||||
{
|
||||
using (PeriodicTimer timer = new(new(0, 0, 3)))
|
||||
{
|
||||
while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false))
|
||||
{
|
||||
Response<GameLoginResult> query = await passportClient2.QRCodeQueryAsync(ticket, token).ConfigureAwait(false);
|
||||
|
||||
if (query is { ReturnCode: 0, Data: { Stat: "Confirmed", Payload.Proto: "Account" } })
|
||||
{
|
||||
UidGameToken? uidGameToken = JsonSerializer.Deserialize<UidGameToken>(query.Data.Payload.Raw);
|
||||
ArgumentNullException.ThrowIfNull(uidGameToken);
|
||||
return uidGameToken;
|
||||
}
|
||||
else if (query.ReturnCode == (int)KnownReturnCode.QrCodeExpired)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@
|
||||
Margin="2,-4"
|
||||
Command="{Binding LoginByQrCodeCommand}"
|
||||
Icon="{shcm:FontIcon Glyph={StaticResource FontIconContentQrCode}}"
|
||||
Label="{shcm:ResourceString Name=ViewUserCookieOperationLoginQrCodeAction}"/>
|
||||
Label="{shcm:ResourceString Name=ViewUserCookieOperationLoginQRCodeAction}"/>
|
||||
<AppBarButton
|
||||
Width="{StaticResource LargeAppBarButtonWidth}"
|
||||
MaxWidth="{StaticResource LargeAppBarButtonWidth}"
|
||||
|
||||
@@ -183,8 +183,8 @@ internal sealed partial class UserViewModel : ObservableObject
|
||||
// ContentDialog must be created by main thread.
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
QrCodeDialog dialog = await contentDialogFactory.CreateInstanceAsync<QrCodeDialog>().ConfigureAwait(false);
|
||||
ValueResult<bool, UidGameToken> result = await dialog.GetAccountAsync().ConfigureAwait(false);
|
||||
UserQRCodeDialog dialog = await contentDialogFactory.CreateInstanceAsync<UserQRCodeDialog>().ConfigureAwait(false);
|
||||
ValueResult<bool, UidGameToken> result = await dialog.GetUidGameTokenAsync().ConfigureAwait(false);
|
||||
|
||||
if (result.TryGetValue(out UidGameToken account))
|
||||
{
|
||||
|
||||
@@ -283,6 +283,14 @@ internal static class ApiEndpoints
|
||||
public const string AnnContent = $"{Hk4eApiAnnouncementApi}/getAnnContent?{AnnouncementQuery}";
|
||||
#endregion
|
||||
|
||||
#region Hk4eSdk
|
||||
|
||||
public const string QrCodeFetch = $"{Hk4eSdk}/hk4e_cn/combo/panda/qrcode/fetch";
|
||||
|
||||
public const string QrCodeQuery = $"{Hk4eSdk}/hk4e_cn/combo/panda/qrcode/query";
|
||||
|
||||
#endregion
|
||||
|
||||
#region PassportApi | PassportApiV4
|
||||
|
||||
/// <summary>
|
||||
@@ -363,14 +371,6 @@ internal static class ApiEndpoints
|
||||
// https://sdk-static.mihoyo.com/hk4e_cn/mdk/launcher/api/content?key=eYd89JmJ&language=zh-cn&launcher_id=18
|
||||
#endregion
|
||||
|
||||
#region Hk4eSdk
|
||||
|
||||
public const string QrCodeFetch = $"{Hk4eSdk}/hk4e_cn/combo/panda/qrcode/fetch";
|
||||
|
||||
public const string QrCodeQuery = $"{Hk4eSdk}/hk4e_cn/combo/panda/qrcode/query";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hosts | Queries
|
||||
private const string ApiTakumi = "https://api-takumi.mihoyo.com";
|
||||
private const string ApiTakumiAuthApi = $"{ApiTakumi}/auth/api";
|
||||
@@ -418,4 +418,4 @@ internal static class ApiEndpoints
|
||||
|
||||
private const string AnnouncementQuery = "game=hk4e&game_biz=hk4e_cn&lang=zh-cn&bundle_id=hk4e_cn&platform=pc®ion=cn_gf01&level=55&uid=100000000";
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Json.Annotation;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Passport;
|
||||
@@ -13,8 +12,7 @@ namespace Snap.Hutao.Web.Hoyolab.Passport;
|
||||
internal sealed class GameLoginResult
|
||||
{
|
||||
[JsonPropertyName("stat")]
|
||||
[JsonEnum(JsonSerializeType.String)]
|
||||
public GameLoginResultStatus Stat { get; set; } = default!;
|
||||
public string Stat { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("payload")]
|
||||
public GameLoginResultPayload Payload { get; set; } = default!;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
|
||||
|
||||
/// <summary>
|
||||
/// Proto 类型常量
|
||||
/// </summary>
|
||||
internal sealed partial class GameLoginResultPayload
|
||||
{
|
||||
public const string ACCOUNT = "Account";
|
||||
public const string RAW = "Raw";
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Passport;
|
||||
|
||||
/// <summary>
|
||||
/// 扫码状态
|
||||
/// </summary>
|
||||
internal enum GameLoginResultStatus
|
||||
{
|
||||
Init,
|
||||
Scanned,
|
||||
Confirmed,
|
||||
}
|
||||
@@ -73,7 +73,7 @@ internal sealed partial class PassportClient2
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>二维码原始链接</returns>
|
||||
public async ValueTask<Response<GameLoginRequestResult>> PostQrCodeFetchAsync(CancellationToken token = default)
|
||||
public async ValueTask<Response<UrlWrapper>> QRCodeFetchAsync(CancellationToken token = default)
|
||||
{
|
||||
GameLoginRequestOptions options = GameLoginRequestOptions.Create(4, HoyolabOptions.Device);
|
||||
|
||||
@@ -81,8 +81,8 @@ internal sealed partial class PassportClient2
|
||||
.SetRequestUri(ApiEndpoints.QrCodeFetch)
|
||||
.PostJson(options);
|
||||
|
||||
Response<GameLoginRequestResult>? resp = await builder
|
||||
.TryCatchSendAsync<Response<GameLoginRequestResult>>(httpClient, logger, token)
|
||||
Response<UrlWrapper>? resp = await builder
|
||||
.TryCatchSendAsync<Response<UrlWrapper>>(httpClient, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
@@ -94,7 +94,7 @@ internal sealed partial class PassportClient2
|
||||
/// <param name="ticket">扫码链接中的ticket</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>扫码结果</returns>
|
||||
public async ValueTask<Response<GameLoginResult>> PostQrCodeQueryAsync(string ticket, CancellationToken token = default)
|
||||
public async ValueTask<Response<GameLoginResult>> QRCodeQueryAsync(string ticket, CancellationToken token = default)
|
||||
{
|
||||
GameLoginResultOptions options = GameLoginResultOptions.Create(4, HoyolabOptions.Device, ticket);
|
||||
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Passport;
|
||||
|
||||
/// <summary>
|
||||
/// 扫码登录请求结果
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class GameLoginRequestResult
|
||||
internal sealed class UrlWrapper
|
||||
{
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; } = default!;
|
||||
Reference in New Issue
Block a user