From a150c4a04c1d79aa0fe6a9c2692796d3ddbb1f1c Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Sun, 13 Nov 2022 15:38:02 +0800 Subject: [PATCH] support getWidgetData for #207 --- .../DependencyInjection/IocConfiguration.cs | 2 +- .../Snap.Hutao/Core/Validation/Must.cs | 5 +- .../Core/Windowing/ExtendedWindow.cs | 2 +- .../Model/Metadata/Avatar/Avatar.cs | 6 +- .../Converter/ElementNameIconConverter.cs | 7 ++- .../Snap.Hutao/Model/Primitive/AvatarId.cs | 3 +- .../Annotation/ApiInformationAttribute.cs | 23 +++++++ .../Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs | 12 ++++ .../Web/Hoyolab/App/GameRecord/CardClient.cs | 51 ++++++++++++++++ .../Web/Hoyolab/App/GameRecord/WidgetData.cs | 60 +++++++++++++++++++ .../Hoyolab/App/GameRecord/WidgetDataItem.cs | 30 ++++++++++ .../Web/Hoyolab/Bbs/User/UserClient.cs | 8 +-- .../Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs | 2 + .../Snap.Hutao/Web/Hoyolab/Cookie.cs | 22 ++++++- .../Snap.Hutao/Web/Hoyolab/CookieType.cs | 25 ++++++++ .../Web/Hoyolab/HttpClientExtensions.cs | 6 +- .../Snap.Hutao/Web/Response/DataWrapper.cs | 17 ++++++ .../Web/Response/KnownReturnCode.cs | 5 ++ .../Snap.Hutao/Web/Response/ListWrapper.cs | 2 +- 19 files changed, 272 insertions(+), 16 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Annotation/ApiInformationAttribute.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/CardClient.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/WidgetData.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/WidgetDataItem.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/CookieType.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Web/Response/DataWrapper.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs index e9123957..c424a285 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs @@ -46,6 +46,6 @@ internal static class IocConfiguration } } - return services.AddDbContextPool(builder => builder.UseSqlite(sqlConnectionString)); + return services.AddDbContext(builder => builder.UseSqlite(sqlConnectionString)); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs b/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs index 10f37bf9..1f0420ad 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs @@ -54,11 +54,12 @@ public static class Must /// /// Unconditionally throws an . /// + /// 上下文 /// Nothing. This method always throws. [DoesNotReturn] - public static System.Exception NeverHappen() + public static System.Exception NeverHappen(string? context = null) { - throw new NotSupportedException("该行为不应发生,请联系开发者进一步确认"); + throw new NotSupportedException(context); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs index 52985e8e..54391558 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs @@ -182,7 +182,7 @@ internal sealed class ExtendedWindow : IRecipient /// Id /// - public int Id { get; set; } + public AvatarId Id { get; set; } /// /// 排序号 @@ -88,6 +89,7 @@ public class Avatar : IStatisticsItemSource, ISummaryItemSource, INameQuality /// /// [非元数据] 搭配数据 /// + [JsonIgnore] public ComplexAvatarCollocation? Collocation { get; set; } /// @@ -118,6 +120,7 @@ public class Avatar : IStatisticsItemSource, ISummaryItemSource, INameQuality Icon = AvatarIconConverter.IconNameToUri(Icon), Badge = ElementNameIconConverter.ElementNameToIconUri(FetterInfo.VisionBefore), Quality = Quality, + Count = count, }; } @@ -137,6 +140,7 @@ public class Avatar : IStatisticsItemSource, ISummaryItemSource, INameQuality Icon = AvatarIconConverter.IconNameToUri(Icon), Badge = ElementNameIconConverter.ElementNameToIconUri(FetterInfo.VisionBefore), Quality = Quality, + Time = time, LastPull = lastPull, IsUp = isUp, diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ElementNameIconConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ElementNameIconConverter.cs index 44511d57..0a91550f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ElementNameIconConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/ElementNameIconConverter.cs @@ -11,6 +11,7 @@ namespace Snap.Hutao.Model.Metadata.Converter; internal class ElementNameIconConverter : ValueConverterBase { private const string BaseUrl = "https://static.snapgenshin.com/IconElement/UI_Icon_Element_{0}.png"; + private static readonly Uri UIIconNone = new("https://static.snapgenshin.com/Bg/UI_Icon_None.png"); /// /// 将中文元素名称转换为图标链接 @@ -28,10 +29,12 @@ internal class ElementNameIconConverter : ValueConverterBase "岩" => "Rock", "水" => "Water", "风" => "Wind", - _ => throw Must.NeverHappen(), + _ => string.Empty, }; - return new Uri(string.Format(BaseUrl, element)); + return string.IsNullOrEmpty(element) + ? UIIconNone + : new Uri(string.Format(BaseUrl, element)); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs index 811d5e61..80feeedc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/AvatarId.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Primitive.Converter; +using Windows.ApplicationModel.Chat; namespace Snap.Hutao.Model.Primitive; @@ -62,4 +63,4 @@ public readonly struct AvatarId : IEquatable { return Value.GetHashCode(); } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Annotation/ApiInformationAttribute.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Annotation/ApiInformationAttribute.cs new file mode 100644 index 00000000..e531a250 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Annotation/ApiInformationAttribute.cs @@ -0,0 +1,23 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Snap.Hutao.Web.Hoyolab.Annotation; + +/// +/// API 信息 +/// +/// API 的返回类型 +[AttributeUsage(AttributeTargets.Method)] +internal class ApiInformationAttribute : Attribute +{ + /// + /// Cookie类型 + /// + public CookieType Cookie { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs index ec6bb1cc..41286916 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/ApiEndpoints.cs @@ -145,13 +145,25 @@ 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 App + + /// + /// 小组件数据 + /// + public const string AppWidgetData = $"{AppCardApi}/getWidgetData?game_id=2"; + #endregion + // consts private const string ApiTakumi = "https://api-takumi.mihoyo.com"; private const string ApiTakumiAuthApi = $"{ApiTakumi}/auth/api"; private const string ApiTaKumiBindingApi = $"{ApiTakumi}/binding/api"; + private const string ApiTakumiRecord = "https://api-takumi-record.mihoyo.com"; private const string ApiTakumiRecordApi = $"{ApiTakumiRecord}/game_record/app/genshin/api"; + private const string App = "https://app.mihoyo.com"; + private const string AppCardApi = $"{App}/game_record/app/card/api"; + private const string BbsApi = "https://bbs-api.mihoyo.com"; private const string BbsApiUserApi = $"{BbsApi}/user/wapi"; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/CardClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/CardClient.cs new file mode 100644 index 00000000..200fafd3 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/CardClient.cs @@ -0,0 +1,51 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; +using Snap.Hutao.Model.Entity; +using Snap.Hutao.Web.Hoyolab.Annotation; +using Snap.Hutao.Web.Response; +using System.Net.Http; + +namespace Snap.Hutao.Web.Hoyolab.App.GameRecord; + +/// +/// 桌面卡片客户端 +/// +[HttpClient(HttpClientConfigration.XRpc)] +internal class CardClient +{ + private readonly HttpClient httpClient; + private readonly JsonSerializerOptions options; + private readonly ILogger logger; + + /// + /// 构造一个新的桌面卡片客户端 + /// + /// http客户端 + /// 选项 + /// 日志器 + public CardClient(HttpClient httpClient, JsonSerializerOptions options, ILogger logger) + { + this.httpClient = httpClient; + this.options = options; + this.logger = logger; + } + + /// + /// 异步获取桌面小组件数据 + /// + /// 用户 + /// 取消令牌 + /// 桌面小组件数据 + [ApiInformation(Cookie = CookieType.Stoken)] + public async Task GetWidgetDataAsync(User user, CancellationToken token) + { + Response>? resp = await httpClient + .SetUser(user, CookieType.Stoken) + .TryCatchGetFromJsonAsync>>(ApiEndpoints.UserFullInfo, options, logger, token) + .ConfigureAwait(false); + + return resp?.Data?.Data; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/WidgetData.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/WidgetData.cs new file mode 100644 index 00000000..db24dcfe --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/WidgetData.cs @@ -0,0 +1,60 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; + +namespace Snap.Hutao.Web.Hoyolab.App.GameRecord; + +/// +/// 小组件数据 +/// +public class WidgetData +{ + /// + /// 游戏Id 2 + /// + [JsonPropertyName("game_id")] + public int GameId { get; set; } + + /// + /// 游戏内Uid + /// + [JsonPropertyName("game_role_id")] + public string GameRoleId { get; set; } = default!; + + /// + /// 昵称 + /// + [JsonPropertyName("nickname")] + public string Nickname { get; set; } = default!; + + /// + /// 区服 + /// + [JsonPropertyName("region")] + public string Region { get; set; } = default!; + + /// + /// 冒险等阶 + /// + [JsonPropertyName("level")] + public int Level { get; set; } + + /// + /// 背景图片 + /// + [JsonPropertyName("background_image")] + public string BackgroundImage { get; set; } = default!; + + /// + /// 数据 + /// + [JsonPropertyName("data")] + public List Data { get; set; } = default!; + + /// + /// 区服名称 + /// + [JsonPropertyName("region_name")] + public string RegionName { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/WidgetDataItem.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/WidgetDataItem.cs new file mode 100644 index 00000000..306d110c --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/App/GameRecord/WidgetDataItem.cs @@ -0,0 +1,30 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; + +namespace Snap.Hutao.Web.Hoyolab.App.GameRecord; + +/// +/// 小组件数据项 +/// +public class WidgetDataItem +{ + /// + /// 项目名称 + /// + [JsonPropertyName("name")] + public string Name { get; set; } = default!; + + /// + /// 类型 均为 "String" + /// + [JsonPropertyName("type")] + public string Type { get; set; } = default!; + + /// + /// 显示值 + /// + [JsonPropertyName("value")] + public string Value { get; set; } = default!; +} \ 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 06d74223..b2335ec9 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 @@ -39,10 +39,10 @@ internal class UserClient public async Task GetUserFullInfoAsync(Model.Binding.User.User user, CancellationToken token = default) { Response? resp = await httpClient - .SetUser(user) - .SetReferer(ApiEndpoints.BbsReferer) - .TryCatchGetFromJsonAsync>(ApiEndpoints.UserFullInfo, options, logger, token) - .ConfigureAwait(false); + .SetUser(user) + .SetReferer(ApiEndpoints.BbsReferer) + .TryCatchGetFromJsonAsync>(ApiEndpoints.UserFullInfo, options, logger, token) + .ConfigureAwait(false); return resp?.Data?.UserInfo; } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs index e75309c5..bdbae465 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.Constant.cs @@ -21,4 +21,6 @@ public partial class Cookie public const string STOKEN = "stoken"; public const string STUID = "stuid"; + + public const string MID = "mid"; } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs index 800a1b83..b944bd44 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Cookie.cs @@ -192,12 +192,32 @@ public partial class Cookie } } + /// + /// 根据类型输出对应的Cookie + /// + /// 类型 + /// Cookie对应的字符串表示 + public string ToString(CookieType type) + { + IEnumerable> results; + + results = type switch + { + CookieType.None => Enumerable.Empty>(), + CookieType.Stoken => inner.Where(kvp => kvp.Key is STUID or STOKEN or MID), + CookieType.All => inner, + _ => throw Must.NeverHappen(type.ToString()), + }; + + return string.Join(';', results.Select(kvp => $"{kvp.Key}={kvp.Value}")); + } + /// /// 转换为Cookie的字符串表示 /// /// Cookie的字符串表示 public override string ToString() { - return string.Join(';', inner.Select(kvp => $"{kvp.Key}={kvp.Value}")); + return ToString(CookieType.All); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/CookieType.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/CookieType.cs new file mode 100644 index 00000000..35ff67a0 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/CookieType.cs @@ -0,0 +1,25 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Web.Hoyolab; + +/// +/// Cookie 类型 +/// +public enum CookieType +{ + /// + /// 不需要 Cookie + /// + None, + + /// + /// 需要 Stoken + /// + Stoken, + + /// + /// 全部 + /// + All, +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientExtensions.cs index 7c12df53..4bf2b8c0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientExtensions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientExtensions.cs @@ -66,6 +66,7 @@ internal static class HttpClientExtensions /// http客户端 /// 绑定用户 /// 客户端 + [Obsolete("请使用带有 type 的重载")] internal static HttpClient SetUser(this HttpClient httpClient, User user) { httpClient.DefaultRequestHeaders.Set("Cookie", user.Cookie!.ToString()); @@ -77,10 +78,11 @@ internal static class HttpClientExtensions /// /// http客户端 /// 实体用户 + /// Cookie类型 /// 客户端 - internal static HttpClient SetUser(this HttpClient httpClient, Model.Entity.User user) + internal static HttpClient SetUser(this HttpClient httpClient, Model.Entity.User user, CookieType type = CookieType.All) { - httpClient.DefaultRequestHeaders.Set("Cookie", user.Cookie!.ToString()); + httpClient.DefaultRequestHeaders.Set("Cookie", user.Cookie!.ToString(type)); return httpClient; } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/DataWrapper.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/DataWrapper.cs new file mode 100644 index 00000000..3ad18a70 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/DataWrapper.cs @@ -0,0 +1,17 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Web.Response; + +/// +/// 数据对象包装器 +/// +/// 数据类型 +public class DataWrapper +{ + /// + /// 数据 + /// + [JsonPropertyName("data")] + public T Data { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs index 6151989c..3e72c6ed 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/KnownReturnCode.cs @@ -23,6 +23,11 @@ public enum KnownReturnCode : int /// RET_NEED_RISK_VERIFY = -3235, + /// + /// 验证码已失效,请重新获取 + /// + VerifyCodeOutdated = -3209, + /// /// 禁止 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Response/ListWrapper.cs b/src/Snap.Hutao/Snap.Hutao/Web/Response/ListWrapper.cs index bbac76d7..2452b91c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Response/ListWrapper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Response/ListWrapper.cs @@ -14,4 +14,4 @@ public class ListWrapper /// [JsonPropertyName("list")] public List List { get; set; } = default!; -} +} \ No newline at end of file