diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Theme/Glyph.xaml b/src/Snap.Hutao/Snap.Hutao/Control/Theme/Glyph.xaml
index d658fc29..4f8f0190 100644
--- a/src/Snap.Hutao/Snap.Hutao/Control/Theme/Glyph.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/Control/Theme/Glyph.xaml
@@ -1,4 +1,5 @@
+
@@ -12,10 +13,10 @@
+
-
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.NameValueCollection.cs b/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.NameValueCollection.cs
index 9d3840c0..2f4bafda 100644
--- a/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.NameValueCollection.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.NameValueCollection.cs
@@ -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))
{
diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/IQrCodeFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/QuickResponse/IQRCodeFactory.cs
similarity index 60%
rename from src/Snap.Hutao/Snap.Hutao/Factory/QrCode/IQrCodeFactory.cs
rename to src/Snap.Hutao/Snap.Hutao/Factory/QuickResponse/IQRCodeFactory.cs
index 0ab732fa..8ba3ea82 100644
--- a/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/IQrCodeFactory.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Factory/QuickResponse/IQRCodeFactory.cs
@@ -3,7 +3,7 @@
namespace Snap.Hutao.Factory.QrCode;
-internal interface IQrCodeFactory
+internal interface IQRCodeFactory
{
- byte[] CreateQrCodeByteArray(string source);
-}
+ byte[] Create(string source);
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/QrCodeFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/QuickResponse/QRCodeFactory.cs
similarity index 76%
rename from src/Snap.Hutao/Snap.Hutao/Factory/QrCode/QrCodeFactory.cs
rename to src/Snap.Hutao/Snap.Hutao/Factory/QuickResponse/QRCodeFactory.cs
index 4ee567fc..fb28e857 100644
--- a/src/Snap.Hutao/Snap.Hutao/Factory/QrCode/QrCodeFactory.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Factory/QuickResponse/QRCodeFactory.cs
@@ -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())
{
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
index 42907257..bcbcfdb2 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
@@ -1265,7 +1265,7 @@
正在转换客户端
-
+
使用米游社扫描二维码
@@ -2621,7 +2621,7 @@
网页登录
-
+
扫码登录
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryManualInputProvider.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryManualInputProvider.cs
index 9e7b98fc..45be4b6b 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryManualInputProvider.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryManualInputProvider.cs
@@ -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))
diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
index 7f248f3e..10c37a81 100644
--- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
+++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
@@ -173,8 +173,8 @@
-
+
@@ -332,7 +332,7 @@
-
+
MSBuild:Compile
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml.cs
deleted file mode 100644
index 235f766b..00000000
--- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml.cs
+++ /dev/null
@@ -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;
-
-///
-/// 扫描二维码对话框
-///
-[HighQuality]
-internal sealed partial class QrCodeDialog : ContentDialog
-{
- private readonly ITaskContext taskContext;
- private readonly PassportClient2 passportClient2;
- private readonly IQrCodeFactory qrCodeFactory;
-
- private UidGameToken? account;
-
- ///
- /// 构造一个新的扫描二维码对话框
- ///
- /// 服务提供器
- public QrCodeDialog(IServiceProvider serviceProvider)
- {
- InitializeComponent();
-
- taskContext = serviceProvider.GetRequiredService();
- passportClient2 = serviceProvider.GetRequiredService();
- qrCodeFactory = serviceProvider.GetRequiredService();
-
- FetchQrCodeAsync().SafeForget();
- }
-
- ///
- /// 获取登录的用户
- ///
- /// QrCodeAccount
- [SuppressMessage("", "SH007")]
- public async ValueTask> GetAccountAsync()
- {
- await taskContext.SwitchToMainThreadAsync();
- ContentDialogResult result = await ShowAsync();
- return new(account is not null, account!);
- }
-
- private async ValueTask FetchQrCodeAsync()
- {
- Response 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 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(query.Data.Payload.Raw);
- await taskContext.SwitchToMainThreadAsync();
- Hide();
- return; // Stop timer
- }
-
- break; // @switch
- }
- }
- else if (query.ReturnCode == (int)KnownReturnCode.QrCodeExpired)
- {
- FetchQrCodeAsync().SafeForget();
- break; // @while
- }
- }
- }
- }
-}
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml b/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml
similarity index 69%
rename from src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml
rename to src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml
index 177a814c..62e88581 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/QrCodeDialog.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml
@@ -1,11 +1,12 @@
+ Width="320"
+ Height="320"
+ Source="{x:Bind QRCodeSource}"/>
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml.cs
new file mode 100644
index 00000000..a9f55887
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserQRCodeDialog.xaml.cs
@@ -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();
+ passportClient2 = serviceProvider.GetRequiredService();
+ qrCodeFactory = serviceProvider.GetRequiredService();
+ }
+
+ ~UserQRCodeDialog()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ if (!disposed)
+ {
+ userManualCancellationTokenSource.Dispose();
+ disposed = true;
+ }
+
+ GC.SuppressFinalize(this);
+ }
+
+ public async ValueTask> GetUidGameTokenAsync()
+ {
+ try
+ {
+ return await GetUidGameTokenCoreAsync().ConfigureAwait(false);
+ }
+ finally
+ {
+ userManualCancellationTokenSource.Dispose();
+ }
+ }
+
+ [Command("CancelCommand")]
+ private void Cancel()
+ {
+ userManualCancellationTokenSource.Cancel();
+ }
+
+ private async ValueTask> 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 FetchQRCodeAndSetImageAsync(CancellationToken token)
+ {
+ Response 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 urlSpan)
+ {
+ ReadOnlySpan 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 WaitQueryQRCodeConfirmAsync(string ticket, CancellationToken token)
+ {
+ using (PeriodicTimer timer = new(new(0, 0, 3)))
+ {
+ while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false))
+ {
+ Response query = await passportClient2.QRCodeQueryAsync(ticket, token).ConfigureAwait(false);
+
+ if (query is { ReturnCode: 0, Data: { Stat: "Confirmed", Payload.Proto: "Account" } })
+ {
+ UidGameToken? uidGameToken = JsonSerializer.Deserialize(query.Data.Payload.Raw);
+ ArgumentNullException.ThrowIfNull(uidGameToken);
+ return uidGameToken;
+ }
+ else if (query.ReturnCode == (int)KnownReturnCode.QrCodeExpired)
+ {
+ break;
+ }
+ }
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml
index d58233b3..bff2ca0b 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml
@@ -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}"/>
().ConfigureAwait(false);
- ValueResult result = await dialog.GetAccountAsync().ConfigureAwait(false);
+ UserQRCodeDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false);
+ ValueResult result = await dialog.GetUidGameTokenAsync().ConfigureAwait(false);
if (result.TryGetValue(out UidGameToken account))
{
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs
index 95032e1f..2774436b 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs
@@ -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
///
@@ -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
-}
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs
index c3757f69..bd52a99c 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResult.cs
@@ -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!;
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.ProtoTypes.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.ProtoTypes.cs
deleted file mode 100644
index 179b7501..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultPayload.ProtoTypes.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Snap.Hutao.Web.Hoyolab.Hk4e.QrCode;
-
-///
-/// Proto 类型常量
-///
-internal sealed partial class GameLoginResultPayload
-{
- public const string ACCOUNT = "Account";
- public const string RAW = "Raw";
-}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultStatus.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultStatus.cs
deleted file mode 100644
index 9f95988f..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginResultStatus.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Snap.Hutao.Web.Hoyolab.Passport;
-
-///
-/// 扫码状态
-///
-internal enum GameLoginResultStatus
-{
- Init,
- Scanned,
- Confirmed,
-}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs
index be261a77..8516723b 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/PassportClient2.cs
@@ -73,7 +73,7 @@ internal sealed partial class PassportClient2
///
/// 取消令牌
/// 二维码原始链接
- public async ValueTask> PostQrCodeFetchAsync(CancellationToken token = default)
+ public async ValueTask> 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? resp = await builder
- .TryCatchSendAsync>(httpClient, logger, token)
+ Response? resp = await builder
+ .TryCatchSendAsync>(httpClient, logger, token)
.ConfigureAwait(false);
return Response.Response.DefaultIfNull(resp);
@@ -94,7 +94,7 @@ internal sealed partial class PassportClient2
/// 扫码链接中的ticket
/// 取消令牌
/// 扫码结果
- public async ValueTask> PostQrCodeQueryAsync(string ticket, CancellationToken token = default)
+ public async ValueTask> QRCodeQueryAsync(string ticket, CancellationToken token = default)
{
GameLoginResultOptions options = GameLoginResultOptions.Create(4, HoyolabOptions.Device, ticket);
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestResult.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UrlWrapper.cs
similarity index 64%
rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestResult.cs
rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UrlWrapper.cs
index 13f067b2..bda18383 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/GameLoginRequestResult.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Passport/UrlWrapper.cs
@@ -3,11 +3,7 @@
namespace Snap.Hutao.Web.Hoyolab.Passport;
-///
-/// 扫码登录请求结果
-///
-[HighQuality]
-internal sealed class GameLoginRequestResult
+internal sealed class UrlWrapper
{
[JsonPropertyName("url")]
public string Url { get; set; } = default!;