mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
refactor static resource
This commit is contained in:
@@ -5,6 +5,9 @@ using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.IO.Hashing;
|
||||
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.Frozen;
|
||||
using System.IO;
|
||||
@@ -36,6 +39,7 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
|
||||
private readonly ConcurrentDictionary<string, Task> concurrentTasks = new();
|
||||
|
||||
private readonly IHttpClientFactory httpClientFactory;
|
||||
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly ILogger<ImageCache> logger;
|
||||
|
||||
@@ -169,38 +173,49 @@ internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOpera
|
||||
HttpClient httpClient = httpClientFactory.CreateClient(nameof(ImageCache));
|
||||
while (retryCount < 3)
|
||||
{
|
||||
using (HttpResponseMessage message = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
|
||||
{
|
||||
if (message.RequestMessage is { RequestUri: { } target } && target != uri)
|
||||
{
|
||||
logger.LogDebug("The Request '{Source}' has been redirected to '{Target}'", uri, target);
|
||||
}
|
||||
HttpRequestMessageBuilder requestMessageBuilder = httpRequestMessageBuilderFactory
|
||||
.Create()
|
||||
.SetRequestUri(uri)
|
||||
|
||||
if (message.IsSuccessStatusCode)
|
||||
// These headers are only available for our own api
|
||||
.SetStaticResourceControlHeadersIf(uri.Host.Contains("api.snapgenshin.com", StringComparison.OrdinalIgnoreCase))
|
||||
.Get();
|
||||
|
||||
using (HttpRequestMessage requestMessage = requestMessageBuilder.HttpRequestMessage)
|
||||
{
|
||||
using (HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
|
||||
{
|
||||
using (Stream httpStream = await message.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
if (responseMessage.RequestMessage is { RequestUri: { } target } && target != uri)
|
||||
{
|
||||
using (FileStream fileStream = File.Create(baseFile))
|
||||
logger.LogDebug("The Request '{Source}' has been redirected to '{Target}'", uri, target);
|
||||
}
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode)
|
||||
{
|
||||
using (Stream httpStream = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
{
|
||||
await httpStream.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
return;
|
||||
using (FileStream fileStream = File.Create(baseFile))
|
||||
{
|
||||
await httpStream.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (message.StatusCode)
|
||||
{
|
||||
case HttpStatusCode.TooManyRequests:
|
||||
{
|
||||
retryCount++;
|
||||
TimeSpan delay = message.Headers.RetryAfter?.Delta ?? retryCountToDelay[retryCount];
|
||||
logger.LogInformation("Retry download '{Uri}' after {Delay}.", uri, delay);
|
||||
await Task.Delay(delay).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
switch (responseMessage.StatusCode)
|
||||
{
|
||||
case HttpStatusCode.TooManyRequests:
|
||||
{
|
||||
retryCount++;
|
||||
TimeSpan delay = responseMessage.Headers.RetryAfter?.Delta ?? retryCountToDelay[retryCount];
|
||||
logger.LogInformation("Retry download '{Uri}' after {Delay}.", uri, delay);
|
||||
await Task.Delay(delay).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ internal static class SettingKeys
|
||||
public const string DataFolderPath = "DataFolderPath";
|
||||
public const string Major1Minor10Revision0GuideState = "Major1Minor10Revision0GuideState1";
|
||||
public const string StaticResourceImageQuality = "StaticResourceImageQuality";
|
||||
public const string StaticResourceUseTrimmedArchive = "StaticResourceUseTrimmedArchive";
|
||||
public const string StaticResourceImageArchive = "StaticResourceImageArchive";
|
||||
public const string HotKeyMouseClickRepeatForever = "HotKeyMouseClickRepeatForever";
|
||||
public const string IsAllocConsoleDebugModeEnabled = "IsAllocConsoleDebugModeEnabled2";
|
||||
#endregion
|
||||
|
||||
@@ -223,11 +223,13 @@
|
||||
ItemsSource="{Binding StaticResourceOptions.ImageQualities}"
|
||||
SelectedItem="{Binding StaticResourceOptions.ImageQuality, Mode=TwoWay}"/>
|
||||
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumHeader}"/>
|
||||
<ToggleSwitch
|
||||
IsOn="{Binding StaticResourceOptions.UseTrimmedArchive, Mode=TwoWay}"
|
||||
OffContent="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumOff}"
|
||||
OnContent="{shcm:ResourceString Name=ViewGuideStepStaticResourceSettingMinimumOn}"/>
|
||||
|
||||
<ListView
|
||||
MinWidth="320"
|
||||
Margin="0,8,0,32"
|
||||
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>
|
||||
|
||||
|
||||
@@ -46,31 +46,31 @@ internal static class StaticResource
|
||||
|
||||
private static readonly ApplicationDataCompositeValue LatestResourceVersionMap = new()
|
||||
{
|
||||
{ "AchievementIcon", 1 },
|
||||
{ "AvatarCard", 1 },
|
||||
{ "AvatarIcon", 4 },
|
||||
{ "Bg", 2 },
|
||||
{ "ChapterIcon", 2 },
|
||||
{ "AchievementIcon", 2 },
|
||||
{ "AvatarCard", 2 },
|
||||
{ "AvatarIcon", 5 },
|
||||
{ "Bg", 3 },
|
||||
{ "ChapterIcon", 3 },
|
||||
{ "CodexMonster", 0 },
|
||||
{ "Costume", 1 },
|
||||
{ "EmotionIcon", 2 },
|
||||
{ "EquipIcon", 3 },
|
||||
{ "GachaAvatarIcon", 3 },
|
||||
{ "GachaAvatarImg", 3 },
|
||||
{ "GachaEquipIcon", 3 },
|
||||
{ "Costume", 2 },
|
||||
{ "EmotionIcon", 3 },
|
||||
{ "EquipIcon", 4 },
|
||||
{ "GachaAvatarIcon", 4 },
|
||||
{ "GachaAvatarImg", 4 },
|
||||
{ "GachaEquipIcon", 4 },
|
||||
{ "GcgCharAvatarIcon", 0 },
|
||||
{ "IconElement", 2 },
|
||||
{ "ItemIcon", 3 },
|
||||
{ "LoadingPic", 1 },
|
||||
{ "MonsterIcon", 2 },
|
||||
{ "MonsterSmallIcon", 1 },
|
||||
{ "NameCardIcon", 2 },
|
||||
{ "NameCardPic", 3 },
|
||||
{ "IconElement", 3 },
|
||||
{ "ItemIcon", 4 },
|
||||
{ "LoadingPic", 2 },
|
||||
{ "MonsterIcon", 3 },
|
||||
{ "MonsterSmallIcon", 2 },
|
||||
{ "NameCardIcon", 3 },
|
||||
{ "NameCardPic", 4 },
|
||||
{ "NameCardPicAlpha", 0 },
|
||||
{ "Property", 1 },
|
||||
{ "RelicIcon", 3 },
|
||||
{ "Skill", 3 },
|
||||
{ "Talent", 3 },
|
||||
{ "Property", 2 },
|
||||
{ "RelicIcon", 4 },
|
||||
{ "Skill", 4 },
|
||||
{ "Talent", 4 },
|
||||
};
|
||||
|
||||
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
|
||||
.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;
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,12 @@ namespace Snap.Hutao.ViewModel.Guide;
|
||||
internal sealed class StaticResourceOptions : ObservableObject
|
||||
{
|
||||
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<StaticResourceArchive>? imageArchive;
|
||||
private string? sizeInformationText;
|
||||
|
||||
private StaticResourceSizeInformation? sizeInformation;
|
||||
|
||||
public List<NameValue<StaticResourceQuality>> ImageQualities { get => imageQualities; }
|
||||
@@ -33,13 +36,18 @@ internal sealed class StaticResourceOptions : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
UpdateSizeInformationText();
|
||||
if (SetProperty(ref imageArchive, value) && value is not null)
|
||||
{
|
||||
UnsafeLocalSetting.Set(SettingKeys.StaticResourceImageArchive, value.Value);
|
||||
UpdateSizeInformationText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,12 +67,12 @@ internal sealed class StaticResourceOptions : ObservableObject
|
||||
{
|
||||
if (SizeInformation is not null)
|
||||
{
|
||||
long result = (ImageQuality?.Value, minimum: UseTrimmedArchive) switch
|
||||
long result = (ImageQuality?.Value, ImageArchive?.Value) switch
|
||||
{
|
||||
(StaticResourceQuality.Raw, minimum: false) => SizeInformation.RawFull,
|
||||
(StaticResourceQuality.Raw, minimum: true) => SizeInformation.RawMinimum,
|
||||
(StaticResourceQuality.High, minimum: false) => SizeInformation.HighFull,
|
||||
(StaticResourceQuality.High, minimum: true) => SizeInformation.HighMinimum,
|
||||
(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,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user