mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
7 Commits
feat/versi
...
revert/qr_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a845dff6ee | ||
|
|
ee99d0b665 | ||
|
|
72b62aa9c6 | ||
|
|
6b031e1866 | ||
|
|
59c03c7f3b | ||
|
|
c03a96b44f | ||
|
|
d5a97903d3 |
@@ -5,6 +5,9 @@ using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
|||||||
using Snap.Hutao.Core.IO;
|
using Snap.Hutao.Core.IO;
|
||||||
using Snap.Hutao.Core.IO.Hashing;
|
using Snap.Hutao.Core.IO.Hashing;
|
||||||
using Snap.Hutao.Core.Logging;
|
using Snap.Hutao.Core.Logging;
|
||||||
|
using Snap.Hutao.ViewModel.Guide;
|
||||||
|
using Snap.Hutao.Web.Request.Builder;
|
||||||
|
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Frozen;
|
using System.Collections.Frozen;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -36,6 +39,7 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
|
|||||||
private readonly ConcurrentDictionary<string, Task> concurrentTasks = new();
|
private readonly ConcurrentDictionary<string, Task> concurrentTasks = new();
|
||||||
|
|
||||||
private readonly IHttpClientFactory httpClientFactory;
|
private readonly IHttpClientFactory httpClientFactory;
|
||||||
|
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
private readonly ILogger<ImageCache> logger;
|
private readonly ILogger<ImageCache> logger;
|
||||||
|
|
||||||
@@ -169,16 +173,26 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
|
|||||||
HttpClient httpClient = httpClientFactory.CreateClient(nameof(ImageCache));
|
HttpClient httpClient = httpClientFactory.CreateClient(nameof(ImageCache));
|
||||||
while (retryCount < 3)
|
while (retryCount < 3)
|
||||||
{
|
{
|
||||||
using (HttpResponseMessage message = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
|
HttpRequestMessageBuilder requestMessageBuilder = httpRequestMessageBuilderFactory
|
||||||
|
.Create()
|
||||||
|
.SetRequestUri(uri)
|
||||||
|
|
||||||
|
// These headers are only available for our own api
|
||||||
|
.SetStaticResourceControlHeadersIf(uri.Host.Contains("api.snapgenshin.com", StringComparison.OrdinalIgnoreCase))
|
||||||
|
.Get();
|
||||||
|
|
||||||
|
using (HttpRequestMessage requestMessage = requestMessageBuilder.HttpRequestMessage)
|
||||||
{
|
{
|
||||||
if (message.RequestMessage is { RequestUri: { } target } && target != uri)
|
using (HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (responseMessage.RequestMessage is { RequestUri: { } target } && target != uri)
|
||||||
{
|
{
|
||||||
logger.LogDebug("The Request '{Source}' has been redirected to '{Target}'", uri, target);
|
logger.LogDebug("The Request '{Source}' has been redirected to '{Target}'", uri, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.IsSuccessStatusCode)
|
if (responseMessage.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
using (Stream httpStream = await message.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
using (Stream httpStream = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
using (FileStream fileStream = File.Create(baseFile))
|
using (FileStream fileStream = File.Create(baseFile))
|
||||||
{
|
{
|
||||||
@@ -188,12 +202,12 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (message.StatusCode)
|
switch (responseMessage.StatusCode)
|
||||||
{
|
{
|
||||||
case HttpStatusCode.TooManyRequests:
|
case HttpStatusCode.TooManyRequests:
|
||||||
{
|
{
|
||||||
retryCount++;
|
retryCount++;
|
||||||
TimeSpan delay = message.Headers.RetryAfter?.Delta ?? retryCountToDelay[retryCount];
|
TimeSpan delay = responseMessage.Headers.RetryAfter?.Delta ?? retryCountToDelay[retryCount];
|
||||||
logger.LogInformation("Retry download '{Uri}' after {Delay}.", uri, delay);
|
logger.LogInformation("Retry download '{Uri}' after {Delay}.", uri, delay);
|
||||||
await Task.Delay(delay).ConfigureAwait(false);
|
await Task.Delay(delay).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
@@ -205,4 +219,5 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ internal static class SettingKeys
|
|||||||
public const string DataFolderPath = "DataFolderPath";
|
public const string DataFolderPath = "DataFolderPath";
|
||||||
public const string Major1Minor10Revision0GuideState = "Major1Minor10Revision0GuideState1";
|
public const string Major1Minor10Revision0GuideState = "Major1Minor10Revision0GuideState1";
|
||||||
public const string StaticResourceImageQuality = "StaticResourceImageQuality";
|
public const string StaticResourceImageQuality = "StaticResourceImageQuality";
|
||||||
public const string StaticResourceUseTrimmedArchive = "StaticResourceUseTrimmedArchive";
|
public const string StaticResourceImageArchive = "StaticResourceImageArchive";
|
||||||
public const string HotKeyMouseClickRepeatForever = "HotKeyMouseClickRepeatForever";
|
public const string HotKeyMouseClickRepeatForever = "HotKeyMouseClickRepeatForever";
|
||||||
public const string IsAllocConsoleDebugModeEnabled = "IsAllocConsoleDebugModeEnabled2";
|
public const string IsAllocConsoleDebugModeEnabled = "IsAllocConsoleDebugModeEnabled2";
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ namespace Snap.Hutao;
|
|||||||
internal sealed partial class GuideWindow : Window, IWindowOptionsSource, IMinMaxInfoHandler
|
internal sealed partial class GuideWindow : Window, IWindowOptionsSource, IMinMaxInfoHandler
|
||||||
{
|
{
|
||||||
private const int MinWidth = 1000;
|
private const int MinWidth = 1000;
|
||||||
private const int MinHeight = 600;
|
private const int MinHeight = 650;
|
||||||
|
|
||||||
private const int MaxWidth = 1200;
|
private const int MaxWidth = 1200;
|
||||||
private const int MaxHeight = 750;
|
private const int MaxHeight = 800;
|
||||||
|
|
||||||
private readonly WindowOptions windowOptions;
|
private readonly WindowOptions windowOptions;
|
||||||
|
|
||||||
|
|||||||
@@ -1382,6 +1382,9 @@
|
|||||||
<data name="ViewGachaLogHeader" xml:space="preserve">
|
<data name="ViewGachaLogHeader" xml:space="preserve">
|
||||||
<value>祈愿记录</value>
|
<value>祈愿记录</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewGuideStaticResourceDownloadSize" xml:space="preserve">
|
||||||
|
<value>预计下载大小:{0}</value>
|
||||||
|
</data>
|
||||||
<data name="ViewGuideStepAgreementIHaveReadText" xml:space="preserve">
|
<data name="ViewGuideStepAgreementIHaveReadText" xml:space="preserve">
|
||||||
<value>我已阅读并同意</value>
|
<value>我已阅读并同意</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1440,10 +1443,10 @@
|
|||||||
<value>图片资源包体</value>
|
<value>图片资源包体</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewGuideStepStaticResourceSettingMinimumOff" xml:space="preserve">
|
<data name="ViewGuideStepStaticResourceSettingMinimumOff" xml:space="preserve">
|
||||||
<value>全部资源(节省 0% 磁盘空间占用)</value>
|
<value>完整包体</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewGuideStepStaticResourceSettingMinimumOn" xml:space="preserve">
|
<data name="ViewGuideStepStaticResourceSettingMinimumOn" xml:space="preserve">
|
||||||
<value>部分资源(节省 13.5% 磁盘空间占用)</value>
|
<value>精简包体</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewGuideStepStaticResourceSettingQualityHeader" xml:space="preserve">
|
<data name="ViewGuideStepStaticResourceSettingQualityHeader" xml:space="preserve">
|
||||||
<value>图片资源质量</value>
|
<value>图片资源质量</value>
|
||||||
@@ -1638,10 +1641,10 @@
|
|||||||
<value>下载资源文件中,请稍候</value>
|
<value>下载资源文件中,请稍候</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewModelGuideStaticResourceQualityHigh" xml:space="preserve">
|
<data name="ViewModelGuideStaticResourceQualityHigh" xml:space="preserve">
|
||||||
<value>高质量(节省 72.8% 磁盘空间占用)</value>
|
<value>高质量</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewModelGuideStaticResourceQualityRaw" xml:space="preserve">
|
<data name="ViewModelGuideStaticResourceQualityRaw" xml:space="preserve">
|
||||||
<value>原图(节省 0% 磁盘空间占用)</value>
|
<value>原图</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewModelHutaoPassportEmailNotValidHint" xml:space="preserve">
|
<data name="ViewModelHutaoPassportEmailNotValidHint" xml:space="preserve">
|
||||||
<value>请输入正确的邮箱</value>
|
<value>请输入正确的邮箱</value>
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
||||||
<WindowsAppSdkUndockedRegFreeWinRTInitialize>false</WindowsAppSdkUndockedRegFreeWinRTInitialize>
|
<WindowsAppSdkUndockedRegFreeWinRTInitialize>false</WindowsAppSdkUndockedRegFreeWinRTInitialize>
|
||||||
|
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||||
|
<GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -303,8 +305,8 @@
|
|||||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.TokenizingTextBox" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.TokenizingTextBox" Version="8.0.240109" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.240109" />
|
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.240109" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.3">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.4">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -319,7 +321,7 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
|
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.3233" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.3233" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240311000" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240404000" />
|
||||||
<PackageReference Include="QRCoder" Version="1.4.3" />
|
<PackageReference Include="QRCoder" Version="1.4.3" />
|
||||||
<PackageReference Include="Snap.Discord.GameSDK" Version="1.6.0" />
|
<PackageReference Include="Snap.Discord.GameSDK" Version="1.6.0" />
|
||||||
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.16.0">
|
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.16.0">
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||||
xmlns:shc="using:Snap.Hutao.Control"
|
|
||||||
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
|
||||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
xmlns:shvg="using:Snap.Hutao.ViewModel.Guide"
|
xmlns:shvg="using:Snap.Hutao.ViewModel.Guide"
|
||||||
@@ -224,10 +223,14 @@
|
|||||||
ItemsSource="{Binding StaticResourceOptions.ImageQualities}"
|
ItemsSource="{Binding StaticResourceOptions.ImageQualities}"
|
||||||
SelectedItem="{Binding StaticResourceOptions.ImageQuality, Mode=TwoWay}"/>
|
SelectedItem="{Binding StaticResourceOptions.ImageQuality, Mode=TwoWay}"/>
|
||||||
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumHeader}"/>
|
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumHeader}"/>
|
||||||
<ToggleSwitch
|
<ListView
|
||||||
IsOn="{Binding StaticResourceOptions.UseTrimmedArchive, Mode=TwoWay}"
|
MinWidth="320"
|
||||||
OffContent="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumOff}"
|
Margin="0,8,0,32"
|
||||||
OnContent="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumOn}"/>
|
DisplayMemberPath="Name"
|
||||||
|
ItemsSource="{Binding StaticResourceOptions.ImageArchives}"
|
||||||
|
SelectedItem="{Binding StaticResourceOptions.ImageArchive, Mode=TwoWay}"/>
|
||||||
|
|
||||||
|
<TextBlock Margin="0,16,0,0" Text="{Binding StaticResourceOptions.SizeInformationText, Mode=OneWay}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -266,12 +269,20 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
IsHitTestVisible="False"
|
IsHitTestVisible="False"
|
||||||
SelectedIndex="{Binding State, Mode=TwoWay}">
|
SelectedIndex="{Binding State, Mode=TwoWay}">
|
||||||
|
<!--
|
||||||
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepLanguage}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepLanguage}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepDocument}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepDocument}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepEnvironment}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepEnvironment}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepCommonSetting}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepCommonSetting}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepStaticResourceSetting}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepStaticResourceSetting}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepStaticResource}" Icon="{shcm:FontIcon Glyph=}"/>
|
<cwc:SegmentedItem Content="{shcm:ResourceString Name=ViewGuideStepStaticResource}" Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
|
-->
|
||||||
|
<cwc:SegmentedItem Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
|
<cwc:SegmentedItem Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
|
<cwc:SegmentedItem Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
|
<cwc:SegmentedItem Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
|
<cwc:SegmentedItem Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
|
<cwc:SegmentedItem Icon="{shcm:FontIcon Glyph=}"/>
|
||||||
</cwc:Segmented>
|
</cwc:Segmented>
|
||||||
<Button
|
<Button
|
||||||
Command="{Binding NextOrCompleteCommand}"
|
Command="{Binding NextOrCompleteCommand}"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Snap.Hutao.Control.Extension;
|
||||||
using Snap.Hutao.ViewModel.Guide;
|
using Snap.Hutao.ViewModel.Guide;
|
||||||
|
|
||||||
namespace Snap.Hutao.View.Guide;
|
namespace Snap.Hutao.View.Guide;
|
||||||
@@ -14,6 +15,6 @@ internal sealed partial class GuideView : UserControl
|
|||||||
public GuideView()
|
public GuideView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContext = Ioc.Default.GetRequiredService<GuideViewModel>();
|
DataContext = this.ServiceProvider().GetRequiredService<GuideViewModel>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ using Snap.Hutao.Core.Setting;
|
|||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
using Snap.Hutao.Service;
|
using Snap.Hutao.Service;
|
||||||
using Snap.Hutao.Web.Hoyolab;
|
using Snap.Hutao.Web.Hoyolab;
|
||||||
|
using Snap.Hutao.Web.Hutao;
|
||||||
|
using Snap.Hutao.Web.Hutao.Response;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
@@ -164,6 +166,19 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
|
|||||||
set => SetProperty(ref downloadSummaries, value);
|
set => SetProperty(ref downloadSummaries, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async ValueTask<bool> InitializeUIAsync()
|
||||||
|
{
|
||||||
|
HutaoInfrastructureClient hutaoInfrastructureClient = serviceProvider.GetRequiredService<HutaoInfrastructureClient>();
|
||||||
|
HutaoResponse<StaticResourceSizeInformation> response = await hutaoInfrastructureClient.GetStaticSizeAsync().ConfigureAwait(false);
|
||||||
|
if (response.IsOk())
|
||||||
|
{
|
||||||
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
|
StaticResourceOptions.SizeInformation = response.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
[Command("NextOrCompleteCommand")]
|
[Command("NextOrCompleteCommand")]
|
||||||
private void NextOrComplete()
|
private void NextOrComplete()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,31 +46,31 @@ internal static class StaticResource
|
|||||||
|
|
||||||
private static readonly ApplicationDataCompositeValue LatestResourceVersionMap = new()
|
private static readonly ApplicationDataCompositeValue LatestResourceVersionMap = new()
|
||||||
{
|
{
|
||||||
{ "AchievementIcon", 1 },
|
{ "AchievementIcon", 2 },
|
||||||
{ "AvatarCard", 1 },
|
{ "AvatarCard", 2 },
|
||||||
{ "AvatarIcon", 4 },
|
{ "AvatarIcon", 5 },
|
||||||
{ "Bg", 2 },
|
{ "Bg", 3 },
|
||||||
{ "ChapterIcon", 2 },
|
{ "ChapterIcon", 3 },
|
||||||
{ "CodexMonster", 0 },
|
{ "CodexMonster", 0 },
|
||||||
{ "Costume", 1 },
|
{ "Costume", 2 },
|
||||||
{ "EmotionIcon", 2 },
|
{ "EmotionIcon", 3 },
|
||||||
{ "EquipIcon", 3 },
|
{ "EquipIcon", 4 },
|
||||||
{ "GachaAvatarIcon", 3 },
|
{ "GachaAvatarIcon", 4 },
|
||||||
{ "GachaAvatarImg", 3 },
|
{ "GachaAvatarImg", 4 },
|
||||||
{ "GachaEquipIcon", 3 },
|
{ "GachaEquipIcon", 4 },
|
||||||
{ "GcgCharAvatarIcon", 0 },
|
{ "GcgCharAvatarIcon", 0 },
|
||||||
{ "IconElement", 2 },
|
{ "IconElement", 3 },
|
||||||
{ "ItemIcon", 3 },
|
{ "ItemIcon", 4 },
|
||||||
{ "LoadingPic", 1 },
|
{ "LoadingPic", 2 },
|
||||||
{ "MonsterIcon", 2 },
|
{ "MonsterIcon", 3 },
|
||||||
{ "MonsterSmallIcon", 1 },
|
{ "MonsterSmallIcon", 2 },
|
||||||
{ "NameCardIcon", 2 },
|
{ "NameCardIcon", 3 },
|
||||||
{ "NameCardPic", 3 },
|
{ "NameCardPic", 4 },
|
||||||
{ "NameCardPicAlpha", 0 },
|
{ "NameCardPicAlpha", 0 },
|
||||||
{ "Property", 1 },
|
{ "Property", 2 },
|
||||||
{ "RelicIcon", 3 },
|
{ "RelicIcon", 4 },
|
||||||
{ "Skill", 3 },
|
{ "Skill", 4 },
|
||||||
{ "Talent", 3 },
|
{ "Talent", 4 },
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void FulfillAll()
|
public static void FulfillAll()
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.ViewModel.Guide;
|
||||||
|
|
||||||
|
[Localization]
|
||||||
|
internal enum StaticResourceArchive
|
||||||
|
{
|
||||||
|
[LocalizationKey(nameof(SH.ViewGuideStepStaticResourceSettingMinimumOff))]
|
||||||
|
Full,
|
||||||
|
|
||||||
|
[LocalizationKey(nameof(SH.ViewGuideStepStaticResourceSettingMinimumOn))]
|
||||||
|
Minimum,
|
||||||
|
}
|
||||||
@@ -15,6 +15,12 @@ internal static class StaticResourceHttpHeaderBuilderExtension
|
|||||||
{
|
{
|
||||||
return builder
|
return builder
|
||||||
.SetHeader("x-quality", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageQuality, StaticResourceQuality.Raw)}")
|
.SetHeader("x-quality", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageQuality, StaticResourceQuality.Raw)}")
|
||||||
.SetHeader("x-minimum", $"{LocalSetting.Get(SettingKeys.StaticResourceUseTrimmedArchive, false)}");
|
.SetHeader("x-archive", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageArchive, StaticResourceArchive.Full)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TBuilder SetStaticResourceControlHeadersIf<TBuilder>(this TBuilder builder, bool condition)
|
||||||
|
where TBuilder : IHttpHeadersBuilder<HttpHeaders>
|
||||||
|
{
|
||||||
|
return condition ? builder.SetStaticResourceControlHeaders() : builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,41 +1,82 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using CommunityToolkit.Common;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Snap.Hutao.Core.Setting;
|
using Snap.Hutao.Core.Setting;
|
||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
|
using Snap.Hutao.Web.Hutao;
|
||||||
|
|
||||||
namespace Snap.Hutao.ViewModel.Guide;
|
namespace Snap.Hutao.ViewModel.Guide;
|
||||||
|
|
||||||
[Injection(InjectAs.Singleton)]
|
[Injection(InjectAs.Singleton)]
|
||||||
internal sealed class StaticResourceOptions
|
internal sealed class StaticResourceOptions : ObservableObject
|
||||||
{
|
{
|
||||||
private readonly List<NameValue<StaticResourceQuality>> imageQualities = CollectionsNameValue.FromEnum<StaticResourceQuality>(q => q.GetLocalizedDescription());
|
private readonly List<NameValue<StaticResourceQuality>> imageQualities = CollectionsNameValue.FromEnum<StaticResourceQuality>(q => q.GetLocalizedDescription());
|
||||||
|
private readonly List<NameValue<StaticResourceArchive>> imageArchives = CollectionsNameValue.FromEnum<StaticResourceArchive>(a => a.GetLocalizedDescription());
|
||||||
|
|
||||||
private NameValue<StaticResourceQuality>? imageQuality;
|
private NameValue<StaticResourceQuality>? imageQuality;
|
||||||
|
private NameValue<StaticResourceArchive>? imageArchive;
|
||||||
|
private string? sizeInformationText;
|
||||||
|
|
||||||
public StaticResourceOptions()
|
private StaticResourceSizeInformation? sizeInformation;
|
||||||
{
|
|
||||||
ImageQuality = ImageQualities.First(q => q.Value == UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageQuality, StaticResourceQuality.Raw));
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<NameValue<StaticResourceQuality>> ImageQualities { get => imageQualities; }
|
public List<NameValue<StaticResourceQuality>> ImageQualities { get => imageQualities; }
|
||||||
|
|
||||||
public NameValue<StaticResourceQuality>? ImageQuality
|
public NameValue<StaticResourceQuality>? ImageQuality
|
||||||
{
|
{
|
||||||
get => imageQuality;
|
get => imageQuality ??= ImageQualities.First(q => q.Value == UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageQuality, StaticResourceQuality.Raw));
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value is not null)
|
if (SetProperty(ref imageQuality, value) && value is not null)
|
||||||
{
|
{
|
||||||
imageQuality = value;
|
|
||||||
UnsafeLocalSetting.Set(SettingKeys.StaticResourceImageQuality, value.Value);
|
UnsafeLocalSetting.Set(SettingKeys.StaticResourceImageQuality, value.Value);
|
||||||
|
UpdateSizeInformationText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UseTrimmedArchive
|
public List<NameValue<StaticResourceArchive>> ImageArchives { get => imageArchives; }
|
||||||
|
|
||||||
|
public NameValue<StaticResourceArchive>? ImageArchive
|
||||||
{
|
{
|
||||||
get => LocalSetting.Get(SettingKeys.StaticResourceUseTrimmedArchive, false);
|
get => imageArchive ??= ImageArchives.First(a => a.Value == UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageArchive, StaticResourceArchive.Full));
|
||||||
set => LocalSetting.Set(SettingKeys.StaticResourceUseTrimmedArchive, value);
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref imageArchive, value) && value is not null)
|
||||||
|
{
|
||||||
|
UnsafeLocalSetting.Set(SettingKeys.StaticResourceImageArchive, value.Value);
|
||||||
|
UpdateSizeInformationText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StaticResourceSizeInformation? SizeInformation
|
||||||
|
{
|
||||||
|
get => sizeInformation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
sizeInformation = value;
|
||||||
|
UpdateSizeInformationText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? SizeInformationText { get => sizeInformationText; set => SetProperty(ref sizeInformationText, value); }
|
||||||
|
|
||||||
|
private void UpdateSizeInformationText()
|
||||||
|
{
|
||||||
|
if (SizeInformation is not null)
|
||||||
|
{
|
||||||
|
long result = (ImageQuality?.Value, ImageArchive?.Value) switch
|
||||||
|
{
|
||||||
|
(StaticResourceQuality.Raw, StaticResourceArchive.Full) => SizeInformation.RawFull,
|
||||||
|
(StaticResourceQuality.Raw, StaticResourceArchive.Minimum) => SizeInformation.RawMinimum,
|
||||||
|
(StaticResourceQuality.High, StaticResourceArchive.Full) => SizeInformation.HighFull,
|
||||||
|
(StaticResourceQuality.High, StaticResourceArchive.Minimum) => SizeInformation.HighMinimum,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
SizeInformationText = SH.FormatViewGuideStaticResourceDownloadSize(Converters.ToFileSizeString(result));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,12 +19,10 @@ internal sealed partial class PandaClient
|
|||||||
|
|
||||||
public async ValueTask<Response<UrlWrapper>> QRCodeFetchAsync(CancellationToken token = default)
|
public async ValueTask<Response<UrlWrapper>> QRCodeFetchAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
// Use 12 (zzz) instead of 4 (gi) temporarily to get legacy game token
|
GameLoginRequest options = GameLoginRequest.Create(4, HoyolabOptions.DeviceId40);
|
||||||
GameLoginRequest options = GameLoginRequest.Create(12, HoyolabOptions.DeviceId40);
|
|
||||||
|
|
||||||
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||||
.SetRequestUri(ApiEndpoints.QrCodeFetch)
|
.SetRequestUri(ApiEndpoints.QrCodeFetch)
|
||||||
.SetHeader("x-rpc-device_id", HoyolabOptions.DeviceId40)
|
|
||||||
.PostJson(options);
|
.PostJson(options);
|
||||||
|
|
||||||
Response<UrlWrapper>? resp = await builder
|
Response<UrlWrapper>? resp = await builder
|
||||||
@@ -36,11 +34,10 @@ internal sealed partial class PandaClient
|
|||||||
|
|
||||||
public async ValueTask<Response<GameLoginResult>> QRCodeQueryAsync(string ticket, CancellationToken token = default)
|
public async ValueTask<Response<GameLoginResult>> QRCodeQueryAsync(string ticket, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
GameLoginRequest options = GameLoginRequest.Create(12, HoyolabOptions.DeviceId40, ticket);
|
GameLoginRequest options = GameLoginRequest.Create(4, HoyolabOptions.DeviceId40, ticket);
|
||||||
|
|
||||||
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||||
.SetRequestUri(ApiEndpoints.QrCodeQuery)
|
.SetRequestUri(ApiEndpoints.QrCodeQuery)
|
||||||
.SetHeader("x-rpc-device_id", HoyolabOptions.DeviceId40)
|
|
||||||
.PostJson(options);
|
.PostJson(options);
|
||||||
|
|
||||||
Response<GameLoginResult>? resp = await builder
|
Response<GameLoginResult>? resp = await builder
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ internal sealed partial class PassportClient2
|
|||||||
|
|
||||||
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||||
.SetRequestUri(ApiEndpoints.AccountGetSTokenByGameToken)
|
.SetRequestUri(ApiEndpoints.AccountGetSTokenByGameToken)
|
||||||
.SetHeader("x-rpc-device_id", HoyolabOptions.DeviceId40)
|
|
||||||
.PostJson(data);
|
.PostJson(data);
|
||||||
|
|
||||||
Response<LoginResult>? resp = await builder
|
Response<LoginResult>? resp = await builder
|
||||||
|
|||||||
@@ -17,6 +17,16 @@ internal sealed partial class HutaoInfrastructureClient
|
|||||||
private readonly ILogger<HutaoInfrastructureClient> logger;
|
private readonly ILogger<HutaoInfrastructureClient> logger;
|
||||||
private readonly HttpClient httpClient;
|
private readonly HttpClient httpClient;
|
||||||
|
|
||||||
|
public async ValueTask<HutaoResponse<StaticResourceSizeInformation>> GetStaticSizeAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||||
|
.SetRequestUri(HutaoEndpoints.StaticSize)
|
||||||
|
.Get();
|
||||||
|
|
||||||
|
HutaoResponse<StaticResourceSizeInformation>? resp = await builder.TryCatchSendAsync<HutaoResponse<StaticResourceSizeInformation>>(httpClient, logger, token).ConfigureAwait(false);
|
||||||
|
return Web.Response.Response.DefaultIfNull(resp);
|
||||||
|
}
|
||||||
|
|
||||||
public async ValueTask<HutaoResponse<IPInformation>> GetIPInformationAsync(CancellationToken token = default)
|
public async ValueTask<HutaoResponse<IPInformation>> GetIPInformationAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao;
|
||||||
|
|
||||||
|
internal sealed partial class StaticResourceSizeInformation
|
||||||
|
{
|
||||||
|
[JsonPropertyName("raw_full")]
|
||||||
|
public long RawFull { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("raw_minimum")]
|
||||||
|
public long RawMinimum { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("tiny_full")]
|
||||||
|
public long HighFull { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("tiny_minimum")]
|
||||||
|
public long HighMinimum { get; set; }
|
||||||
|
}
|
||||||
@@ -270,6 +270,8 @@ internal static class HutaoEndpoints
|
|||||||
{
|
{
|
||||||
return $"{ApiSnapGenshinStaticZip}/{fileName}.zip";
|
return $"{ApiSnapGenshinStaticZip}/{fileName}.zip";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public const string StaticSize = $"{ApiSnapGenshin}/static/size";
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Wallpaper
|
#region Wallpaper
|
||||||
|
|||||||
Reference in New Issue
Block a user