diff --git a/README.md b/README.md index d9cf7fe5c3..2bad66cc80 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,26 @@ -# Snap.Hutao +# [Snap.Hutao](https://hut.ao) > 唷,找本堂主有何贵干呀? ![Snap.Hutao](https://repobeats.axiom.co/api/embed/f029553fbe0c60689b1710476ec8512452163fc9.svg) -## 项目首页(文档) +# 特别感谢 -[![Deploy Docs](https://github.com/DGP-Studio/Snap.Hutao.Docs/actions/workflows/deploy-docs.yml/badge.svg)](https://github.com/DGP-Studio/Snap.Hutao.Docs/actions/workflows/deploy-docs.yml) +### 原神组织与个人 -[HUT.AO](https://hut.ao) +* [HolographicHat](https://github.com/HolographicHat) +* [UIGF organization](https://uigf.org) -## 安装 - -* 前往 [下载页面](https://go.hut.ao/down) 下载最新版本的 `胡桃` 安装包 -* (曾启用的可以跳过此步骤)在系统设置中打开 **开发者选项** 界面,勾选 `开发人员模式` 和 `允许 PowerShell 脚本` -* 完全解压后,右键使用 powershell 运行 `install.ps1` 文件 -* 安装完成后可以关闭 `允许 PowerShell 脚本` - -## 特别感谢 - -### 原神项目 +### 特定的原神项目 * [biuuu/genshin-wish-export](https://github.com/biuuu/genshin-wish-export) -* [HolographicHat/YaeAchievement](https://github.com/HolographicHat/YaeAchievement) -* [HolographicHat/MiHoYoWebBridge](https://github.com/HolographicHat/MiHoYoWebBridge) * [xunkong/xunkong](https://github.com/xunkong/xunkong) * [YuehaiTeam/cocogoat](https://github.com/YuehaiTeam/cocogoat) -### 技术栈 +### 使用的技术栈 * [CommunityToolkit/dotnet](https://github.com/CommunityToolkit/dotnet) * [CommunityToolkit/WindowsCommunityToolkit](https://github.com/CommunityToolkit/WindowsCommunityToolkit) +* [dahall/taskscheduler](https://github.com/dahall/taskscheduler) * [dotnet/efcore](https://github.com/dotnet/efcore) * [dotnet/runtime](https://github.com/dotnet/runtime) * [DotNetAnalyzers/StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/PickerFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/PickerFactory.cs index b44da7bdbe..5aff475177 100644 --- a/src/Snap.Hutao/Snap.Hutao/Factory/PickerFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Factory/PickerFactory.cs @@ -3,6 +3,9 @@ using Snap.Hutao.Factory.Abstraction; using Windows.Storage.Pickers; +using Windows.Win32; +using Windows.Win32.UI.Shell; +using WinRT; using WinRT.Interop; namespace Snap.Hutao.Factory; @@ -37,6 +40,7 @@ public FileOpenPicker GetFileOpenPicker(PickerLocationId location, string commit picker.FileTypeFilter.Add(type); } + // https://github.com/microsoft/WindowsAppSDK/issues/2931 picker.FileTypeFilter.Add(AnyType); return picker; diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Cultivation/CultivateItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Cultivation/CultivateItem.cs index 758f7d7e01..74d56fca93 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Cultivation/CultivateItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Cultivation/CultivateItem.cs @@ -25,6 +25,7 @@ public CultivateItem(Material inner, Entity.CultivateItem entity) Inner = inner; Entity = entity; isFinished = Entity.IsFinished; + IsToday = CultivateItemHelper.IsTodaysMaterial(inner.Id, DateTimeOffset.Now); FinishStateCommand = new RelayCommand(FlipIsFinished); } @@ -59,6 +60,11 @@ public bool IsFinished } } + /// + /// 是否为今日物品 + /// + public bool IsToday { get; } + private void FlipIsFinished() { IsFinished = !IsFinished; diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Cultivation/CultivateItemHelper.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Cultivation/CultivateItemHelper.cs new file mode 100644 index 0000000000..775e4563b9 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Cultivation/CultivateItemHelper.cs @@ -0,0 +1,64 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.Binding.Cultivation; + +/// +/// 养成物品帮助类 +/// +public static class CultivateItemHelper +{ + /// + /// 判断是否为当日物品 + /// + /// 材料Id + /// 时间 + /// 是否为当日物品 + public static bool IsTodaysMaterial(int itemId, DateTimeOffset now) + { + DateTimeOffset utcNow = now.ToUniversalTime(); + utcNow = utcNow.AddHours(4); + DayOfWeek dayOfWeek = utcNow.DayOfWeek; + + return dayOfWeek switch + { + DayOfWeek.Monday or DayOfWeek.Thursday => itemId switch + { + 104301 or 104302 or 104303 => true, // 「自由」 + 104310 or 104311 or 104312 => true, // 「繁荣」 + 104320 or 104321 or 104322 => true, // 「浮世」 + 104329 or 104330 or 104331 => true, // 「诤言」 + 114001 or 114002 or 114003 or 114004 => true, // 高塔孤王 + 114013 or 114014 or 114015 or 114016 => true, // 孤云寒林 + 114025 or 114026 or 114027 or 114028 => true, // 远海夷地 + 114037 or 114038 or 114039 or 114040 => true, // 谧林涓露 + _ => false, + }, + DayOfWeek.Tuesday or DayOfWeek.Friday => itemId switch + { + 104304 or 104305 or 104306 => true, // 「抗争」 + 104313 or 104314 or 104315 => true, // 「勤劳」 + 104323 or 104324 or 104325 => true, // 「风雅」 + 104332 or 104333 or 104334 => true, // 「巧思」 + 114005 or 114006 or 114007 or 114008 => true, // 凛风奔狼 + 114017 or 114018 or 114019 or 114020 => true, // 雾海云间 + 114029 or 114030 or 114031 or 114032 => true, // 鸣神御灵 + 114041 or 114042 or 114043 or 114044 => true, // 绿洲花园 + _ => false, + }, + DayOfWeek.Wednesday or DayOfWeek.Saturday => itemId switch + { + 104307 or 104308 or 104309 => true, // 「诗文」 + 104316 or 104317 or 104318 => true, // 「黄金」 + 104326 or 104327 or 104328 => true, // 「天光」 + 104335 or 104336 or 104337 => true, // 「笃行」 + 114009 or 114010 or 114011 or 114012 => true, // 狮牙斗士 + 114021 or 114022 or 114023 or 114024 => true, // 漆黑陨铁 + 114033 or 114034 or 114035 or 114036 => true, // 今昔剧画 + 114045 or 114046 or 114047 or 114048 => true, // 谧林涓露 + _ => false, + }, + _ => false, + }; + } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/CookBonusView.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/CookBonusView.cs new file mode 100644 index 0000000000..aa9fc7d3ef --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/CookBonusView.cs @@ -0,0 +1,46 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Metadata; +using Snap.Hutao.Model.Metadata.Avatar; +using Snap.Hutao.Model.Primitive; + +namespace Snap.Hutao.Model.Binding.Hutao; + +/// +/// 料理奖励视图 +/// +public class CookBonusView +{ + /// + /// 原型 + /// + public Material OriginItem { get; set; } = default!; + + /// + /// 名称 + /// + public Material Item { get; set; } = default!; + + /// + /// 创建一个新的料理奖励视图 + /// + /// 料理奖励 + /// 材料映射 + /// 新的料理奖励视图 + public static CookBonusView? Create(CookBonus? cookBonus, Dictionary idMaterialMap) + { + if (cookBonus == null) + { + return null; + } + + CookBonusView view = new() + { + OriginItem = idMaterialMap[cookBonus.OriginItemId], + Item = idMaterialMap[cookBonus.ItemId], + }; + + return view; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIF.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIF.cs index 47fbe2be79..79c11ffeef 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIF.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIF.cs @@ -31,60 +31,4 @@ internal class UIIF /// [JsonPropertyName("list")] public List List { get; set; } = default!; -} - -/// -/// UIIF物品 -/// -[JsonDerivedType(typeof(UIIFReliquary))] -[JsonDerivedType(typeof(UIIFWeapon))] -internal class UIIFItem -{ - /// - /// 物品Id - /// - [JsonPropertyName("itemId")] - public int ItemId { get; set; } - - /// - /// 物品Id - /// - [JsonPropertyName("count")] - public int Count { get; set; } -} - -/// -/// UIIF圣遗物 -/// -internal class UIIFReliquary : UIIFItem -{ - /// - /// 物品Id - /// - [JsonPropertyName("level")] - public int Level { get; set; } - - /// - /// 副属性列表 - /// - [JsonPropertyName("appendPropIdList")] - public List AppendPropIdList { get; set; } = default!; -} - -/// -/// UIIF武器 -/// -internal class UIIFWeapon : UIIFItem -{ - /// - /// 物品Id - /// - [JsonPropertyName("level")] - public int Level { get; set; } - - /// - /// 精炼等级 0-4 - /// - [JsonPropertyName("promoteLevel")] - public int PromoteLevel { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFItem.cs new file mode 100644 index 0000000000..7314656b4b --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFItem.cs @@ -0,0 +1,45 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using System.Collections.Immutable; + +namespace Snap.Hutao.Model.InterChange.Inventory; + +/// +/// UIIF物品 +/// +internal class UIIFItem +{ + /// + /// 物品Id + /// + [JsonPropertyName("itemId")] + public int ItemId { get; set; } + + /// + /// 物品Id + /// + [JsonPropertyName("count")] + public int Count { get; set; } + + /// + /// 等级 + /// Reliquary/Weapon + /// + [JsonPropertyName("level")] + public int? Level { get; set; } + + /// + /// 副属性列表 + /// Reliquary + /// + [JsonPropertyName("appendPropIdList")] + public List? AppendPropIdList { get; set; } = default!; + + /// + /// 精炼等级 0-4 + /// Weapon + /// + [JsonPropertyName("promoteLevel")] + public int? PromoteLevel { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs new file mode 100644 index 0000000000..9def3dcd98 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs @@ -0,0 +1,59 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.Intrinsic; + +/// +/// 材料类型 +/// +[SuppressMessage("", "SA1602")] +public enum MaterialType +{ + MATERIAL_NONE = 0, + MATERIAL_FOOD = 1, + MATERIAL_QUEST = 2, + MATERIAL_EXCHANGE = 4, + MATERIAL_CONSUME, + MATERIAL_EXP_FRUIT, + MATERIAL_AVATAR, + MATERIAL_ADSORBATE, + MATERIAL_CRICKET, + MATERIAL_ELEM_CRYSTAL, + MATERIAL_WEAPON_EXP_STONE, + MATERIAL_CHEST, + MATERIAL_RELIQUARY_MATERIAL, + MATERIAL_AVATAR_MATERIAL, + MATERIAL_NOTICE_ADD_HP, + MATERIAL_SEA_LAMP, + MATERIAL_SELECTABLE_CHEST, + MATERIAL_FLYCLOAK, + MATERIAL_NAMECARD, + MATERIAL_TALENT, + MATERIAL_WIDGET, + MATERIAL_CHEST_BATCH_USE, + MATERIAL_FAKE_ABSORBATE, + MATERIAL_CONSUME_BATCH_USE, + MATERIAL_WOOD, + MATERIAL_FURNITURE_FORMULA = 27, + MATERIAL_CHANNELLER_SLAB_BUFF, + MATERIAL_FURNITURE_SUITE_FORMULA, + MATERIAL_COSTUME, + MATERIAL_HOME_SEED, + MATERIAL_FISH_BAIT, + MATERIAL_FISH_ROD, + MATERIAL_SUMO_BUFF, // never appear + MATERIAL_FIREWORKS, + MATERIAL_BGM, + MATERIAL_SPICE_FOOD, + MATERIAL_ACTIVITY_ROBOT, + MATERIAL_ACTIVITY_GEAR, + MATERIAL_ACTIVITY_JIGSAW, + MATERIAL_ARANARA, + MATERIAL_GCG_CARD, + MATERIAL_GCG_CARD_FACE, // 影幻卡面 + MATERIAL_GCG_CARD_BACK, + MATERIAL_GCG_FIELD, + MATERIAL_DESHRET_MANUAL, + MATERIAL_RENAME_ITEM, + MATERIAL_GCG_EXCHANGE_ITEM, +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs index d7997f5c43..81a63f1aea 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs @@ -22,6 +22,17 @@ public partial class Avatar : IStatisticsItemSource, ISummaryItemSource, INameQu [JsonIgnore] public ComplexAvatarCollocation? Collocation { get; set; } + /// + /// [非元数据] 烹饪奖励 + /// + [JsonIgnore] + public CookBonusView? CookBonusView { get; set; } + + /// + /// 养成物品视图 + /// + public List? CultivationItemsView { get; set; } + /// public ICalculableAvatar ToCalculable() { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs index 65b5d65358..8eff5b97bf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs @@ -81,5 +81,10 @@ public partial class Avatar /// /// 皮肤 /// - public IEnumerable Costumes { get; set; } = default!; + public List Costumes { get; set; } = default!; + + /// + /// 养成物品 + /// + public List CultivationItems { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/CookBonus.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/CookBonus.cs index 9fbdb57b30..888c4bd4c5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/CookBonus.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/CookBonus.cs @@ -1,7 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Primitive; namespace Snap.Hutao.Model.Metadata.Avatar; @@ -13,45 +13,15 @@ public class CookBonus /// /// 原型名称 /// - public string OriginName { get; set; } = default!; - - /// - /// 原型描述 - /// - public string OriginDescription { get; set; } = default!; - - /// - /// 原型图标 - /// - public string OriginIcon { get; set; } = default!; + public MaterialId OriginItemId { get; set; } = default!; /// /// 名称 /// - public string Name { get; set; } = default!; - - /// - /// 描述 - /// - public string Description { get; set; } = default!; - - /// - /// 效果描述 - /// - public string EffectDescription { get; set; } = default!; - - /// - /// 图标 - /// - public string Icon { get; set; } = default!; - - /// - /// 物品等级 - /// - public ItemQuality RankLevel { get; set; } + public MaterialId ItemId { get; set; } = default!; /// /// 材料列表 /// - public List InputList { get; set; } = default!; + public List InputList { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs index b6c823a559..ba4cd8f684 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs @@ -83,7 +83,7 @@ public string BirthFormatted /// /// 料理 /// - public CookBonus? CookBonus { get; set; } + public CookBonus? CookBonus2 { get; set; } /// /// 好感语音 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyInfoDescriptor.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyInfoDescriptor.cs index ca7b087c3b..9af3879c9a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyInfoDescriptor.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyInfoDescriptor.cs @@ -105,4 +105,4 @@ private static IList GetParameterInfos(IList parameters, return results; } -} \ No newline at end of file +} diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Material.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Material.cs index e46e897f2c..e580002b3c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Material.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Material.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Primitive; namespace Snap.Hutao.Model.Metadata; @@ -13,7 +14,7 @@ public class Material /// /// 物品Id /// - public int Id { get; set; } + public MaterialId Id { get; set; } /// /// 等级 @@ -25,6 +26,11 @@ public class Material /// public ItemType ItemType { get; set; } + /// + /// 材料类型 + /// + public MaterialType MaterialType { get; set; } + /// /// 图标 /// @@ -44,4 +50,9 @@ public class Material /// 类型描述 /// public string TypeDescription { get; set; } = default!; + + /// + /// 效果描述 + /// + public string? EffectDescription { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/MaterialId.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/MaterialId.cs new file mode 100644 index 0000000000..59cbcb4060 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/MaterialId.cs @@ -0,0 +1,71 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Primitive.Converter; + +namespace Snap.Hutao.Model.Primitive; + +/// +/// 3-6位 材料Id +/// +[JsonConverter(typeof(IdentityConverter))] +public readonly struct MaterialId : IEquatable, IComparable +{ + /// + /// 值 + /// + public readonly int Value; + + /// + /// Initializes a new instance of the struct. + /// + /// value + public MaterialId(int value) + { + Value = value; + } + + public static implicit operator int(MaterialId value) + { + return value.Value; + } + + public static implicit operator MaterialId(int value) + { + return new(value); + } + + public static bool operator ==(MaterialId left, MaterialId right) + { + return left.Value == right.Value; + } + + public static bool operator !=(MaterialId left, MaterialId right) + { + return !(left == right); + } + + /// + public int CompareTo(MaterialId other) + { + return Value.CompareTo(other.Value); + } + + /// + public bool Equals(MaterialId other) + { + return Value == other.Value; + } + + /// + public override bool Equals(object? obj) + { + return obj is MaterialId other && Equals(other); + } + + /// + public override int GetHashCode() + { + return Value.GetHashCode(); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/WeaponId.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/WeaponId.cs index d274ae4423..70d2d4079b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/WeaponId.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/WeaponId.cs @@ -62,4 +62,4 @@ public override int GetHashCode() { return Value.GetHashCode(); } -} \ No newline at end of file +} diff --git a/src/Snap.Hutao/Snap.Hutao/NativeMethods.txt b/src/Snap.Hutao/Snap.Hutao/NativeMethods.txt index 1a601fd0e8..0c64a13b20 100644 --- a/src/Snap.Hutao/Snap.Hutao/NativeMethods.txt +++ b/src/Snap.Hutao/Snap.Hutao/NativeMethods.txt @@ -4,8 +4,6 @@ WM_GETMINMAXINFO WM_NCRBUTTONDOWN WM_NCRBUTTONUP -STDAPI - // Type definition CWMO_FLAGS HRESULT diff --git a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest index 2e8b4b8138..0f77283457 100644 --- a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest +++ b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest @@ -12,7 +12,7 @@ + Version="1.2.15.0" /> 胡桃 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs index 4f11e774e6..95bb831f15 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs @@ -155,7 +155,8 @@ public async Task> GetCultivateEntri List resultItems = new(); List items = await appDbContext.CultivateItems .Where(i => i.EntryId == entryId) - .OrderBy(i => i.ItemId).ToListAsync() + .OrderBy(i => i.ItemId) + .ToListAsync() .ConfigureAwait(false); foreach (CultivateItem item in items) @@ -173,7 +174,7 @@ public async Task> GetCultivateEntri results.Add(new(entry, itemBase, resultItems)); } - return new(results); + return new(results.OrderByDescending(e => e.Items.Any(i => i.IsToday))); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotifier.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotifier.cs index 130b29b100..e4b9942022 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotifier.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotifier.cs @@ -6,6 +6,7 @@ using Snap.Hutao.Context.Database; using Snap.Hutao.Core.Database; using Snap.Hutao.Model.Entity; +using Snap.Hutao.Web.Hoyolab.Takumi.Auth; using Snap.Hutao.Web.Hoyolab.Takumi.Binding; using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote; @@ -23,7 +24,6 @@ internal class DailyNoteNotifier /// 构造一个新的实时便笺通知器 /// /// 范围工厂 - /// 绑定客户端 /// 实时便笺入口 public DailyNoteNotifier(IServiceScopeFactory scopeFactory, DailyNoteEntry entry) { @@ -121,8 +121,17 @@ public async ValueTask NotifyAsync() { AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); BindingClient bindingClient = scope.ServiceProvider.GetRequiredService(); + AuthClient authClient = scope.ServiceProvider.GetRequiredService(); + + string? actionTicket = await authClient + .GetActionTicketByStokenAsync("game_role", entry.User) + .ConfigureAwait(false); + + List roles = await scope.ServiceProvider + .GetRequiredService() + .GetUserGameRolesByActionTicketAsync(actionTicket!, entry.User) + .ConfigureAwait(false); - List roles = await bindingClient.GetUserGameRolesByCookieAsync(entry.User).ConfigureAwait(false); string attribution = roles.SingleOrDefault(r => r.GameUid == entry.Uid)?.ToString() ?? "未知角色"; ToastContentBuilder builder = new ToastContentBuilder() diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs index a3e2c2aa6e..3c21465fc5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs @@ -64,6 +64,13 @@ internal interface IMetadataService /// Id到角色的字典 ValueTask> GetIdToAvatarMapAsync(CancellationToken token = default); + /// + /// 异步获取Id到材料的字典 + /// + /// 取消令牌 + /// Id到材料的字典 + ValueTask> GetIdToMaterialMapAsync(CancellationToken token = default(CancellationToken)); + /// /// 异步获取ID到圣遗物副词条的字典 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs index 8c27a5b744..40b3e530f1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Metadata; using Snap.Hutao.Model.Metadata.Avatar; using Snap.Hutao.Model.Metadata.Reliquary; using Snap.Hutao.Model.Metadata.Weapon; @@ -26,6 +27,12 @@ public ValueTask> GetIdToAvatarMapAsync(Cancellatio return FromCacheAsDictionaryAsync("Avatar", a => a.Id, token); } + /// + public ValueTask> GetIdToMaterialMapAsync(CancellationToken token = default) + { + return FromCacheAsDictionaryAsync("Material", a => a.Id, token); + } + /// public ValueTask> GetIdReliquaryAffixMapAsync(CancellationToken token = default) { diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index 6bc32b0df2..9b3d8d0b23 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -71,6 +71,7 @@ + @@ -183,6 +184,11 @@ + + + MSBuild:Compile + + MSBuild:Compile diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/CommunityGameRecordDialog.xaml b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CommunityGameRecordDialog.xaml new file mode 100644 index 0000000000..89b35a8dc1 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CommunityGameRecordDialog.xaml @@ -0,0 +1,22 @@ + + + + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/CommunityGameRecordDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CommunityGameRecordDialog.xaml.cs new file mode 100644 index 0000000000..8bf6f38604 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CommunityGameRecordDialog.xaml.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.Web.WebView2.Core; +using Snap.Hutao.Model.Binding.User; +using Snap.Hutao.Service.User; +using Snap.Hutao.Web.Bridge; + +namespace Snap.Hutao.View.Dialog; + +/// +/// Ϸ¼Ի +/// +public sealed partial class CommunityGameRecordDialog : ContentDialog +{ + private readonly IServiceScope scope; + [SuppressMessage("", "IDE0052")] + private MiHoYoJSInterface? jsInterface; + + /// + /// һµϷ¼Ի + /// + /// + public CommunityGameRecordDialog(MainWindow window) + { + InitializeComponent(); + XamlRoot = window.Content.XamlRoot; + scope = Ioc.Default.CreateScope(); + } + + private void OnGridLoaded(object sender, RoutedEventArgs e) + { + InitializeAsync().SafeForget(); + } + + private async Task InitializeAsync() + { + await WebView.EnsureCoreWebView2Async(); + CoreWebView2 coreWebView2 = WebView.CoreWebView2; + User? user = scope.ServiceProvider.GetRequiredService().Current; + + if (user == null) + { + return; + } + + coreWebView2.SetCookie(user.CookieToken, user.Ltoken, null).SetMobileUserAgent(); + jsInterface = new(coreWebView2, scope.ServiceProvider); + coreWebView2.Navigate("https://webstatic.mihoyo.com/app/community-game-records/index.html"); + } + + private void OnContentDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) + { + jsInterface = null; + scope.Dispose(); + } +} diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/SignInWebViewDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/SignInWebViewDialog.xaml.cs index b0f5e8e215..8da9a813a7 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/SignInWebViewDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/SignInWebViewDialog.xaml.cs @@ -39,8 +39,7 @@ private async Task InitializeAsync() { await WebView.EnsureCoreWebView2Async(); CoreWebView2 coreWebView2 = WebView.CoreWebView2; - IUserService userService = scope.ServiceProvider.GetRequiredService(); - User? user = userService.Current; + User? user = scope.ServiceProvider.GetRequiredService().Current; if (user == null) { diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml index 483884aa9d..3ac6b3eaa6 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml @@ -142,6 +142,13 @@ + + + + + + + 1 + + @@ -71,6 +77,7 @@ - + @@ -115,64 +122,65 @@ ToolTipService.ToolTip="删除清单"/> - - - - - - - - - - - - - + - - - - + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml index d7d2b50b02..2022a62947 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml @@ -178,13 +178,13 @@ - + @@ -286,6 +291,24 @@ Content="{Binding Selected.Property, Mode=OneWay}" ContentTemplate="{StaticResource PropertyDataTemplate}"/> + + + + + + + + + + + @@ -405,12 +426,7 @@ Margin="16,32,0,0" Style="{StaticResource BaseTextBlockStyle}" Text="其他"/> - + @@ -443,7 +459,7 @@ HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Header="料理"> - + @@ -451,7 +467,6 @@ - @@ -465,8 +480,8 @@ Grid.Row="1" Grid.Column="0" Margin="16,16,0,16" - Text="{Binding Selected.FetterInfo.CookBonus.Name}"> - + Text="{Binding Item.Name}"> + - + Text="{Binding OriginItem.Name}"> + - - - - - - - - - - - - - + Margin="16"> + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs index aeb320efb8..b8068b5c28 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs @@ -185,6 +185,37 @@ public NamedValue SelectedBackdropType /// public ICommand ShowSignInWebViewDialogCommand { get; } + private static async Task DangerousUnusedLoginMethodAsync() + { + LoginMihoyoBBSDialog dialog = ActivatorUtilities.CreateInstance(Ioc.Default); + (bool isOk, Dictionary? data) = await dialog.GetInputAccountPasswordAsync().ConfigureAwait(false); + + if (isOk) + { + (Response? resp, Aigis? aigis) = await Ioc.Default + .GetRequiredService() + .LoginByPasswordAsync(data, CancellationToken.None) + .ConfigureAwait(false); + + if (resp != null) + { + if (resp.IsOk()) + { + Cookie cookie = Cookie.FromLoginResult(resp.Data); + + await Ioc.Default + .GetRequiredService() + .ProcessInputCookieAsync(cookie) + .ConfigureAwait(false); + } + + if (resp.ReturnCode == (int)KnownReturnCode.RET_NEED_AIGIS) + { + } + } + } + } + private async Task SetGamePathAsync() { IGameLocator locator = Ioc.Default.GetRequiredService>() @@ -221,33 +252,10 @@ private async Task ShowSignInWebViewDialogAsync() private async Task DebugThrowExceptionAsync() { #if DEBUG - LoginMihoyoBBSDialog dialog = ActivatorUtilities.CreateInstance(Ioc.Default); - (bool isOk, Dictionary? data) = await dialog.GetInputAccountPasswordAsync().ConfigureAwait(false); - - if (isOk) - { - (Response? resp, Aigis? aigis) = await Ioc.Default - .GetRequiredService() - .LoginByPasswordAsync(data, CancellationToken.None) - .ConfigureAwait(false); - - if (resp != null) - { - if (resp.IsOk()) - { - Cookie cookie = Cookie.FromLoginResult(resp.Data); - - await Ioc.Default - .GetRequiredService() - .ProcessInputCookieAsync(cookie) - .ConfigureAwait(false); - } - - if (resp.ReturnCode == (int)KnownReturnCode.RET_NEED_AIGIS) - { - } - } - } + CommunityGameRecordDialog dialog = ActivatorUtilities.CreateInstance(Ioc.Default); + await dialog.ShowAsync(); +#else + await Task.Yield(); #endif } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs index b1c310875e..6b92301813 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs @@ -10,6 +10,7 @@ using Snap.Hutao.Model.Binding.Cultivation; using Snap.Hutao.Model.Binding.Hutao; using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Metadata; using Snap.Hutao.Model.Metadata.Avatar; using Snap.Hutao.Model.Primitive; using Snap.Hutao.Service.Abstraction; @@ -89,13 +90,14 @@ private async Task OpenUIAsync() { if (await metadataService.InitializeAsync().ConfigureAwait(false)) { + Dictionary idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false); List avatars = await metadataService.GetAvatarsAsync().ConfigureAwait(false); List sorted = avatars .OrderByDescending(avatar => avatar.BeginTime) .ThenByDescending(avatar => avatar.Sort) .ToList(); - await CombineWithAvatarCollocationsAsync(sorted).ConfigureAwait(false); + await CombineComplexDataAsync(sorted, idMaterialMap).ConfigureAwait(false); await ThreadHelper.SwitchToMainThreadAsync(); Avatars = new AdvancedCollectionView(sorted, true); @@ -103,7 +105,7 @@ private async Task OpenUIAsync() } } - private async Task CombineWithAvatarCollocationsAsync(List avatars) + private async Task CombineComplexDataAsync(List avatars, Dictionary idMaterialMap) { if (await hutaoCache.InitializeForWikiAvatarViewModelAsync().ConfigureAwait(false)) { @@ -112,6 +114,8 @@ private async Task CombineWithAvatarCollocationsAsync(List avatars) foreach (Avatar avatar in avatars) { avatar.Collocation = idCollocations.GetValueOrDefault(avatar.Id); + avatar.CookBonusView ??= CookBonusView.Create(avatar.FetterInfo.CookBonus2, idMaterialMap); + avatar.CultivationItemsView ??= avatar.CultivationItems.Select(i => idMaterialMap[i]).ToList(); } } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs index 813a846286..feaa34ec7b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs @@ -311,6 +311,14 @@ public static string GachaInfoGetGachaLog(string query) public const string AccountCreateActionTicket = $"{PassportApi}/account/ma-cn-verifier/app/createActionTicketByToken"; #endregion + #region Patcher + + /// + /// 胡桃检查更新 + /// + public const string PatcherHutaoStable = $"{PatcherApi}/hutao/stable"; + #endregion + #region SdkStaticLauncherApi /// @@ -360,6 +368,8 @@ public static string SdkStaticLauncherResource(string launcherId, string channel private const string PassportApiAuthApi = $"{PassportApi}/account/auth/api"; private const string PassportApiV4 = "https://passport-api-v4.mihoyo.com"; + private const string PatcherApi = "https://patcher.dgp-studio.cn"; + private const string SdkStatic = "https://sdk-static.mihoyo.com"; private const string SdkStaticLauncherApi = $"{SdkStatic}/hk4e_cn/mdk/launcher/api"; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs index 02990e3098..c44cabc0a3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs @@ -48,7 +48,7 @@ public class MiHoYoJSInterface /// /// webview2 /// 服务提供器 - protected MiHoYoJSInterface(CoreWebView2 webView, IServiceProvider serviceProvider) + public MiHoYoJSInterface(CoreWebView2 webView, IServiceProvider serviceProvider) { this.webView = webView; this.serviceProvider = serviceProvider; @@ -159,7 +159,7 @@ public virtual JsResult> GetDynamicSecrectV2(JsParam< long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); int r = GetRandom(); string b = param.Payload.Body; - string q = string.Join('&', param.Payload.Query.OrderBy(x => x.Key).Select(x => $"{x.Key}={x.Value}")); + string q = param.Payload.GetQueryParam(); string check = Md5Convert.ToHexString($"salt={salt}&t={t}&r={r}&b={b}&q={q}").ToLowerInvariant(); return new() { Data = new() { ["DS"] = $"{t},{r},{check}", }, }; @@ -256,6 +256,13 @@ public virtual JsResult> GetStatusBarHeight(JsParam p return new() { Data = new() { { "statusBarHeight", 0 } } }; } + [JsMethod("pushPage")] + public virtual IJsResult? PushPage(JsParam param) + { + webView.Navigate(param.Payload.Page); + return null; + } + [JsMethod("showAlertDialog")] public virtual Task ShowAlertDialogAsync(JsParam param) { @@ -286,12 +293,6 @@ public virtual JsResult> GetStatusBarHeight(JsParam p throw new NotImplementedException(); } - [JsMethod("pushPage")] - public virtual IJsResult? PushPage(JsParam param) - { - throw new NotImplementedException(); - } - [JsMethod("openSystemBrowser")] public virtual IJsResult? OpenSystemBrowser(JsParam param) { @@ -344,7 +345,7 @@ private async Task ExecuteCallbackScriptAsync(string callback, string? p private async void OnWebMessageReceived(CoreWebView2 webView2, CoreWebView2WebMessageReceivedEventArgs args) { string message = args.TryGetWebMessageAsString(); - + logger.LogInformation("[OnRawMessage]\n{message}", message); JsParam param = JsonSerializer.Deserialize(message)!; logger.LogInformation("[OnMessage]\nMethod : {method}\nPayload : {payload}\nCallback: {callback}", param.Method, param.Payload, param.Callback); @@ -363,6 +364,7 @@ private async void OnWebMessageReceived(CoreWebView2 webView2, CoreWebView2WebMe "getUserInfo" => GetUserInfo(param), "hideLoading" => null, "login" => null, + "pushPage" => PushPage(param), "showLoading" => null, _ => logger.LogWarning("Unhandled Message Type: {method}", param.Method), }; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/DynamicSecrect2Playload.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/DynamicSecrect2Playload.cs index 8505c3b21c..97447e153e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/DynamicSecrect2Playload.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/DynamicSecrect2Playload.cs @@ -12,11 +12,30 @@ public class DynamicSecrect2Playload /// q /// [JsonPropertyName("query")] - public Dictionary Query { get; set; } = default!; + public Dictionary Query { get; set; } = default!; /// /// b /// [JsonPropertyName("body")] public string Body { get; set; } = default!; + + /// + /// 获取排序后的的查询参数 + /// + /// 查询参数 + public string GetQueryParam() + { + IEnumerable parts = Query.OrderBy(x => x.Key).Select(x => + { + if (x.Value.ValueKind == JsonValueKind.True || x.Value.ValueKind == JsonValueKind.False) + { + return $"{x.Key}={x.Value.ToString().ToLowerInvariant()}"; + } + + return $"{x.Key}={x.Value}"; + }); + + return string.Join('&', parts); + } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/JsParam.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/JsParam.cs index 2eb39f4bf8..61e59145cd 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/JsParam.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/JsParam.cs @@ -63,4 +63,4 @@ public static implicit operator JsParam(JsParam jsParam) Callback = jsParam.Callback, }; } -} \ No newline at end of file +} diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/PushPagePayload.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/PushPagePayload.cs new file mode 100644 index 0000000000..b0ed80d87c --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/Model/PushPagePayload.cs @@ -0,0 +1,16 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Web.Bridge.Model; + +/// +/// 导航页面参数 +/// +public class PushPagePayload +{ + /// + /// 页面Url + /// + [JsonPropertyName("page")] + public string Page { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs index 789eb0abf6..9313031cdd 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient.cs @@ -59,6 +59,7 @@ public async Task> GetUserGameRolesByActionTicketAsync(string /// 用户 /// 取消令牌 /// 用户角色信息 + [Obsolete("Set-Cookie 冲突")] [ApiInformation(Cookie = CookieType.Ltoken)] public async Task> GetUserGameRolesByCookieAsync(User user, CancellationToken token = default) { diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient2.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient2.cs index da1cf2a1a9..8f08b9e7ed 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient2.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/BindingClient2.cs @@ -41,12 +41,12 @@ public BindingClient2(HttpClient httpClient, JsonSerializerOptions options, ILog /// 用户 /// 取消令牌 /// 用户角色信息 - [ApiInformation(Cookie = CookieType.Stoken)] + [ApiInformation(Cookie = CookieType.Stoken, Salt = SaltType.LK2)] public async Task> GetUserGameRolesByStokenAsync(User user, CancellationToken token = default) { Response>? resp = await httpClient .SetUser(user, CookieType.Stoken) - .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.K2, true) + .UseDynamicSecret(DynamicSecretVersion.Gen1, SaltType.LK2, true) .TryCatchGetFromJsonAsync>>(ApiEndpoints.UserGameRolesByStoken, options, logger, token) .ConfigureAwait(false); diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs index 522ac6e338..f50bd00b9f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs @@ -19,7 +19,6 @@ namespace Snap.Hutao.Web.Hutao; /// /// 胡桃API客户端 /// -// [Injection(InjectAs.Transient)] [HttpClient(HttpClientConfigration.Default)] internal class HomaClient { @@ -220,4 +219,4 @@ public async Task GetPlayerRecordAsync(User user, CancellationToke { return httpClient.TryCatchPostAsJsonAsync>($"{HutaoAPI}/Record/Upload", playerRecord, options, logger, token); } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Patch/PatchInformation.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Patch/PatchInformation.cs new file mode 100644 index 0000000000..405ad030d3 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Patch/PatchInformation.cs @@ -0,0 +1,30 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Web.Hutao.Patch; + +/// +/// 更新信息 +/// +public class PatchInformation +{ + /// + /// 标签名 通常被替换为版本 + /// + public string TagName { get; set; } = default!; + + /// + /// 更新日志 + /// + public string Body { get; set; } = default!; + + /// + /// 浏览器下载链接 + /// + public Uri BrowserDownloadUrl { get; set; } = default!; + + /// + /// 缓存时间 + /// + public DateTimeOffset CacheTime { get; set; } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/PatchClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/PatchClient.cs new file mode 100644 index 0000000000..40f0362258 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/PatchClient.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.Extension; +using Snap.Hutao.Model.Binding.User; +using Snap.Hutao.Web.Hoyolab; +using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord; +using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar; +using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss; +using Snap.Hutao.Web.Hutao.Model; +using Snap.Hutao.Web.Hutao.Model.Post; +using Snap.Hutao.Web.Response; +using System.Net.Http; +using System.Net.Http.Json; + +namespace Snap.Hutao.Web.Hutao; + +/// +/// 更新客户端 +/// +[HttpClient(HttpClientConfigration.Default)] +internal class PatchClient +{ + private readonly HttpClient httpClient; + private readonly JsonSerializerOptions options; + private readonly ILogger logger; + + /// + /// 构造一个新的更新客户端 + /// + /// http 客户端 + /// json选项 + /// 日志器 + public PatchClient(HttpClient httpClient, JsonSerializerOptions options, ILogger logger) + { + this.httpClient = httpClient; + this.options = options; + this.logger = logger; + } + + /// + /// 更新信息 + /// + /// + /// + public Task GetPatchInformationAsync(CancellationToken token = default) + { + return httpClient.TryCatchGetFromJsonAsync(ApiEndpoints.PatcherHutaoStable, options, logger, token); + } +} \ No newline at end of file