mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
refactor
This commit is contained in:
@@ -110,7 +110,6 @@ dotnet_diagnostic.SA1642.severity = none
|
||||
|
||||
dotnet_diagnostic.IDE0005.severity = warning
|
||||
dotnet_diagnostic.IDE0060.severity = none
|
||||
dotnet_diagnostic.IDE0290.severity = none
|
||||
|
||||
# SA1208: System using directives should be placed before other using directives
|
||||
dotnet_diagnostic.SA1208.severity = none
|
||||
@@ -321,7 +320,8 @@ dotnet_diagnostic.CA2227.severity = suggestion
|
||||
|
||||
# CA2251: 使用 “string.Equals”
|
||||
dotnet_diagnostic.CA2251.severity = suggestion
|
||||
csharp_style_prefer_primary_constructors = true:suggestion
|
||||
|
||||
csharp_style_prefer_primary_constructors = false:none
|
||||
|
||||
[*.vb]
|
||||
#### 命名样式 ####
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using Snap.Hutao.Core.Diagnostics;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
|
||||
@@ -77,34 +78,36 @@ internal sealed class HttpShardCopyWorker<TStatus> : IDisposable
|
||||
using (HttpResponseMessage response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token).ConfigureAwait(false))
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
Memory<byte> buffer = new byte[bufferSize];
|
||||
using (Stream stream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false))
|
||||
using (IMemoryOwner<byte> memoryOwner = MemoryPool<byte>.Shared.Rent())
|
||||
{
|
||||
int totalBytesRead = 0;
|
||||
int bytesReadAfterPreviousReport = 0;
|
||||
do
|
||||
Memory<byte> buffer = memoryOwner.Memory;
|
||||
using (Stream stream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false))
|
||||
{
|
||||
int bytesRead = await stream.ReadAsync(buffer, token).ConfigureAwait(false);
|
||||
if (bytesRead <= 0)
|
||||
int totalBytesRead = 0;
|
||||
int bytesReadAfterPreviousReport = 0;
|
||||
do
|
||||
{
|
||||
progress.Report(new(bytesReadAfterPreviousReport));
|
||||
bytesReadAfterPreviousReport = 0;
|
||||
break;
|
||||
}
|
||||
int bytesRead = await stream.ReadAsync(buffer, token).ConfigureAwait(false);
|
||||
if (bytesRead <= 0)
|
||||
{
|
||||
progress.Report(new(bytesReadAfterPreviousReport));
|
||||
bytesReadAfterPreviousReport = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
await RandomAccess.WriteAsync(destFileHandle, buffer[..bytesRead], shard.StartOffset + totalBytesRead, token).ConfigureAwait(false);
|
||||
await RandomAccess.WriteAsync(destFileHandle, buffer[..bytesRead], shard.StartOffset + totalBytesRead, token).ConfigureAwait(false);
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
bytesReadAfterPreviousReport += bytesRead;
|
||||
if (stopwatch.GetElapsedTime().TotalMilliseconds > 500)
|
||||
{
|
||||
progress.Report(new(bytesReadAfterPreviousReport));
|
||||
bytesReadAfterPreviousReport = 0;
|
||||
stopwatch = ValueStopwatch.StartNew();
|
||||
totalBytesRead += bytesRead;
|
||||
bytesReadAfterPreviousReport += bytesRead;
|
||||
if (stopwatch.GetElapsedTime().TotalMilliseconds > 500)
|
||||
{
|
||||
progress.Report(new(bytesReadAfterPreviousReport));
|
||||
bytesReadAfterPreviousReport = 0;
|
||||
stopwatch = ValueStopwatch.StartNew();
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Buffer;
|
||||
using Snap.Hutao.Core.Diagnostics;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
|
||||
namespace Snap.Hutao.Core.IO;
|
||||
@@ -51,26 +53,30 @@ internal class StreamCopyWorker<TStatus>
|
||||
|
||||
long totalBytesRead = 0;
|
||||
int bytesRead;
|
||||
Memory<byte> buffer = new byte[bufferSize];
|
||||
|
||||
do
|
||||
using (IMemoryOwner<byte> memoryOwner = MemoryPool<byte>.Shared.Rent(bufferSize))
|
||||
{
|
||||
bytesRead = await source.ReadAsync(buffer).ConfigureAwait(false);
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
progress.Report(statusFactory(totalBytesRead));
|
||||
break;
|
||||
}
|
||||
Memory<byte> buffer = memoryOwner.Memory;
|
||||
|
||||
await destination.WriteAsync(buffer[..bytesRead]).ConfigureAwait(false);
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
if (stopwatch.GetElapsedTime().TotalMilliseconds > 1000)
|
||||
do
|
||||
{
|
||||
progress.Report(statusFactory(totalBytesRead));
|
||||
stopwatch = ValueStopwatch.StartNew();
|
||||
bytesRead = await source.ReadAsync(buffer).ConfigureAwait(false);
|
||||
if (bytesRead is 0)
|
||||
{
|
||||
progress.Report(statusFactory(totalBytesRead));
|
||||
break;
|
||||
}
|
||||
|
||||
await destination.WriteAsync(buffer[..bytesRead]).ConfigureAwait(false);
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
if (stopwatch.GetElapsedTime().TotalMilliseconds > 1000)
|
||||
{
|
||||
progress.Report(statusFactory(totalBytesRead));
|
||||
stopwatch = ValueStopwatch.StartNew();
|
||||
}
|
||||
}
|
||||
while (bytesRead > 0);
|
||||
}
|
||||
while (bytesRead > 0);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,9 @@ internal static class SettingKeys
|
||||
#region Application
|
||||
public const string LaunchTimes = "LaunchTimes";
|
||||
public const string DataFolderPath = "DataFolderPath";
|
||||
public const string Major1Minor7Revision0GuideState = "Major1Minor7Revision0GuideState";
|
||||
public const string Major1Minor10Revision0GuideState = "Major1Minor10Revision0GuideState";
|
||||
public const string StaticResourceImageQuality = "StaticResourceImageQuality";
|
||||
public const string StaticResourceUseTrimmedArchive = "StaticResourceUseTrimmedArchive";
|
||||
public const string HotKeyMouseClickRepeatForever = "HotKeyMouseClickRepeatForever";
|
||||
public const string IsAllocConsoleDebugModeEnabled = "IsAllocConsoleDebugModeEnabled2";
|
||||
#endregion
|
||||
@@ -60,6 +62,10 @@ internal static class SettingKeys
|
||||
#endregion
|
||||
|
||||
#region Obsolete
|
||||
|
||||
[Obsolete("重置新手引导状态")]
|
||||
public const string Major1Minor7Revision0GuideState = "Major1Minor7Revision0GuideState";
|
||||
|
||||
[Obsolete("重置调试控制台开关")]
|
||||
public const string IsAllocConsoleDebugModeEnabledLegacy1 = "IsAllocConsoleDebugModeEnabled";
|
||||
#endregion
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
xmlns:shvg="using:Snap.Hutao.View.Guide"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid x:Name="RootGrid">
|
||||
<Grid x:Name="RootGrid" Background="{ThemeResource SolidBackgroundFillColorBaseBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
|
||||
@@ -347,9 +347,6 @@
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnablePreviewMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\LaunchGameConfigurationFixDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -7,105 +7,107 @@ using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.Caching;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Factory.Progress;
|
||||
using Snap.Hutao.Web.Request.Builder;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using System.Collections.Frozen;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Guide;
|
||||
|
||||
/// <summary>
|
||||
/// 下载信息
|
||||
/// </summary>
|
||||
internal sealed class DownloadSummary : ObservableObject
|
||||
{
|
||||
private static readonly FrozenSet<string?> AllowedMediaTypes = FrozenSet.ToFrozenSet(
|
||||
[
|
||||
"application/octet-stream",
|
||||
"application/zip",
|
||||
]);
|
||||
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IImageCache imageCache;
|
||||
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
|
||||
private readonly HttpClient httpClient;
|
||||
|
||||
private readonly string fileName;
|
||||
private readonly string fileUrl;
|
||||
private readonly Progress<StreamCopyStatus> progress;
|
||||
private readonly IProgress<StreamCopyStatus> progress;
|
||||
|
||||
private string description = SH.ViewModelWelcomeDownloadSummaryDefault;
|
||||
private double progressValue;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的下载信息
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="fileName">压缩文件名称</param>
|
||||
public DownloadSummary(IServiceProvider serviceProvider, string fileName)
|
||||
{
|
||||
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
httpRequestMessageBuilderFactory = serviceProvider.GetRequiredService<IHttpRequestMessageBuilderFactory>();
|
||||
httpClient = serviceProvider.GetRequiredService<HttpClient>();
|
||||
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(serviceProvider.GetRequiredService<RuntimeOptions>().UserAgent);
|
||||
imageCache = serviceProvider.GetRequiredService<IImageCache>();
|
||||
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(runtimeOptions.UserAgent);
|
||||
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
||||
DisplayName = fileName;
|
||||
this.fileName = fileName;
|
||||
fileUrl = Web.HutaoEndpoints.StaticZip(fileName);
|
||||
|
||||
progress = new(UpdateProgressStatus);
|
||||
progress = serviceProvider.GetRequiredService<IProgressFactory>().CreateForMainThread<StreamCopyStatus>(UpdateProgressStatus);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get; init; }
|
||||
public string DisplayName { get => fileName; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get => description; private set => SetProperty(ref description, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 进度值,最大1
|
||||
/// </summary>
|
||||
public double ProgressValue { get => progressValue; set => SetProperty(ref progressValue, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 异步下载并解压
|
||||
/// </summary>
|
||||
/// <returns>任务</returns>
|
||||
public async ValueTask<bool> DownloadAndExtractAsync()
|
||||
{
|
||||
ILogger<DownloadSummary> logger = serviceProvider.GetRequiredService<ILogger<DownloadSummary>>();
|
||||
try
|
||||
{
|
||||
HttpResponseMessage response = await httpClient.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
|
||||
HttpRequestMessage message = httpRequestMessageBuilderFactory
|
||||
.Create()
|
||||
.SetRequestUri(fileUrl)
|
||||
.SetStaticResourceControlHeaders()
|
||||
.Get()
|
||||
.HttpRequestMessage;
|
||||
|
||||
if (response.Content.Headers.ContentType?.MediaType is not ("application/octet-stream" or "application/zip"))
|
||||
using (message)
|
||||
{
|
||||
logger.LogWarning("Download Static Zip failed, Content-Type is {Type}", response.Content.Headers.ContentType);
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Description = SH.ViewModelWelcomeDownloadSummaryContentTypeNotMatch;
|
||||
return false;
|
||||
}
|
||||
|
||||
long contentLength = response.Content.Headers.ContentLength ?? 0;
|
||||
logger.LogInformation("Begin download, length: {length}", contentLength);
|
||||
using (Stream content = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
{
|
||||
using (TempFileStream temp = new(FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
using (HttpResponseMessage response = await httpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
|
||||
{
|
||||
await new StreamCopyWorker(content, temp, contentLength).CopyAsync(progress).ConfigureAwait(false);
|
||||
ExtractFiles(temp);
|
||||
if (!AllowedMediaTypes.Contains(response.Content.Headers.ContentType?.MediaType))
|
||||
{
|
||||
logger.LogWarning("Download Static Zip failed, Content-Type is {Type}", response.Content.Headers.ContentType);
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Description = SH.ViewModelWelcomeDownloadSummaryContentTypeNotMatch;
|
||||
return false;
|
||||
}
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
ProgressValue = 1;
|
||||
Description = SH.ViewModelWelcomeDownloadSummaryComplete;
|
||||
return true;
|
||||
long contentLength = response.Content.Headers.ContentLength ?? 0;
|
||||
logger.LogInformation("Begin download, size: {length}", Converters.ToFileSizeString(contentLength));
|
||||
using (Stream content = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
{
|
||||
using (TempFileStream temp = new(FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
{
|
||||
await new StreamCopyWorker(content, temp, contentLength).CopyAsync(progress).ConfigureAwait(false);
|
||||
ExtractFiles(temp);
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
ProgressValue = 1;
|
||||
Description = SH.ViewModelWelcomeDownloadSummaryComplete;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Download Static Zip failed");
|
||||
logger.LogError(ex, "Download static zip failed");
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Description = ex is HttpRequestException httpRequestException
|
||||
? $"{SH.ViewModelWelcomeDownloadSummaryException} - [HTTP '{httpRequestException.StatusCode:D}'] [Error '{httpRequestException.HttpRequestError}']"
|
||||
Description = ex is HttpRequestException httpRequestEx
|
||||
? $"{SH.ViewModelWelcomeDownloadSummaryException} - [HTTP '{httpRequestEx.StatusCode:D}'] [Error '{httpRequestEx.HttpRequestError}']"
|
||||
: ex.Message;
|
||||
return false;
|
||||
}
|
||||
@@ -114,7 +116,7 @@ internal sealed class DownloadSummary : ObservableObject
|
||||
private void UpdateProgressStatus(StreamCopyStatus status)
|
||||
{
|
||||
Description = $"{Converters.ToFileSizeString(status.BytesCopied)}/{Converters.ToFileSizeString(status.TotalBytes)}";
|
||||
ProgressValue = status.TotalBytes == 0 ? 0 : (double)status.BytesCopied / status.TotalBytes;
|
||||
ProgressValue = status.TotalBytes is 0 ? 0 : (double)status.BytesCopied / status.TotalBytes;
|
||||
}
|
||||
|
||||
private void ExtractFiles(Stream stream)
|
||||
|
||||
@@ -24,7 +24,17 @@ internal enum GuideState : uint
|
||||
Environment,
|
||||
|
||||
/// <summary>
|
||||
/// 开始下载资源
|
||||
/// 正在查看常用设置
|
||||
/// </summary>
|
||||
CommonSetting,
|
||||
|
||||
/// <summary>
|
||||
/// 正在查看图像资源设置
|
||||
/// </summary>
|
||||
StaticResourceSetting,
|
||||
|
||||
/// <summary>
|
||||
/// 开始下载图像资源
|
||||
/// </summary>
|
||||
StaticResourceBegin,
|
||||
|
||||
|
||||
@@ -36,8 +36,7 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
|
||||
{
|
||||
get
|
||||
{
|
||||
uint value = LocalSetting.Get(SettingKeys.Major1Minor7Revision0GuideState, 0U);
|
||||
GuideState state = (GuideState)value;
|
||||
GuideState state = UnsafeLocalSetting.Get(SettingKeys.Major1Minor10Revision0GuideState, GuideState.Language);
|
||||
|
||||
if (state is GuideState.Document)
|
||||
{
|
||||
@@ -61,12 +60,12 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
|
||||
(NextOrCompleteButtonText, IsNextOrCompleteButtonEnabled) = (SH.ViewModelGuideActionNext, true);
|
||||
}
|
||||
|
||||
return value;
|
||||
return (uint)state;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
LocalSetting.Set(SettingKeys.Major1Minor7Revision0GuideState, value);
|
||||
LocalSetting.Set(SettingKeys.Major1Minor10Revision0GuideState, value);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
@@ -93,13 +92,14 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
#region Agreement
|
||||
public bool IsTermOfServiceAgreed
|
||||
{
|
||||
get => isTermOfServiceAgreed; set
|
||||
{
|
||||
if (SetProperty(ref isTermOfServiceAgreed, value))
|
||||
{
|
||||
OnAgreeSateChanged();
|
||||
OnAgreementStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
|
||||
{
|
||||
if (SetProperty(ref isPrivacyPolicyAgreed, value))
|
||||
{
|
||||
OnAgreeSateChanged();
|
||||
OnAgreementStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
|
||||
{
|
||||
if (SetProperty(ref isIssueReportAgreed, value))
|
||||
{
|
||||
OnAgreeSateChanged();
|
||||
OnAgreementStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,14 +132,12 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
|
||||
{
|
||||
if (SetProperty(ref isOpenSourceLicenseAgreed, value))
|
||||
{
|
||||
OnAgreeSateChanged();
|
||||
OnAgreementStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 下载信息
|
||||
/// </summary>
|
||||
public ObservableCollection<DownloadSummary>? DownloadSummaries
|
||||
{
|
||||
get => downloadSummaries;
|
||||
@@ -152,7 +150,7 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
|
||||
++State;
|
||||
}
|
||||
|
||||
private void OnAgreeSateChanged()
|
||||
private void OnAgreementStateChanged()
|
||||
{
|
||||
IsNextOrCompleteButtonEnabled = IsTermOfServiceAgreed && IsPrivacyPolicyAgreed && IsIssueReportAgreed && IsOpenSourceLicenseAgreed;
|
||||
}
|
||||
@@ -173,7 +171,7 @@ internal sealed partial class GuideViewModel : Abstraction.ViewModel
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
StaticResource.FulfillAll();
|
||||
UnsafeLocalSetting.Set(SettingKeys.Major1Minor7Revision0GuideState, GuideState.Completed);
|
||||
UnsafeLocalSetting.Set(SettingKeys.Major1Minor10Revision0GuideState, GuideState.Completed);
|
||||
AppInstance.Restart(string.Empty);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ internal static class StaticResource
|
||||
|
||||
private static readonly ApplicationDataCompositeValue DefaultResourceVersionMap = new()
|
||||
{
|
||||
// DO NOT MIDIFY THIS MAP
|
||||
// DO NOT MODIFY THIS MAP
|
||||
{ "AchievementIcon", 0 },
|
||||
{ "AvatarCard", 0 },
|
||||
{ "AvatarIcon", 0 },
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Web.Request.Builder;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Guide;
|
||||
|
||||
internal static class StaticResourceHttpHeaderBuilderExtension
|
||||
{
|
||||
public static TBuilder SetStaticResourceControlHeaders<TBuilder>(this TBuilder builder)
|
||||
where TBuilder : IHttpHeadersBuilder<HttpHeaders>
|
||||
{
|
||||
return builder
|
||||
.SetHeader("x-quality", $"{UnsafeLocalSetting.Get(SettingKeys.StaticResourceImageQuality, StaticResourceQuality.Raw)}")
|
||||
.SetHeader("x-minimum", $"{LocalSetting.Get(SettingKeys.StaticResourceUseTrimmedArchive, false)}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Guide;
|
||||
|
||||
internal enum StaticResourceQuality
|
||||
{
|
||||
Raw,
|
||||
High,
|
||||
}
|
||||
@@ -35,8 +35,7 @@ internal static class HttpContentBuilderExtension
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
public static T SetFormUrlEncodedContent<T>(
|
||||
this T builder, IEnumerable<KeyValuePair<string, string>> content)
|
||||
public static T SetFormUrlEncodedContent<T>(this T builder, IEnumerable<KeyValuePair<string, string>> content)
|
||||
where T : IHttpContentBuilder
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(builder);
|
||||
|
||||
@@ -41,12 +41,6 @@ internal static partial class HttpHeadersBuilderExtension
|
||||
return builder.ConfigureHeaders<TBuilder, THeaders>(headers => headers.Add(name, value));
|
||||
}
|
||||
|
||||
public static T SetReferer<T>(this T builder, string referer)
|
||||
where T : IHttpHeadersBuilder<HttpHeaders>
|
||||
{
|
||||
return builder.SetHeader("Referer", referer);
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
public static T SetHeader<T>(this T builder, string name)
|
||||
where T : IHttpHeadersBuilder<HttpHeaders>
|
||||
@@ -80,6 +74,12 @@ internal static partial class HttpHeadersBuilderExtension
|
||||
.AddHeader<TBuilder, THeaders>(name, value);
|
||||
}
|
||||
|
||||
public static T SetReferer<T>(this T builder, string referer)
|
||||
where T : IHttpHeadersBuilder<HttpHeaders>
|
||||
{
|
||||
return builder.SetHeader("Referer", referer);
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
public static T RemoveHeader<T>(this T builder, params string?[]? names)
|
||||
where T : IHttpHeadersBuilder<HttpHeaders>
|
||||
|
||||
@@ -12,7 +12,7 @@ internal static class HttpHeadersExtension
|
||||
ArgumentNullException.ThrowIfNull(name);
|
||||
|
||||
// We have to work around the .NET API a little bit. See the comment below for details.
|
||||
values ??= Enumerable.Empty<string?>();
|
||||
values ??= [];
|
||||
values = values.Where(v => v is not null);
|
||||
|
||||
if (values.Any())
|
||||
|
||||
Reference in New Issue
Block a user