mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
fix #804
This commit is contained in:
@@ -150,7 +150,7 @@ internal sealed class Activation : IActivation
|
||||
// Increase launch times
|
||||
LocalSetting.Set(SettingKeys.LaunchTimes, LocalSetting.Get(SettingKeys.LaunchTimes, 0) + 1);
|
||||
|
||||
if (LocalSetting.Get(SettingKeys.Major1Minor7Revision0GuideState, (uint)GuideState.None) < (uint)GuideState.Completed)
|
||||
if (false && LocalSetting.Get(SettingKeys.Major1Minor7Revision0GuideState, (uint)GuideState.None) < (uint)GuideState.Completed)
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
serviceProvider.GetRequiredService<GuideWindow>();
|
||||
|
||||
@@ -21,4 +21,20 @@ internal static class StringExtension
|
||||
{
|
||||
return new(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除结尾可能存在的字符串
|
||||
/// </summary>
|
||||
/// <param name="source">源</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <returns>新的字符串</returns>
|
||||
public static string TrimEnd(this string source, string value)
|
||||
{
|
||||
while (source.EndsWith(value))
|
||||
{
|
||||
source = source[..^value.Length];
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -1374,6 +1374,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Url 中的语言:{0} 与胡桃的语言:{1} 不匹配,请切换到对应语言重试 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale {
|
||||
get {
|
||||
return ResourceManager.GetString("ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 不支持的 Item Id:{0} 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -2135,4 +2135,7 @@
|
||||
<data name="GuideWindowTitle" xml:space="preserve">
|
||||
<value>欢迎使用胡桃</value>
|
||||
</data>
|
||||
<data name="ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale" xml:space="preserve">
|
||||
<value>Url 中的语言:{0} 与胡桃的语言:{1} 不匹配,请切换到对应语言重试</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using Snap.Hutao.Web.Request.QueryString;
|
||||
|
||||
namespace Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||
|
||||
@@ -14,6 +16,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||
internal sealed partial class GachaLogQueryManualInputProvider : IGachaLogQueryProvider
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly MetadataOptions metadataOptions;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -25,13 +28,26 @@ internal sealed partial class GachaLogQueryManualInputProvider : IGachaLogQueryP
|
||||
// ContentDialog must be created by main thread.
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
GachaLogUrlDialog dialog = serviceProvider.CreateInstance<GachaLogUrlDialog>();
|
||||
(bool isOk, string query) = await dialog.GetInputUrlAsync().ConfigureAwait(false);
|
||||
(bool isOk, string queryString) = await dialog.GetInputUrlAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
if (query.Contains("&auth_appid=webview_gacha"))
|
||||
QueryString query = QueryString.Parse(queryString);
|
||||
string queryLanguageCode = query["lang"];
|
||||
if (query["auth_appid"] == "webview_gacha")
|
||||
{
|
||||
return new(true, new(query));
|
||||
if (metadataOptions.IsCurrentLocale(queryLanguageCode))
|
||||
{
|
||||
return new(true, new(queryString));
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = string.Format(
|
||||
SH.ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale,
|
||||
queryLanguageCode,
|
||||
metadataOptions.LocaleName);
|
||||
return new(false, message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.User;
|
||||
using Snap.Hutao.ViewModel.User;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||
@@ -18,6 +19,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||
internal sealed partial class GachaLogQuerySTokenProvider : IGachaLogQueryProvider
|
||||
{
|
||||
private readonly BindingClient2 bindingClient2;
|
||||
private readonly MetadataOptions metadataOptions;
|
||||
private readonly IUserService userService;
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -38,7 +40,7 @@ internal sealed partial class GachaLogQuerySTokenProvider : IGachaLogQueryProvid
|
||||
|
||||
if (authkeyResponse.IsOk())
|
||||
{
|
||||
return new(true, new(GachaLogQueryOptions.AsQuery(data, authkeyResponse.Data)));
|
||||
return new(true, new(GachaLogQueryOptions.AsQuery(data, authkeyResponse.Data, metadataOptions.LanguageCode)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Service.Game;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Web.Request.QueryString;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -18,6 +21,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||
internal sealed partial class GachaLogQueryWebCacheProvider : IGachaLogQueryProvider
|
||||
{
|
||||
private readonly IGameService gameService;
|
||||
private readonly MetadataOptions metadataOptions;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name { get => nameof(GachaLogQueryWebCacheProvider); }
|
||||
@@ -63,7 +67,20 @@ internal sealed partial class GachaLogQueryWebCacheProvider : IGachaLogQueryProv
|
||||
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
{
|
||||
return new(true, new(result));
|
||||
QueryString query = QueryString.Parse(result.TrimEnd("#/log"));
|
||||
string queryLanguageCode = query["lang"];
|
||||
if (metadataOptions.IsCurrentLocale(queryLanguageCode))
|
||||
{
|
||||
return new(true, new(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = string.Format(
|
||||
SH.ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale,
|
||||
queryLanguageCode,
|
||||
metadataOptions.LocaleName);
|
||||
return new(false, message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Snap.Hutao.Core;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
@@ -15,6 +16,8 @@ namespace Snap.Hutao.Service.Metadata;
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed partial class MetadataOptions : IOptions<MetadataOptions>
|
||||
{
|
||||
|
||||
|
||||
private readonly AppOptions appOptions;
|
||||
private readonly HutaoOptions hutaoOptions;
|
||||
|
||||
@@ -61,12 +64,51 @@ internal sealed partial class MetadataOptions : IOptions<MetadataOptions>
|
||||
/// </summary>
|
||||
public string LocaleName
|
||||
{
|
||||
get => localeName ??= GetLocaleName();
|
||||
get => localeName ??= GetLocaleName(appOptions.CurrentCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前语言代码
|
||||
/// </summary>
|
||||
public string LanguageCode
|
||||
{
|
||||
get => LocaleNames.LocaleNameLanguageCodeMap[LocaleName];
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public MetadataOptions Value { get => this; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取语言名称
|
||||
/// </summary>
|
||||
/// <param name="cultureInfo">语言信息</param>
|
||||
/// <returns>元数据语言名称</returns>
|
||||
public static string GetLocaleName(CultureInfo cultureInfo)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (LocaleNames.LanguageNameLocaleNameMap.TryGetValue(cultureInfo.Name, out string? localeName))
|
||||
{
|
||||
return localeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
cultureInfo = cultureInfo.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否为当前语言名称
|
||||
/// </summary>
|
||||
/// <param name="languageCode">语言代码</param>
|
||||
/// <returns>是否为当前语言名称</returns>
|
||||
public bool IsCurrentLocale(string languageCode)
|
||||
{
|
||||
CultureInfo cultureInfo = CultureInfo.GetCultureInfo(languageCode);
|
||||
return GetLocaleName(cultureInfo) == LocaleName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取本地的本地化元数据文件
|
||||
/// </summary>
|
||||
@@ -90,38 +132,65 @@ internal sealed partial class MetadataOptions : IOptions<MetadataOptions>
|
||||
return Web.HutaoEndpoints.HutaoMetadata2File(LocaleName, fileNameWithExtension);
|
||||
#endif
|
||||
}
|
||||
|
||||
private string GetLocaleName()
|
||||
{
|
||||
CultureInfo cultureInfo = appOptions.CurrentCulture;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Equals(cultureInfo, CultureInfo.InvariantCulture))
|
||||
{
|
||||
// Fallback to Chinese.
|
||||
return "CHS";
|
||||
}
|
||||
|
||||
switch (cultureInfo.Name)
|
||||
{
|
||||
case "de": return "DE"; // German
|
||||
case "en": return "EN"; // English
|
||||
case "es": return "ES"; // Spanish
|
||||
case "fr": return "FR"; // French
|
||||
case "id": return "ID"; // Indonesian
|
||||
case "it": return "IT"; // Italian
|
||||
case "ja": return "JP"; // Japanese
|
||||
case "ko": return "KR"; // Korean
|
||||
case "pt": return "PT"; // Portuguese
|
||||
case "ru": return "RU"; // Russian
|
||||
case "th": return "TH"; // Thai
|
||||
case "tr": return "TR"; // Turkish
|
||||
case "vi": return "TR"; // Vietnamese
|
||||
case "zh-Hans": return "CHS"; // Chinese (Simplified)
|
||||
case "zh-Hant": return "CHT"; // Chinese (Traditional)
|
||||
default: cultureInfo = cultureInfo.Parent; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 本地化名称
|
||||
/// </summary>
|
||||
internal static class LocaleNames
|
||||
{
|
||||
public const string DE = "DE"; // German
|
||||
public const string EN = "EN"; // English
|
||||
public const string ES = "ES"; // Spanish
|
||||
public const string FR = "FR"; // French
|
||||
public const string ID = "ID"; // Indonesian
|
||||
public const string IT = "IT"; // Italian
|
||||
public const string JP = "JP"; // Japanese
|
||||
public const string KR = "KR"; // Korean
|
||||
public const string PT = "PT"; // Portuguese
|
||||
public const string RU = "RU"; // Russian
|
||||
public const string TH = "TH"; // Thai
|
||||
public const string TR = "TR"; // Turkish
|
||||
public const string VI = "VI"; // Vietnamese
|
||||
public const string CHS = "CHS"; // Chinese (Simplified)
|
||||
public const string CHT = "CHT"; // Chinese (Traditional)
|
||||
|
||||
public static readonly ImmutableDictionary<string, string> LanguageNameLocaleNameMap = new Dictionary<string, string>()
|
||||
{
|
||||
["de"] = DE,
|
||||
["en"] = EN,
|
||||
["es"] = ES,
|
||||
["fr"] = FR,
|
||||
["id"] = ID,
|
||||
["it"] = IT,
|
||||
["ja"] = JP,
|
||||
["ko"] = KR,
|
||||
["pt"] = PT,
|
||||
["ru"] = RU,
|
||||
["th"] = TH,
|
||||
["tr"] = TR,
|
||||
["vi"] = VI,
|
||||
["zh-Hans"] = CHS,
|
||||
["zh-Hant"] = CHT,
|
||||
[string.Empty] = CHS, // Fallback to Chinese.
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
public static readonly ImmutableDictionary<string, string> LocaleNameLanguageCodeMap = new Dictionary<string, string>()
|
||||
{
|
||||
[DE] = "de-de",
|
||||
[EN] = "en-us",
|
||||
[ES] = "es-es",
|
||||
[FR] = "fr-fr",
|
||||
[ID] = "id-id",
|
||||
[IT] = "it-it",
|
||||
[JP] = "ja-jp",
|
||||
[KR] = "ko-kr",
|
||||
[PT] = "pt-pt",
|
||||
[RU] = "ru-ru",
|
||||
[TH] = "th-th",
|
||||
[TR] = "tr-tr",
|
||||
[VI] = "vi-vn",
|
||||
[CHS] = "zh-cn",
|
||||
[CHT] = "zh-tw",
|
||||
}.ToImmutableDictionary();
|
||||
}
|
||||
@@ -33,7 +33,7 @@ internal sealed partial class GachaLogUrlDialog : ContentDialog
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
string url = InputText.Text;
|
||||
string url = InputText.Text.TrimEnd("#/log");
|
||||
|
||||
return new(result == ContentDialogResult.Primary, url);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ internal struct GachaLogQueryOptions
|
||||
IsOversea = query.IsOversea;
|
||||
innerQuery = QueryString.Parse(query.Query);
|
||||
|
||||
innerQuery.Set("lang", "zh-cn");
|
||||
// innerQuery.Set("lang", "zh-cn");
|
||||
innerQuery.Set("gacha_type", (int)type);
|
||||
innerQuery.Set("size", Size);
|
||||
|
||||
@@ -68,10 +68,12 @@ internal struct GachaLogQueryOptions
|
||||
/// </summary>
|
||||
/// <param name="genAuthKeyData">生成信息</param>
|
||||
/// <param name="gameAuthKey">验证包装</param>
|
||||
/// <param name="lang">语言</param>
|
||||
/// <returns>查询</returns>
|
||||
public static string AsQuery(GenAuthKeyData genAuthKeyData, GameAuthKey gameAuthKey)
|
||||
public static string AsQuery(GenAuthKeyData genAuthKeyData, GameAuthKey gameAuthKey, string lang)
|
||||
{
|
||||
QueryString queryString = new();
|
||||
queryString.Set("lang", lang);
|
||||
queryString.Set("auth_appid", genAuthKeyData.AuthAppId);
|
||||
queryString.Set("authkey", Uri.EscapeDataString(gameAuthKey.AuthKey));
|
||||
queryString.Set("authkey_ver", gameAuthKey.AuthKeyVersion);
|
||||
|
||||
Reference in New Issue
Block a user